summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/lib/CodeGen
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
commitb64793999546ed8adebaeebd9d8345d18db8927d (patch)
tree4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/tools/clang/lib/CodeGen
parentAdd support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff)
downloadwireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz
wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/tools/clang/lib/CodeGen')
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/ABIInfo.h146
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/Address.h118
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp1452
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp2043
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp3036
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.h299
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGBuilder.h306
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp13508
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp632
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.cpp46
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.h73
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCXX.cpp318
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp321
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.h624
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp4579
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCall.h388
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGClass.cpp2906
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp1283
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h650
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp760
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp4497
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h754
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGDecl.cpp2426
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp734
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGException.cpp2114
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGExpr.cpp4942
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp1935
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp2273
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp1158
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp2176
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp4526
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGGPUBuiltin.cpp123
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.cpp402
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.h203
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGNonTrivialStruct.cpp906
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGObjC.cpp3665
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp4022
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp7663
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp388
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h316
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp173
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h100
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp9860
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h2155
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp4604
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h478
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h220
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp897
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGStmt.cpp2350
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp5081
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGVTT.cpp180
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGVTables.cpp1068
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGVTables.h132
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CGValue.h632
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CMakeLists.txt106
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp88
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp1075
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp2565
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h4373
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp5511
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.h1470
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp1059
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h120
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp424
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h258
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h122
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp812
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h381
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/ConstantEmitter.h181
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp280
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp1476
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h114
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/EHScopeStack.h421
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp4281
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp200
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h123
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp4273
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp332
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp355
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/README.txt47
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp107
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.h53
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp865
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp9608
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.h311
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.cpp168
-rw-r--r--gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.h71
87 files changed, 0 insertions, 148271 deletions
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/ABIInfo.h b/gnu/llvm/tools/clang/lib/CodeGen/ABIInfo.h
deleted file mode 100644
index feed3833f24..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/ABIInfo.h
+++ /dev/null
@@ -1,146 +0,0 @@
-//===----- ABIInfo.h - ABI information access & encapsulation ---*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_ABIINFO_H
-#define LLVM_CLANG_LIB_CODEGEN_ABIINFO_H
-
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Type.h"
-#include "llvm/IR/CallingConv.h"
-#include "llvm/IR/Type.h"
-
-namespace llvm {
- class Value;
- class LLVMContext;
- class DataLayout;
- class Type;
-}
-
-namespace clang {
- class ASTContext;
- class CodeGenOptions;
- class TargetInfo;
-
-namespace CodeGen {
- class ABIArgInfo;
- class Address;
- class CGCXXABI;
- class CGFunctionInfo;
- class CodeGenFunction;
- class CodeGenTypes;
- class SwiftABIInfo;
-
-namespace swiftcall {
- class SwiftAggLowering;
-}
-
- // FIXME: All of this stuff should be part of the target interface
- // somehow. It is currently here because it is not clear how to factor
- // the targets to support this, since the Targets currently live in a
- // layer below types n'stuff.
-
-
- /// ABIInfo - Target specific hooks for defining how a type should be
- /// passed or returned from functions.
- class ABIInfo {
- public:
- CodeGen::CodeGenTypes &CGT;
- protected:
- llvm::CallingConv::ID RuntimeCC;
- public:
- ABIInfo(CodeGen::CodeGenTypes &cgt)
- : CGT(cgt), RuntimeCC(llvm::CallingConv::C) {}
-
- virtual ~ABIInfo();
-
- virtual bool supportsSwift() const { return false; }
-
- CodeGen::CGCXXABI &getCXXABI() const;
- ASTContext &getContext() const;
- llvm::LLVMContext &getVMContext() const;
- const llvm::DataLayout &getDataLayout() const;
- const TargetInfo &getTarget() const;
- const CodeGenOptions &getCodeGenOpts() const;
-
- /// Return the calling convention to use for system runtime
- /// functions.
- llvm::CallingConv::ID getRuntimeCC() const {
- return RuntimeCC;
- }
-
- virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0;
-
- /// EmitVAArg - Emit the target dependent code to load a value of
- /// \arg Ty from the va_list pointed to by \arg VAListAddr.
-
- // FIXME: This is a gaping layering violation if we wanted to drop
- // the ABI information any lower than CodeGen. Of course, for
- // VAArg handling it has to be at this level; there is no way to
- // abstract this out.
- virtual CodeGen::Address EmitVAArg(CodeGen::CodeGenFunction &CGF,
- CodeGen::Address VAListAddr,
- QualType Ty) const = 0;
-
- bool isAndroid() const;
-
- /// Emit the target dependent code to load a value of
- /// \arg Ty from the \c __builtin_ms_va_list pointed to by \arg VAListAddr.
- virtual CodeGen::Address EmitMSVAArg(CodeGen::CodeGenFunction &CGF,
- CodeGen::Address VAListAddr,
- QualType Ty) const;
-
- virtual bool isHomogeneousAggregateBaseType(QualType Ty) const;
-
- virtual bool isHomogeneousAggregateSmallEnough(const Type *Base,
- uint64_t Members) const;
-
- bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
- uint64_t &Members) const;
-
- /// A convenience method to return an indirect ABIArgInfo with an
- /// expected alignment equal to the ABI alignment of the given type.
- CodeGen::ABIArgInfo
- getNaturalAlignIndirect(QualType Ty, bool ByRef = true,
- bool Realign = false,
- llvm::Type *Padding = nullptr) const;
-
- CodeGen::ABIArgInfo
- getNaturalAlignIndirectInReg(QualType Ty, bool Realign = false) const;
-
-
- };
-
- /// A refining implementation of ABIInfo for targets that support swiftcall.
- ///
- /// If we find ourselves wanting multiple such refinements, they'll probably
- /// be independent refinements, and we should probably find another way
- /// to do it than simple inheritance.
- class SwiftABIInfo : public ABIInfo {
- public:
- SwiftABIInfo(CodeGen::CodeGenTypes &cgt) : ABIInfo(cgt) {}
-
- bool supportsSwift() const final override { return true; }
-
- virtual bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> types,
- bool asReturnValue) const = 0;
-
- virtual bool isLegalVectorTypeForSwift(CharUnits totalSize,
- llvm::Type *eltTy,
- unsigned elts) const;
-
- virtual bool isSwiftErrorInRegister() const = 0;
-
- static bool classof(const ABIInfo *info) {
- return info->supportsSwift();
- }
- };
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/Address.h b/gnu/llvm/tools/clang/lib/CodeGen/Address.h
deleted file mode 100644
index 334308081ff..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/Address.h
+++ /dev/null
@@ -1,118 +0,0 @@
-//===-- Address.h - An aligned address -------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class provides a simple wrapper for a pair of a pointer and an
-// alignment.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H
-#define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H
-
-#include "llvm/IR/Constants.h"
-#include "clang/AST/CharUnits.h"
-
-namespace clang {
-namespace CodeGen {
-
-/// An aligned address.
-class Address {
- llvm::Value *Pointer;
- CharUnits Alignment;
-public:
- Address(llvm::Value *pointer, CharUnits alignment)
- : Pointer(pointer), Alignment(alignment) {
- assert((!alignment.isZero() || pointer == nullptr) &&
- "creating valid address with invalid alignment");
- }
-
- static Address invalid() { return Address(nullptr, CharUnits()); }
- bool isValid() const { return Pointer != nullptr; }
-
- llvm::Value *getPointer() const {
- assert(isValid());
- return Pointer;
- }
-
- /// Return the type of the pointer value.
- llvm::PointerType *getType() const {
- return llvm::cast<llvm::PointerType>(getPointer()->getType());
- }
-
- /// Return the type of the values stored in this address.
- ///
- /// When IR pointer types lose their element type, we should simply
- /// store it in Address instead for the convenience of writing code.
- llvm::Type *getElementType() const {
- return getType()->getElementType();
- }
-
- /// Return the address space that this address resides in.
- unsigned getAddressSpace() const {
- return getType()->getAddressSpace();
- }
-
- /// Return the IR name of the pointer value.
- llvm::StringRef getName() const {
- return getPointer()->getName();
- }
-
- /// Return the alignment of this pointer.
- CharUnits getAlignment() const {
- assert(isValid());
- return Alignment;
- }
-};
-
-/// A specialization of Address that requires the address to be an
-/// LLVM Constant.
-class ConstantAddress : public Address {
-public:
- ConstantAddress(llvm::Constant *pointer, CharUnits alignment)
- : Address(pointer, alignment) {}
-
- static ConstantAddress invalid() {
- return ConstantAddress(nullptr, CharUnits());
- }
-
- llvm::Constant *getPointer() const {
- return llvm::cast<llvm::Constant>(Address::getPointer());
- }
-
- ConstantAddress getBitCast(llvm::Type *ty) const {
- return ConstantAddress(llvm::ConstantExpr::getBitCast(getPointer(), ty),
- getAlignment());
- }
-
- ConstantAddress getElementBitCast(llvm::Type *ty) const {
- return getBitCast(ty->getPointerTo(getAddressSpace()));
- }
-
- static bool isaImpl(Address addr) {
- return llvm::isa<llvm::Constant>(addr.getPointer());
- }
- static ConstantAddress castImpl(Address addr) {
- return ConstantAddress(llvm::cast<llvm::Constant>(addr.getPointer()),
- addr.getAlignment());
- }
-};
-
-}
-
-// Present a minimal LLVM-like casting interface.
-template <class U> inline U cast(CodeGen::Address addr) {
- return U::castImpl(addr);
-}
-template <class U> inline bool isa(CodeGen::Address addr) {
- return U::isaImpl(addr);
-}
-
-}
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/gnu/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp
deleted file mode 100644
index b927acabac5..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp
+++ /dev/null
@@ -1,1452 +0,0 @@
-//===--- BackendUtil.cpp - LLVM Backend Utilities -------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CodeGen/BackendUtil.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/TargetOptions.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Frontend/Utils.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Analysis/TargetLibraryInfo.h"
-#include "llvm/Analysis/TargetTransformInfo.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/Bitcode/BitcodeWriter.h"
-#include "llvm/Bitcode/BitcodeWriterPass.h"
-#include "llvm/CodeGen/RegAllocRegistry.h"
-#include "llvm/CodeGen/SchedulerRegistry.h"
-#include "llvm/CodeGen/TargetSubtargetInfo.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/IRPrintingPasses.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/ModuleSummaryIndex.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/LTO/LTOBackend.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Passes/PassBuilder.h"
-#include "llvm/Support/BuryPointer.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/Timer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetOptions.h"
-#include "llvm/Transforms/Coroutines.h"
-#include "llvm/Transforms/IPO.h"
-#include "llvm/Transforms/IPO/AlwaysInliner.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
-#include "llvm/Transforms/InstCombine/InstCombine.h"
-#include "llvm/Transforms/Instrumentation.h"
-#include "llvm/Transforms/Instrumentation/BoundsChecking.h"
-#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
-#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
-#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
-#include "llvm/Transforms/ObjCARC.h"
-#include "llvm/Transforms/Scalar.h"
-#include "llvm/Transforms/Scalar/GVN.h"
-#include "llvm/Transforms/Utils.h"
-#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
-#include "llvm/Transforms/Utils/NameAnonGlobals.h"
-#include "llvm/Transforms/Utils/SymbolRewriter.h"
-#include <memory>
-using namespace clang;
-using namespace llvm;
-
-namespace {
-
-// Default filename used for profile generation.
-static constexpr StringLiteral DefaultProfileGenName = "default_%m.profraw";
-
-class EmitAssemblyHelper {
- DiagnosticsEngine &Diags;
- const HeaderSearchOptions &HSOpts;
- const CodeGenOptions &CodeGenOpts;
- const clang::TargetOptions &TargetOpts;
- const LangOptions &LangOpts;
- Module *TheModule;
-
- Timer CodeGenerationTime;
-
- std::unique_ptr<raw_pwrite_stream> OS;
-
- TargetIRAnalysis getTargetIRAnalysis() const {
- if (TM)
- return TM->getTargetIRAnalysis();
-
- return TargetIRAnalysis();
- }
-
- void CreatePasses(legacy::PassManager &MPM, legacy::FunctionPassManager &FPM);
-
- /// Generates the TargetMachine.
- /// Leaves TM unchanged if it is unable to create the target machine.
- /// Some of our clang tests specify triples which are not built
- /// into clang. This is okay because these tests check the generated
- /// IR, and they require DataLayout which depends on the triple.
- /// In this case, we allow this method to fail and not report an error.
- /// When MustCreateTM is used, we print an error if we are unable to load
- /// the requested target.
- void CreateTargetMachine(bool MustCreateTM);
-
- /// Add passes necessary to emit assembly or LLVM IR.
- ///
- /// \return True on success.
- bool AddEmitPasses(legacy::PassManager &CodeGenPasses, BackendAction Action,
- raw_pwrite_stream &OS, raw_pwrite_stream *DwoOS);
-
- std::unique_ptr<llvm::ToolOutputFile> openOutputFile(StringRef Path) {
- std::error_code EC;
- auto F = llvm::make_unique<llvm::ToolOutputFile>(Path, EC,
- llvm::sys::fs::F_None);
- if (EC) {
- Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
- F.reset();
- }
- return F;
- }
-
-public:
- EmitAssemblyHelper(DiagnosticsEngine &_Diags,
- const HeaderSearchOptions &HeaderSearchOpts,
- const CodeGenOptions &CGOpts,
- const clang::TargetOptions &TOpts,
- const LangOptions &LOpts, Module *M)
- : Diags(_Diags), HSOpts(HeaderSearchOpts), CodeGenOpts(CGOpts),
- TargetOpts(TOpts), LangOpts(LOpts), TheModule(M),
- CodeGenerationTime("codegen", "Code Generation Time") {}
-
- ~EmitAssemblyHelper() {
- if (CodeGenOpts.DisableFree)
- BuryPointer(std::move(TM));
- }
-
- std::unique_ptr<TargetMachine> TM;
-
- void EmitAssembly(BackendAction Action,
- std::unique_ptr<raw_pwrite_stream> OS);
-
- void EmitAssemblyWithNewPassManager(BackendAction Action,
- std::unique_ptr<raw_pwrite_stream> OS);
-};
-
-// We need this wrapper to access LangOpts and CGOpts from extension functions
-// that we add to the PassManagerBuilder.
-class PassManagerBuilderWrapper : public PassManagerBuilder {
-public:
- PassManagerBuilderWrapper(const Triple &TargetTriple,
- const CodeGenOptions &CGOpts,
- const LangOptions &LangOpts)
- : PassManagerBuilder(), TargetTriple(TargetTriple), CGOpts(CGOpts),
- LangOpts(LangOpts) {}
- const Triple &getTargetTriple() const { return TargetTriple; }
- const CodeGenOptions &getCGOpts() const { return CGOpts; }
- const LangOptions &getLangOpts() const { return LangOpts; }
-
-private:
- const Triple &TargetTriple;
- const CodeGenOptions &CGOpts;
- const LangOptions &LangOpts;
-};
-}
-
-static void addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
- if (Builder.OptLevel > 0)
- PM.add(createObjCARCAPElimPass());
-}
-
-static void addObjCARCExpandPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
- if (Builder.OptLevel > 0)
- PM.add(createObjCARCExpandPass());
-}
-
-static void addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
- if (Builder.OptLevel > 0)
- PM.add(createObjCARCOptPass());
-}
-
-static void addAddDiscriminatorsPass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- PM.add(createAddDiscriminatorsPass());
-}
-
-static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- PM.add(createBoundsCheckingLegacyPass());
-}
-
-static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- SanitizerCoverageOptions Opts;
- Opts.CoverageType =
- static_cast<SanitizerCoverageOptions::Type>(CGOpts.SanitizeCoverageType);
- Opts.IndirectCalls = CGOpts.SanitizeCoverageIndirectCalls;
- Opts.TraceBB = CGOpts.SanitizeCoverageTraceBB;
- Opts.TraceCmp = CGOpts.SanitizeCoverageTraceCmp;
- Opts.TraceDiv = CGOpts.SanitizeCoverageTraceDiv;
- Opts.TraceGep = CGOpts.SanitizeCoverageTraceGep;
- Opts.Use8bitCounters = CGOpts.SanitizeCoverage8bitCounters;
- Opts.TracePC = CGOpts.SanitizeCoverageTracePC;
- Opts.TracePCGuard = CGOpts.SanitizeCoverageTracePCGuard;
- Opts.NoPrune = CGOpts.SanitizeCoverageNoPrune;
- Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters;
- Opts.PCTable = CGOpts.SanitizeCoveragePCTable;
- Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth;
- PM.add(createSanitizerCoverageModulePass(Opts));
-}
-
-// Check if ASan should use GC-friendly instrumentation for globals.
-// First of all, there is no point if -fdata-sections is off (expect for MachO,
-// where this is not a factor). Also, on ELF this feature requires an assembler
-// extension that only works with -integrated-as at the moment.
-static bool asanUseGlobalsGC(const Triple &T, const CodeGenOptions &CGOpts) {
- if (!CGOpts.SanitizeAddressGlobalsDeadStripping)
- return false;
- switch (T.getObjectFormat()) {
- case Triple::MachO:
- case Triple::COFF:
- return true;
- case Triple::ELF:
- return CGOpts.DataSections && !CGOpts.DisableIntegratedAS;
- default:
- return false;
- }
-}
-
-static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const Triple &T = BuilderWrapper.getTargetTriple();
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Address);
- bool UseAfterScope = CGOpts.SanitizeAddressUseAfterScope;
- bool UseOdrIndicator = CGOpts.SanitizeAddressUseOdrIndicator;
- bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts);
- PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover,
- UseAfterScope));
- PM.add(createAddressSanitizerModulePass(/*CompileKernel*/ false, Recover,
- UseGlobalsGC, UseOdrIndicator));
-}
-
-static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- PM.add(createAddressSanitizerFunctionPass(
- /*CompileKernel*/ true, /*Recover*/ true, /*UseAfterScope*/ false));
- PM.add(createAddressSanitizerModulePass(
- /*CompileKernel*/ true, /*Recover*/ true, /*UseGlobalsGC*/ true,
- /*UseOdrIndicator*/ false));
-}
-
-static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper &>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::HWAddress);
- PM.add(createHWAddressSanitizerPass(/*CompileKernel*/ false, Recover));
-}
-
-static void addKernelHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- PM.add(createHWAddressSanitizerPass(
- /*CompileKernel*/ true, /*Recover*/ true));
-}
-
-static void addGeneralOptsForMemorySanitizer(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM,
- bool CompileKernel) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- int TrackOrigins = CGOpts.SanitizeMemoryTrackOrigins;
- bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Memory);
- PM.add(createMemorySanitizerLegacyPassPass(TrackOrigins, Recover, CompileKernel));
-
- // MemorySanitizer inserts complex instrumentation that mostly follows
- // the logic of the original code, but operates on "shadow" values.
- // It can benefit from re-running some general purpose optimization passes.
- if (Builder.OptLevel > 0) {
- PM.add(createEarlyCSEPass());
- PM.add(createReassociatePass());
- PM.add(createLICMPass());
- PM.add(createGVNPass());
- PM.add(createInstructionCombiningPass());
- PM.add(createDeadStoreEliminationPass());
- }
-}
-
-static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- addGeneralOptsForMemorySanitizer(Builder, PM, /*CompileKernel*/ false);
-}
-
-static void addKernelMemorySanitizerPass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- addGeneralOptsForMemorySanitizer(Builder, PM, /*CompileKernel*/ true);
-}
-
-static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- PM.add(createThreadSanitizerLegacyPassPass());
-}
-
-static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const LangOptions &LangOpts = BuilderWrapper.getLangOpts();
- PM.add(createDataFlowSanitizerPass(LangOpts.SanitizerBlacklistFiles));
-}
-
-static void addEfficiencySanitizerPass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const LangOptions &LangOpts = BuilderWrapper.getLangOpts();
- EfficiencySanitizerOptions Opts;
- if (LangOpts.Sanitize.has(SanitizerKind::EfficiencyCacheFrag))
- Opts.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag;
- else if (LangOpts.Sanitize.has(SanitizerKind::EfficiencyWorkingSet))
- Opts.ToolType = EfficiencySanitizerOptions::ESAN_WorkingSet;
- PM.add(createEfficiencySanitizerPass(Opts));
-}
-
-static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple,
- const CodeGenOptions &CodeGenOpts) {
- TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple);
- if (!CodeGenOpts.SimplifyLibCalls)
- TLII->disableAllFunctions();
- else {
- // Disable individual libc/libm calls in TargetLibraryInfo.
- LibFunc F;
- for (auto &FuncName : CodeGenOpts.getNoBuiltinFuncs())
- if (TLII->getLibFunc(FuncName, F))
- TLII->setUnavailable(F);
- }
-
- switch (CodeGenOpts.getVecLib()) {
- case CodeGenOptions::Accelerate:
- TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::Accelerate);
- break;
- case CodeGenOptions::SVML:
- TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::SVML);
- break;
- default:
- break;
- }
- return TLII;
-}
-
-static void addSymbolRewriterPass(const CodeGenOptions &Opts,
- legacy::PassManager *MPM) {
- llvm::SymbolRewriter::RewriteDescriptorList DL;
-
- llvm::SymbolRewriter::RewriteMapParser MapParser;
- for (const auto &MapFile : Opts.RewriteMapFiles)
- MapParser.parse(MapFile, &DL);
-
- MPM->add(createRewriteSymbolsPass(DL));
-}
-
-static CodeGenOpt::Level getCGOptLevel(const CodeGenOptions &CodeGenOpts) {
- switch (CodeGenOpts.OptimizationLevel) {
- default:
- llvm_unreachable("Invalid optimization level!");
- case 0:
- return CodeGenOpt::None;
- case 1:
- return CodeGenOpt::Less;
- case 2:
- return CodeGenOpt::Default; // O2/Os/Oz
- case 3:
- return CodeGenOpt::Aggressive;
- }
-}
-
-static Optional<llvm::CodeModel::Model>
-getCodeModel(const CodeGenOptions &CodeGenOpts) {
- unsigned CodeModel = llvm::StringSwitch<unsigned>(CodeGenOpts.CodeModel)
- .Case("tiny", llvm::CodeModel::Tiny)
- .Case("small", llvm::CodeModel::Small)
- .Case("kernel", llvm::CodeModel::Kernel)
- .Case("medium", llvm::CodeModel::Medium)
- .Case("large", llvm::CodeModel::Large)
- .Case("default", ~1u)
- .Default(~0u);
- assert(CodeModel != ~0u && "invalid code model!");
- if (CodeModel == ~1u)
- return None;
- return static_cast<llvm::CodeModel::Model>(CodeModel);
-}
-
-static TargetMachine::CodeGenFileType getCodeGenFileType(BackendAction Action) {
- if (Action == Backend_EmitObj)
- return TargetMachine::CGFT_ObjectFile;
- else if (Action == Backend_EmitMCNull)
- return TargetMachine::CGFT_Null;
- else {
- assert(Action == Backend_EmitAssembly && "Invalid action!");
- return TargetMachine::CGFT_AssemblyFile;
- }
-}
-
-static void initTargetOptions(llvm::TargetOptions &Options,
- const CodeGenOptions &CodeGenOpts,
- const clang::TargetOptions &TargetOpts,
- const LangOptions &LangOpts,
- const HeaderSearchOptions &HSOpts) {
- Options.ThreadModel =
- llvm::StringSwitch<llvm::ThreadModel::Model>(CodeGenOpts.ThreadModel)
- .Case("posix", llvm::ThreadModel::POSIX)
- .Case("single", llvm::ThreadModel::Single);
-
- // Set float ABI type.
- assert((CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp" ||
- CodeGenOpts.FloatABI == "hard" || CodeGenOpts.FloatABI.empty()) &&
- "Invalid Floating Point ABI!");
- Options.FloatABIType =
- llvm::StringSwitch<llvm::FloatABI::ABIType>(CodeGenOpts.FloatABI)
- .Case("soft", llvm::FloatABI::Soft)
- .Case("softfp", llvm::FloatABI::Soft)
- .Case("hard", llvm::FloatABI::Hard)
- .Default(llvm::FloatABI::Default);
-
- // Set FP fusion mode.
- switch (LangOpts.getDefaultFPContractMode()) {
- case LangOptions::FPC_Off:
- // Preserve any contraction performed by the front-end. (Strict performs
- // splitting of the muladd intrinsic in the backend.)
- Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
- break;
- case LangOptions::FPC_On:
- Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
- break;
- case LangOptions::FPC_Fast:
- Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
- break;
- }
-
- Options.UseInitArray = CodeGenOpts.UseInitArray;
- Options.DisableIntegratedAS = CodeGenOpts.DisableIntegratedAS;
- Options.CompressDebugSections = CodeGenOpts.getCompressDebugSections();
- Options.RelaxELFRelocations = CodeGenOpts.RelaxELFRelocations;
-
- // Set EABI version.
- Options.EABIVersion = TargetOpts.EABIVersion;
-
- if (LangOpts.SjLjExceptions)
- Options.ExceptionModel = llvm::ExceptionHandling::SjLj;
- if (LangOpts.SEHExceptions)
- Options.ExceptionModel = llvm::ExceptionHandling::WinEH;
- if (LangOpts.DWARFExceptions)
- Options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI;
-
- Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath;
- Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath;
- Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
- Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
- Options.StackAlignmentOverride = CodeGenOpts.StackAlignment;
- Options.FunctionSections = CodeGenOpts.FunctionSections;
- Options.DataSections = CodeGenOpts.DataSections;
- Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames;
- Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
- Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS;
- Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning();
- Options.EmitStackSizeSection = CodeGenOpts.StackSizeSection;
- Options.EmitAddrsig = CodeGenOpts.Addrsig;
-
- if (CodeGenOpts.getSplitDwarfMode() != CodeGenOptions::NoFission)
- Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile;
- Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
- Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
- Options.MCOptions.MCUseDwarfDirectory = !CodeGenOpts.NoDwarfDirectoryAsm;
- Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
- Options.MCOptions.MCIncrementalLinkerCompatible =
- CodeGenOpts.IncrementalLinkerCompatible;
- Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations;
- Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
- Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
- Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
- Options.MCOptions.ABIName = TargetOpts.ABI;
- for (const auto &Entry : HSOpts.UserEntries)
- if (!Entry.IsFramework &&
- (Entry.Group == frontend::IncludeDirGroup::Quoted ||
- Entry.Group == frontend::IncludeDirGroup::Angled ||
- Entry.Group == frontend::IncludeDirGroup::System))
- Options.MCOptions.IASSearchPaths.push_back(
- Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path);
-}
-static Optional<GCOVOptions> getGCOVOptions(const CodeGenOptions &CodeGenOpts) {
- if (CodeGenOpts.DisableGCov)
- return None;
- if (!CodeGenOpts.EmitGcovArcs && !CodeGenOpts.EmitGcovNotes)
- return None;
- // Not using 'GCOVOptions::getDefault' allows us to avoid exiting if
- // LLVM's -default-gcov-version flag is set to something invalid.
- GCOVOptions Options;
- Options.EmitNotes = CodeGenOpts.EmitGcovNotes;
- Options.EmitData = CodeGenOpts.EmitGcovArcs;
- llvm::copy(CodeGenOpts.CoverageVersion, std::begin(Options.Version));
- Options.UseCfgChecksum = CodeGenOpts.CoverageExtraChecksum;
- Options.NoRedZone = CodeGenOpts.DisableRedZone;
- Options.FunctionNamesInData = !CodeGenOpts.CoverageNoFunctionNamesInData;
- Options.Filter = CodeGenOpts.ProfileFilterFiles;
- Options.Exclude = CodeGenOpts.ProfileExcludeFiles;
- Options.ExitBlockBeforeBody = CodeGenOpts.CoverageExitBlockBeforeBody;
- return Options;
-}
-
-void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
- legacy::FunctionPassManager &FPM) {
- // Handle disabling of all LLVM passes, where we want to preserve the
- // internal module before any optimization.
- if (CodeGenOpts.DisableLLVMPasses)
- return;
-
- // Figure out TargetLibraryInfo. This needs to be added to MPM and FPM
- // manually (and not via PMBuilder), since some passes (eg. InstrProfiling)
- // are inserted before PMBuilder ones - they'd get the default-constructed
- // TLI with an unknown target otherwise.
- Triple TargetTriple(TheModule->getTargetTriple());
- std::unique_ptr<TargetLibraryInfoImpl> TLII(
- createTLII(TargetTriple, CodeGenOpts));
-
- PassManagerBuilderWrapper PMBuilder(TargetTriple, CodeGenOpts, LangOpts);
-
- // At O0 and O1 we only run the always inliner which is more efficient. At
- // higher optimization levels we run the normal inliner.
- if (CodeGenOpts.OptimizationLevel <= 1) {
- bool InsertLifetimeIntrinsics = (CodeGenOpts.OptimizationLevel != 0 &&
- !CodeGenOpts.DisableLifetimeMarkers);
- PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
- } else {
- // We do not want to inline hot callsites for SamplePGO module-summary build
- // because profile annotation will happen again in ThinLTO backend, and we
- // want the IR of the hot path to match the profile.
- PMBuilder.Inliner = createFunctionInliningPass(
- CodeGenOpts.OptimizationLevel, CodeGenOpts.OptimizeSize,
- (!CodeGenOpts.SampleProfileFile.empty() &&
- CodeGenOpts.PrepareForThinLTO));
- }
-
- PMBuilder.OptLevel = CodeGenOpts.OptimizationLevel;
- PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
- PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;
- PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
-
- PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
- PMBuilder.MergeFunctions = CodeGenOpts.MergeFunctions;
- PMBuilder.PrepareForThinLTO = CodeGenOpts.PrepareForThinLTO;
- PMBuilder.PrepareForLTO = CodeGenOpts.PrepareForLTO;
- PMBuilder.RerollLoops = CodeGenOpts.RerollLoops;
-
- MPM.add(new TargetLibraryInfoWrapperPass(*TLII));
-
- if (TM)
- TM->adjustPassManager(PMBuilder);
-
- if (CodeGenOpts.DebugInfoForProfiling ||
- !CodeGenOpts.SampleProfileFile.empty())
- PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
- addAddDiscriminatorsPass);
-
- // In ObjC ARC mode, add the main ARC optimization passes.
- if (LangOpts.ObjCAutoRefCount) {
- PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
- addObjCARCExpandPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_ModuleOptimizerEarly,
- addObjCARCAPElimPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
- addObjCARCOptPass);
- }
-
- if (LangOpts.CoroutinesTS)
- addCoroutinePassesToExtensionPoints(PMBuilder);
-
- if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
- addBoundsCheckingPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addBoundsCheckingPass);
- }
-
- if (CodeGenOpts.SanitizeCoverageType ||
- CodeGenOpts.SanitizeCoverageIndirectCalls ||
- CodeGenOpts.SanitizeCoverageTraceCmp) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addSanitizerCoveragePass);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addSanitizerCoveragePass);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::Address)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addAddressSanitizerPasses);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addAddressSanitizerPasses);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::KernelAddress)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addKernelAddressSanitizerPasses);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addKernelAddressSanitizerPasses);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::HWAddress)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addHWAddressSanitizerPasses);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addHWAddressSanitizerPasses);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::KernelHWAddress)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addKernelHWAddressSanitizerPasses);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addKernelHWAddressSanitizerPasses);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::Memory)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addMemorySanitizerPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addMemorySanitizerPass);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::KernelMemory)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addKernelMemorySanitizerPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addKernelMemorySanitizerPass);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::Thread)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addThreadSanitizerPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addThreadSanitizerPass);
- }
-
- if (LangOpts.Sanitize.has(SanitizerKind::DataFlow)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addDataFlowSanitizerPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addDataFlowSanitizerPass);
- }
-
- if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Efficiency)) {
- PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addEfficiencySanitizerPass);
- PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addEfficiencySanitizerPass);
- }
-
- // Set up the per-function pass manager.
- FPM.add(new TargetLibraryInfoWrapperPass(*TLII));
- if (CodeGenOpts.VerifyModule)
- FPM.add(createVerifierPass());
-
- // Set up the per-module pass manager.
- if (!CodeGenOpts.RewriteMapFiles.empty())
- addSymbolRewriterPass(CodeGenOpts, &MPM);
-
- if (Optional<GCOVOptions> Options = getGCOVOptions(CodeGenOpts)) {
- MPM.add(createGCOVProfilerPass(*Options));
- if (CodeGenOpts.getDebugInfo() == codegenoptions::NoDebugInfo)
- MPM.add(createStripSymbolsPass(true));
- }
-
- if (CodeGenOpts.hasProfileClangInstr()) {
- InstrProfOptions Options;
- Options.NoRedZone = CodeGenOpts.DisableRedZone;
- Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput;
-
- // TODO: Surface the option to emit atomic profile counter increments at
- // the driver level.
- Options.Atomic = LangOpts.Sanitize.has(SanitizerKind::Thread);
-
- MPM.add(createInstrProfilingLegacyPass(Options));
- }
- if (CodeGenOpts.hasProfileIRInstr()) {
- PMBuilder.EnablePGOInstrGen = true;
- if (!CodeGenOpts.InstrProfileOutput.empty())
- PMBuilder.PGOInstrGen = CodeGenOpts.InstrProfileOutput;
- else
- PMBuilder.PGOInstrGen = DefaultProfileGenName;
- }
- if (CodeGenOpts.hasProfileIRUse())
- PMBuilder.PGOInstrUse = CodeGenOpts.ProfileInstrumentUsePath;
-
- if (!CodeGenOpts.SampleProfileFile.empty())
- PMBuilder.PGOSampleUse = CodeGenOpts.SampleProfileFile;
-
- PMBuilder.populateFunctionPassManager(FPM);
- PMBuilder.populateModulePassManager(MPM);
-}
-
-static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) {
- SmallVector<const char *, 16> BackendArgs;
- BackendArgs.push_back("clang"); // Fake program name.
- if (!CodeGenOpts.DebugPass.empty()) {
- BackendArgs.push_back("-debug-pass");
- BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
- }
- if (!CodeGenOpts.LimitFloatPrecision.empty()) {
- BackendArgs.push_back("-limit-float-precision");
- BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
- }
- BackendArgs.push_back(nullptr);
- llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
- BackendArgs.data());
-}
-
-void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
- // Create the TargetMachine for generating code.
- std::string Error;
- std::string Triple = TheModule->getTargetTriple();
- const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
- if (!TheTarget) {
- if (MustCreateTM)
- Diags.Report(diag::err_fe_unable_to_create_target) << Error;
- return;
- }
-
- Optional<llvm::CodeModel::Model> CM = getCodeModel(CodeGenOpts);
- std::string FeaturesStr =
- llvm::join(TargetOpts.Features.begin(), TargetOpts.Features.end(), ",");
- llvm::Reloc::Model RM = CodeGenOpts.RelocationModel;
- CodeGenOpt::Level OptLevel = getCGOptLevel(CodeGenOpts);
-
- llvm::TargetOptions Options;
- initTargetOptions(Options, CodeGenOpts, TargetOpts, LangOpts, HSOpts);
- TM.reset(TheTarget->createTargetMachine(Triple, TargetOpts.CPU, FeaturesStr,
- Options, RM, CM, OptLevel));
-}
-
-bool EmitAssemblyHelper::AddEmitPasses(legacy::PassManager &CodeGenPasses,
- BackendAction Action,
- raw_pwrite_stream &OS,
- raw_pwrite_stream *DwoOS) {
- // Add LibraryInfo.
- llvm::Triple TargetTriple(TheModule->getTargetTriple());
- std::unique_ptr<TargetLibraryInfoImpl> TLII(
- createTLII(TargetTriple, CodeGenOpts));
- CodeGenPasses.add(new TargetLibraryInfoWrapperPass(*TLII));
-
- // Normal mode, emit a .s or .o file by running the code generator. Note,
- // this also adds codegenerator level optimization passes.
- TargetMachine::CodeGenFileType CGFT = getCodeGenFileType(Action);
-
- // Add ObjC ARC final-cleanup optimizations. This is done as part of the
- // "codegen" passes so that it isn't run multiple times when there is
- // inlining happening.
- if (CodeGenOpts.OptimizationLevel > 0)
- CodeGenPasses.add(createObjCARCContractPass());
-
- if (TM->addPassesToEmitFile(CodeGenPasses, OS, DwoOS, CGFT,
- /*DisableVerify=*/!CodeGenOpts.VerifyModule)) {
- Diags.Report(diag::err_fe_unable_to_interface_with_target);
- return false;
- }
-
- return true;
-}
-
-void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
- std::unique_ptr<raw_pwrite_stream> OS) {
- TimeRegion Region(FrontendTimesIsEnabled ? &CodeGenerationTime : nullptr);
-
- setCommandLineOpts(CodeGenOpts);
-
- bool UsesCodeGen = (Action != Backend_EmitNothing &&
- Action != Backend_EmitBC &&
- Action != Backend_EmitLL);
- CreateTargetMachine(UsesCodeGen);
-
- if (UsesCodeGen && !TM)
- return;
- if (TM)
- TheModule->setDataLayout(TM->createDataLayout());
-
- legacy::PassManager PerModulePasses;
- PerModulePasses.add(
- createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
-
- legacy::FunctionPassManager PerFunctionPasses(TheModule);
- PerFunctionPasses.add(
- createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
-
- CreatePasses(PerModulePasses, PerFunctionPasses);
-
- legacy::PassManager CodeGenPasses;
- CodeGenPasses.add(
- createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
-
- std::unique_ptr<llvm::ToolOutputFile> ThinLinkOS, DwoOS;
-
- switch (Action) {
- case Backend_EmitNothing:
- break;
-
- case Backend_EmitBC:
- if (CodeGenOpts.PrepareForThinLTO && !CodeGenOpts.DisableLLVMPasses) {
- if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) {
- ThinLinkOS = openOutputFile(CodeGenOpts.ThinLinkBitcodeFile);
- if (!ThinLinkOS)
- return;
- }
- TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
- CodeGenOpts.EnableSplitLTOUnit);
- PerModulePasses.add(createWriteThinLTOBitcodePass(
- *OS, ThinLinkOS ? &ThinLinkOS->os() : nullptr));
- } else {
- // Emit a module summary by default for Regular LTO except for ld64
- // targets
- bool EmitLTOSummary =
- (CodeGenOpts.PrepareForLTO &&
- !CodeGenOpts.DisableLLVMPasses &&
- llvm::Triple(TheModule->getTargetTriple()).getVendor() !=
- llvm::Triple::Apple);
- if (EmitLTOSummary) {
- if (!TheModule->getModuleFlag("ThinLTO"))
- TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0));
- TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
- CodeGenOpts.EnableSplitLTOUnit);
- }
-
- PerModulePasses.add(createBitcodeWriterPass(
- *OS, CodeGenOpts.EmitLLVMUseLists, EmitLTOSummary));
- }
- break;
-
- case Backend_EmitLL:
- PerModulePasses.add(
- createPrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists));
- break;
-
- default:
- if (!CodeGenOpts.SplitDwarfFile.empty() &&
- (CodeGenOpts.getSplitDwarfMode() == CodeGenOptions::SplitFileFission)) {
- DwoOS = openOutputFile(CodeGenOpts.SplitDwarfFile);
- if (!DwoOS)
- return;
- }
- if (!AddEmitPasses(CodeGenPasses, Action, *OS,
- DwoOS ? &DwoOS->os() : nullptr))
- return;
- }
-
- // Before executing passes, print the final values of the LLVM options.
- cl::PrintOptionValues();
-
- // Run passes. For now we do all passes at once, but eventually we
- // would like to have the option of streaming code generation.
-
- {
- PrettyStackTraceString CrashInfo("Per-function optimization");
-
- PerFunctionPasses.doInitialization();
- for (Function &F : *TheModule)
- if (!F.isDeclaration())
- PerFunctionPasses.run(F);
- PerFunctionPasses.doFinalization();
- }
-
- {
- PrettyStackTraceString CrashInfo("Per-module optimization passes");
- PerModulePasses.run(*TheModule);
- }
-
- {
- PrettyStackTraceString CrashInfo("Code generation");
- CodeGenPasses.run(*TheModule);
- }
-
- if (ThinLinkOS)
- ThinLinkOS->keep();
- if (DwoOS)
- DwoOS->keep();
-}
-
-static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
- switch (Opts.OptimizationLevel) {
- default:
- llvm_unreachable("Invalid optimization level!");
-
- case 1:
- return PassBuilder::O1;
-
- case 2:
- switch (Opts.OptimizeSize) {
- default:
- llvm_unreachable("Invalid optimization level for size!");
-
- case 0:
- return PassBuilder::O2;
-
- case 1:
- return PassBuilder::Os;
-
- case 2:
- return PassBuilder::Oz;
- }
-
- case 3:
- return PassBuilder::O3;
- }
-}
-
-/// A clean version of `EmitAssembly` that uses the new pass manager.
-///
-/// Not all features are currently supported in this system, but where
-/// necessary it falls back to the legacy pass manager to at least provide
-/// basic functionality.
-///
-/// This API is planned to have its functionality finished and then to replace
-/// `EmitAssembly` at some point in the future when the default switches.
-void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
- BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) {
- TimeRegion Region(FrontendTimesIsEnabled ? &CodeGenerationTime : nullptr);
- setCommandLineOpts(CodeGenOpts);
-
- // The new pass manager always makes a target machine available to passes
- // during construction.
- CreateTargetMachine(/*MustCreateTM*/ true);
- if (!TM)
- // This will already be diagnosed, just bail.
- return;
- TheModule->setDataLayout(TM->createDataLayout());
-
- Optional<PGOOptions> PGOOpt;
-
- if (CodeGenOpts.hasProfileIRInstr())
- // -fprofile-generate.
- PGOOpt = PGOOptions(CodeGenOpts.InstrProfileOutput.empty()
- ? DefaultProfileGenName
- : CodeGenOpts.InstrProfileOutput,
- "", "", "", true,
- CodeGenOpts.DebugInfoForProfiling);
- else if (CodeGenOpts.hasProfileIRUse())
- // -fprofile-use.
- PGOOpt = PGOOptions("", CodeGenOpts.ProfileInstrumentUsePath, "",
- CodeGenOpts.ProfileRemappingFile, false,
- CodeGenOpts.DebugInfoForProfiling);
- else if (!CodeGenOpts.SampleProfileFile.empty())
- // -fprofile-sample-use
- PGOOpt = PGOOptions("", "", CodeGenOpts.SampleProfileFile,
- CodeGenOpts.ProfileRemappingFile, false,
- CodeGenOpts.DebugInfoForProfiling);
- else if (CodeGenOpts.DebugInfoForProfiling)
- // -fdebug-info-for-profiling
- PGOOpt = PGOOptions("", "", "", "", false, true);
-
- PassBuilder PB(TM.get(), PGOOpt);
-
- LoopAnalysisManager LAM(CodeGenOpts.DebugPassManager);
- FunctionAnalysisManager FAM(CodeGenOpts.DebugPassManager);
- CGSCCAnalysisManager CGAM(CodeGenOpts.DebugPassManager);
- ModuleAnalysisManager MAM(CodeGenOpts.DebugPassManager);
-
- // Register the AA manager first so that our version is the one used.
- FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
-
- // Register the target library analysis directly and give it a customized
- // preset TLI.
- Triple TargetTriple(TheModule->getTargetTriple());
- std::unique_ptr<TargetLibraryInfoImpl> TLII(
- createTLII(TargetTriple, CodeGenOpts));
- FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
- MAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
-
- // Register all the basic analyses with the managers.
- PB.registerModuleAnalyses(MAM);
- PB.registerCGSCCAnalyses(CGAM);
- PB.registerFunctionAnalyses(FAM);
- PB.registerLoopAnalyses(LAM);
- PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
-
- ModulePassManager MPM(CodeGenOpts.DebugPassManager);
-
- if (!CodeGenOpts.DisableLLVMPasses) {
- bool IsThinLTO = CodeGenOpts.PrepareForThinLTO;
- bool IsLTO = CodeGenOpts.PrepareForLTO;
-
- if (CodeGenOpts.OptimizationLevel == 0) {
- if (Optional<GCOVOptions> Options = getGCOVOptions(CodeGenOpts))
- MPM.addPass(GCOVProfilerPass(*Options));
-
- // Build a minimal pipeline based on the semantics required by Clang,
- // which is just that always inlining occurs.
- MPM.addPass(AlwaysInlinerPass());
-
- // At -O0 we directly run necessary sanitizer passes.
- if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds))
- MPM.addPass(createModuleToFunctionPassAdaptor(BoundsCheckingPass()));
-
- // Lastly, add semantically necessary passes for LTO.
- if (IsLTO || IsThinLTO) {
- MPM.addPass(CanonicalizeAliasesPass());
- MPM.addPass(NameAnonGlobalPass());
- }
- } else {
- // Map our optimization levels into one of the distinct levels used to
- // configure the pipeline.
- PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts);
-
- // Register callbacks to schedule sanitizer passes at the appropriate part of
- // the pipeline.
- if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds))
- PB.registerScalarOptimizerLateEPCallback(
- [](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
- FPM.addPass(BoundsCheckingPass());
- });
- if (Optional<GCOVOptions> Options = getGCOVOptions(CodeGenOpts))
- PB.registerPipelineStartEPCallback([Options](ModulePassManager &MPM) {
- MPM.addPass(GCOVProfilerPass(*Options));
- });
-
- if (IsThinLTO) {
- MPM = PB.buildThinLTOPreLinkDefaultPipeline(
- Level, CodeGenOpts.DebugPassManager);
- MPM.addPass(CanonicalizeAliasesPass());
- MPM.addPass(NameAnonGlobalPass());
- } else if (IsLTO) {
- MPM = PB.buildLTOPreLinkDefaultPipeline(Level,
- CodeGenOpts.DebugPassManager);
- MPM.addPass(CanonicalizeAliasesPass());
- MPM.addPass(NameAnonGlobalPass());
- } else {
- MPM = PB.buildPerModuleDefaultPipeline(Level,
- CodeGenOpts.DebugPassManager);
- }
- }
- }
-
- // FIXME: We still use the legacy pass manager to do code generation. We
- // create that pass manager here and use it as needed below.
- legacy::PassManager CodeGenPasses;
- bool NeedCodeGen = false;
- std::unique_ptr<llvm::ToolOutputFile> ThinLinkOS, DwoOS;
-
- // Append any output we need to the pass manager.
- switch (Action) {
- case Backend_EmitNothing:
- break;
-
- case Backend_EmitBC:
- if (CodeGenOpts.PrepareForThinLTO && !CodeGenOpts.DisableLLVMPasses) {
- if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) {
- ThinLinkOS = openOutputFile(CodeGenOpts.ThinLinkBitcodeFile);
- if (!ThinLinkOS)
- return;
- }
- TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
- CodeGenOpts.EnableSplitLTOUnit);
- MPM.addPass(ThinLTOBitcodeWriterPass(*OS, ThinLinkOS ? &ThinLinkOS->os()
- : nullptr));
- } else {
- // Emit a module summary by default for Regular LTO except for ld64
- // targets
- bool EmitLTOSummary =
- (CodeGenOpts.PrepareForLTO &&
- !CodeGenOpts.DisableLLVMPasses &&
- llvm::Triple(TheModule->getTargetTriple()).getVendor() !=
- llvm::Triple::Apple);
- if (EmitLTOSummary) {
- if (!TheModule->getModuleFlag("ThinLTO"))
- TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0));
- TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
- CodeGenOpts.EnableSplitLTOUnit);
- }
- MPM.addPass(
- BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists, EmitLTOSummary));
- }
- break;
-
- case Backend_EmitLL:
- MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists));
- break;
-
- case Backend_EmitAssembly:
- case Backend_EmitMCNull:
- case Backend_EmitObj:
- NeedCodeGen = true;
- CodeGenPasses.add(
- createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
- if (!CodeGenOpts.SplitDwarfFile.empty()) {
- DwoOS = openOutputFile(CodeGenOpts.SplitDwarfFile);
- if (!DwoOS)
- return;
- }
- if (!AddEmitPasses(CodeGenPasses, Action, *OS,
- DwoOS ? &DwoOS->os() : nullptr))
- // FIXME: Should we handle this error differently?
- return;
- break;
- }
-
- // Before executing passes, print the final values of the LLVM options.
- cl::PrintOptionValues();
-
- // Now that we have all of the passes ready, run them.
- {
- PrettyStackTraceString CrashInfo("Optimizer");
- MPM.run(*TheModule, MAM);
- }
-
- // Now if needed, run the legacy PM for codegen.
- if (NeedCodeGen) {
- PrettyStackTraceString CrashInfo("Code generation");
- CodeGenPasses.run(*TheModule);
- }
-
- if (ThinLinkOS)
- ThinLinkOS->keep();
- if (DwoOS)
- DwoOS->keep();
-}
-
-Expected<BitcodeModule> clang::FindThinLTOModule(MemoryBufferRef MBRef) {
- Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef);
- if (!BMsOrErr)
- return BMsOrErr.takeError();
-
- // The bitcode file may contain multiple modules, we want the one that is
- // marked as being the ThinLTO module.
- if (const BitcodeModule *Bm = FindThinLTOModule(*BMsOrErr))
- return *Bm;
-
- return make_error<StringError>("Could not find module summary",
- inconvertibleErrorCode());
-}
-
-BitcodeModule *clang::FindThinLTOModule(MutableArrayRef<BitcodeModule> BMs) {
- for (BitcodeModule &BM : BMs) {
- Expected<BitcodeLTOInfo> LTOInfo = BM.getLTOInfo();
- if (LTOInfo && LTOInfo->IsThinLTO)
- return &BM;
- }
- return nullptr;
-}
-
-static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
- const HeaderSearchOptions &HeaderOpts,
- const CodeGenOptions &CGOpts,
- const clang::TargetOptions &TOpts,
- const LangOptions &LOpts,
- std::unique_ptr<raw_pwrite_stream> OS,
- std::string SampleProfile,
- std::string ProfileRemapping,
- BackendAction Action) {
- StringMap<DenseMap<GlobalValue::GUID, GlobalValueSummary *>>
- ModuleToDefinedGVSummaries;
- CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
-
- setCommandLineOpts(CGOpts);
-
- // We can simply import the values mentioned in the combined index, since
- // we should only invoke this using the individual indexes written out
- // via a WriteIndexesThinBackend.
- FunctionImporter::ImportMapTy ImportList;
- for (auto &GlobalList : *CombinedIndex) {
- // Ignore entries for undefined references.
- if (GlobalList.second.SummaryList.empty())
- continue;
-
- auto GUID = GlobalList.first;
- for (auto &Summary : GlobalList.second.SummaryList) {
- // Skip the summaries for the importing module. These are included to
- // e.g. record required linkage changes.
- if (Summary->modulePath() == M->getModuleIdentifier())
- continue;
- // Add an entry to provoke importing by thinBackend.
- ImportList[Summary->modulePath()].insert(GUID);
- }
- }
-
- std::vector<std::unique_ptr<llvm::MemoryBuffer>> OwnedImports;
- MapVector<llvm::StringRef, llvm::BitcodeModule> ModuleMap;
-
- for (auto &I : ImportList) {
- ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MBOrErr =
- llvm::MemoryBuffer::getFile(I.first());
- if (!MBOrErr) {
- errs() << "Error loading imported file '" << I.first()
- << "': " << MBOrErr.getError().message() << "\n";
- return;
- }
-
- Expected<BitcodeModule> BMOrErr = FindThinLTOModule(**MBOrErr);
- if (!BMOrErr) {
- handleAllErrors(BMOrErr.takeError(), [&](ErrorInfoBase &EIB) {
- errs() << "Error loading imported file '" << I.first()
- << "': " << EIB.message() << '\n';
- });
- return;
- }
- ModuleMap.insert({I.first(), *BMOrErr});
-
- OwnedImports.push_back(std::move(*MBOrErr));
- }
- auto AddStream = [&](size_t Task) {
- return llvm::make_unique<lto::NativeObjectStream>(std::move(OS));
- };
- lto::Config Conf;
- if (CGOpts.SaveTempsFilePrefix != "") {
- if (Error E = Conf.addSaveTemps(CGOpts.SaveTempsFilePrefix + ".",
- /* UseInputModulePath */ false)) {
- handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
- errs() << "Error setting up ThinLTO save-temps: " << EIB.message()
- << '\n';
- });
- }
- }
- Conf.CPU = TOpts.CPU;
- Conf.CodeModel = getCodeModel(CGOpts);
- Conf.MAttrs = TOpts.Features;
- Conf.RelocModel = CGOpts.RelocationModel;
- Conf.CGOptLevel = getCGOptLevel(CGOpts);
- initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts);
- Conf.SampleProfile = std::move(SampleProfile);
- Conf.ProfileRemapping = std::move(ProfileRemapping);
- Conf.UseNewPM = CGOpts.ExperimentalNewPassManager;
- Conf.DebugPassManager = CGOpts.DebugPassManager;
- Conf.RemarksWithHotness = CGOpts.DiagnosticsWithHotness;
- Conf.RemarksFilename = CGOpts.OptRecordFile;
- Conf.DwoPath = CGOpts.SplitDwarfFile;
- switch (Action) {
- case Backend_EmitNothing:
- Conf.PreCodeGenModuleHook = [](size_t Task, const Module &Mod) {
- return false;
- };
- break;
- case Backend_EmitLL:
- Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) {
- M->print(*OS, nullptr, CGOpts.EmitLLVMUseLists);
- return false;
- };
- break;
- case Backend_EmitBC:
- Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) {
- WriteBitcodeToFile(*M, *OS, CGOpts.EmitLLVMUseLists);
- return false;
- };
- break;
- default:
- Conf.CGFileType = getCodeGenFileType(Action);
- break;
- }
- if (Error E = thinBackend(
- Conf, -1, AddStream, *M, *CombinedIndex, ImportList,
- ModuleToDefinedGVSummaries[M->getModuleIdentifier()], ModuleMap)) {
- handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
- errs() << "Error running ThinLTO backend: " << EIB.message() << '\n';
- });
- }
-}
-
-void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
- const HeaderSearchOptions &HeaderOpts,
- const CodeGenOptions &CGOpts,
- const clang::TargetOptions &TOpts,
- const LangOptions &LOpts,
- const llvm::DataLayout &TDesc, Module *M,
- BackendAction Action,
- std::unique_ptr<raw_pwrite_stream> OS) {
- std::unique_ptr<llvm::Module> EmptyModule;
- if (!CGOpts.ThinLTOIndexFile.empty()) {
- // If we are performing a ThinLTO importing compile, load the function index
- // into memory and pass it into runThinLTOBackend, which will run the
- // function importer and invoke LTO passes.
- Expected<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr =
- llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile,
- /*IgnoreEmptyThinLTOIndexFile*/true);
- if (!IndexOrErr) {
- logAllUnhandledErrors(IndexOrErr.takeError(), errs(),
- "Error loading index file '" +
- CGOpts.ThinLTOIndexFile + "': ");
- return;
- }
- std::unique_ptr<ModuleSummaryIndex> CombinedIndex = std::move(*IndexOrErr);
- // A null CombinedIndex means we should skip ThinLTO compilation
- // (LLVM will optionally ignore empty index files, returning null instead
- // of an error).
- if (CombinedIndex) {
- if (!CombinedIndex->skipModuleByDistributedBackend()) {
- runThinLTOBackend(CombinedIndex.get(), M, HeaderOpts, CGOpts, TOpts,
- LOpts, std::move(OS), CGOpts.SampleProfileFile,
- CGOpts.ProfileRemappingFile, Action);
- return;
- }
- // Distributed indexing detected that nothing from the module is needed
- // for the final linking. So we can skip the compilation. We sill need to
- // output an empty object file to make sure that a linker does not fail
- // trying to read it. Also for some features, like CFI, we must skip
- // the compilation as CombinedIndex does not contain all required
- // information.
- EmptyModule = llvm::make_unique<llvm::Module>("empty", M->getContext());
- EmptyModule->setTargetTriple(M->getTargetTriple());
- M = EmptyModule.get();
- }
- }
-
- EmitAssemblyHelper AsmHelper(Diags, HeaderOpts, CGOpts, TOpts, LOpts, M);
-
- if (CGOpts.ExperimentalNewPassManager)
- AsmHelper.EmitAssemblyWithNewPassManager(Action, std::move(OS));
- else
- AsmHelper.EmitAssembly(Action, std::move(OS));
-
- // Verify clang's TargetInfo DataLayout against the LLVM TargetMachine's
- // DataLayout.
- if (AsmHelper.TM) {
- std::string DLDesc = M->getDataLayout().getStringRepresentation();
- if (DLDesc != TDesc.getStringRepresentation()) {
- unsigned DiagID = Diags.getCustomDiagID(
- DiagnosticsEngine::Error, "backend data layout '%0' does not match "
- "expected target description '%1'");
- Diags.Report(DiagID) << DLDesc << TDesc.getStringRepresentation();
- }
- }
-}
-
-static const char* getSectionNameForBitcode(const Triple &T) {
- switch (T.getObjectFormat()) {
- case Triple::MachO:
- return "__LLVM,__bitcode";
- case Triple::COFF:
- case Triple::ELF:
- case Triple::Wasm:
- case Triple::UnknownObjectFormat:
- return ".llvmbc";
- }
- llvm_unreachable("Unimplemented ObjectFormatType");
-}
-
-static const char* getSectionNameForCommandline(const Triple &T) {
- switch (T.getObjectFormat()) {
- case Triple::MachO:
- return "__LLVM,__cmdline";
- case Triple::COFF:
- case Triple::ELF:
- case Triple::Wasm:
- case Triple::UnknownObjectFormat:
- return ".llvmcmd";
- }
- llvm_unreachable("Unimplemented ObjectFormatType");
-}
-
-// With -fembed-bitcode, save a copy of the llvm IR as data in the
-// __LLVM,__bitcode section.
-void clang::EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts,
- llvm::MemoryBufferRef Buf) {
- if (CGOpts.getEmbedBitcode() == CodeGenOptions::Embed_Off)
- return;
-
- // Save llvm.compiler.used and remote it.
- SmallVector<Constant*, 2> UsedArray;
- SmallPtrSet<GlobalValue*, 4> UsedGlobals;
- Type *UsedElementType = Type::getInt8Ty(M->getContext())->getPointerTo(0);
- GlobalVariable *Used = collectUsedGlobalVariables(*M, UsedGlobals, true);
- for (auto *GV : UsedGlobals) {
- if (GV->getName() != "llvm.embedded.module" &&
- GV->getName() != "llvm.cmdline")
- UsedArray.push_back(
- ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
- }
- if (Used)
- Used->eraseFromParent();
-
- // Embed the bitcode for the llvm module.
- std::string Data;
- ArrayRef<uint8_t> ModuleData;
- Triple T(M->getTargetTriple());
- // Create a constant that contains the bitcode.
- // In case of embedding a marker, ignore the input Buf and use the empty
- // ArrayRef. It is also legal to create a bitcode marker even Buf is empty.
- if (CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Marker) {
- if (!isBitcode((const unsigned char *)Buf.getBufferStart(),
- (const unsigned char *)Buf.getBufferEnd())) {
- // If the input is LLVM Assembly, bitcode is produced by serializing
- // the module. Use-lists order need to be perserved in this case.
- llvm::raw_string_ostream OS(Data);
- llvm::WriteBitcodeToFile(*M, OS, /* ShouldPreserveUseListOrder */ true);
- ModuleData =
- ArrayRef<uint8_t>((const uint8_t *)OS.str().data(), OS.str().size());
- } else
- // If the input is LLVM bitcode, write the input byte stream directly.
- ModuleData = ArrayRef<uint8_t>((const uint8_t *)Buf.getBufferStart(),
- Buf.getBufferSize());
- }
- llvm::Constant *ModuleConstant =
- llvm::ConstantDataArray::get(M->getContext(), ModuleData);
- llvm::GlobalVariable *GV = new llvm::GlobalVariable(
- *M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage,
- ModuleConstant);
- GV->setSection(getSectionNameForBitcode(T));
- UsedArray.push_back(
- ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
- if (llvm::GlobalVariable *Old =
- M->getGlobalVariable("llvm.embedded.module", true)) {
- assert(Old->hasOneUse() &&
- "llvm.embedded.module can only be used once in llvm.compiler.used");
- GV->takeName(Old);
- Old->eraseFromParent();
- } else {
- GV->setName("llvm.embedded.module");
- }
-
- // Skip if only bitcode needs to be embedded.
- if (CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Bitcode) {
- // Embed command-line options.
- ArrayRef<uint8_t> CmdData(const_cast<uint8_t *>(CGOpts.CmdArgs.data()),
- CGOpts.CmdArgs.size());
- llvm::Constant *CmdConstant =
- llvm::ConstantDataArray::get(M->getContext(), CmdData);
- GV = new llvm::GlobalVariable(*M, CmdConstant->getType(), true,
- llvm::GlobalValue::PrivateLinkage,
- CmdConstant);
- GV->setSection(getSectionNameForCommandline(T));
- UsedArray.push_back(
- ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType));
- if (llvm::GlobalVariable *Old =
- M->getGlobalVariable("llvm.cmdline", true)) {
- assert(Old->hasOneUse() &&
- "llvm.cmdline can only be used once in llvm.compiler.used");
- GV->takeName(Old);
- Old->eraseFromParent();
- } else {
- GV->setName("llvm.cmdline");
- }
- }
-
- if (UsedArray.empty())
- return;
-
- // Recreate llvm.compiler.used.
- ArrayType *ATy = ArrayType::get(UsedElementType, UsedArray.size());
- auto *NewUsed = new GlobalVariable(
- *M, ATy, false, llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used");
- NewUsed->setSection("llvm.metadata");
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp
deleted file mode 100644
index 24056a449de..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp
+++ /dev/null
@@ -1,2043 +0,0 @@
-//===--- CGAtomic.cpp - Emit LLVM IR for atomic operations ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains the code for emitting atomic operations.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCall.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Operator.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
- class AtomicInfo {
- CodeGenFunction &CGF;
- QualType AtomicTy;
- QualType ValueTy;
- uint64_t AtomicSizeInBits;
- uint64_t ValueSizeInBits;
- CharUnits AtomicAlign;
- CharUnits ValueAlign;
- CharUnits LValueAlign;
- TypeEvaluationKind EvaluationKind;
- bool UseLibcall;
- LValue LVal;
- CGBitFieldInfo BFI;
- public:
- AtomicInfo(CodeGenFunction &CGF, LValue &lvalue)
- : CGF(CGF), AtomicSizeInBits(0), ValueSizeInBits(0),
- EvaluationKind(TEK_Scalar), UseLibcall(true) {
- assert(!lvalue.isGlobalReg());
- ASTContext &C = CGF.getContext();
- if (lvalue.isSimple()) {
- AtomicTy = lvalue.getType();
- if (auto *ATy = AtomicTy->getAs<AtomicType>())
- ValueTy = ATy->getValueType();
- else
- ValueTy = AtomicTy;
- EvaluationKind = CGF.getEvaluationKind(ValueTy);
-
- uint64_t ValueAlignInBits;
- uint64_t AtomicAlignInBits;
- TypeInfo ValueTI = C.getTypeInfo(ValueTy);
- ValueSizeInBits = ValueTI.Width;
- ValueAlignInBits = ValueTI.Align;
-
- TypeInfo AtomicTI = C.getTypeInfo(AtomicTy);
- AtomicSizeInBits = AtomicTI.Width;
- AtomicAlignInBits = AtomicTI.Align;
-
- assert(ValueSizeInBits <= AtomicSizeInBits);
- assert(ValueAlignInBits <= AtomicAlignInBits);
-
- AtomicAlign = C.toCharUnitsFromBits(AtomicAlignInBits);
- ValueAlign = C.toCharUnitsFromBits(ValueAlignInBits);
- if (lvalue.getAlignment().isZero())
- lvalue.setAlignment(AtomicAlign);
-
- LVal = lvalue;
- } else if (lvalue.isBitField()) {
- ValueTy = lvalue.getType();
- ValueSizeInBits = C.getTypeSize(ValueTy);
- auto &OrigBFI = lvalue.getBitFieldInfo();
- auto Offset = OrigBFI.Offset % C.toBits(lvalue.getAlignment());
- AtomicSizeInBits = C.toBits(
- C.toCharUnitsFromBits(Offset + OrigBFI.Size + C.getCharWidth() - 1)
- .alignTo(lvalue.getAlignment()));
- auto VoidPtrAddr = CGF.EmitCastToVoidPtr(lvalue.getBitFieldPointer());
- auto OffsetInChars =
- (C.toCharUnitsFromBits(OrigBFI.Offset) / lvalue.getAlignment()) *
- lvalue.getAlignment();
- VoidPtrAddr = CGF.Builder.CreateConstGEP1_64(
- VoidPtrAddr, OffsetInChars.getQuantity());
- auto Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- VoidPtrAddr,
- CGF.Builder.getIntNTy(AtomicSizeInBits)->getPointerTo(),
- "atomic_bitfield_base");
- BFI = OrigBFI;
- BFI.Offset = Offset;
- BFI.StorageSize = AtomicSizeInBits;
- BFI.StorageOffset += OffsetInChars;
- LVal = LValue::MakeBitfield(Address(Addr, lvalue.getAlignment()),
- BFI, lvalue.getType(), lvalue.getBaseInfo(),
- lvalue.getTBAAInfo());
- AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned);
- if (AtomicTy.isNull()) {
- llvm::APInt Size(
- /*numBits=*/32,
- C.toCharUnitsFromBits(AtomicSizeInBits).getQuantity());
- AtomicTy = C.getConstantArrayType(C.CharTy, Size, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- }
- AtomicAlign = ValueAlign = lvalue.getAlignment();
- } else if (lvalue.isVectorElt()) {
- ValueTy = lvalue.getType()->getAs<VectorType>()->getElementType();
- ValueSizeInBits = C.getTypeSize(ValueTy);
- AtomicTy = lvalue.getType();
- AtomicSizeInBits = C.getTypeSize(AtomicTy);
- AtomicAlign = ValueAlign = lvalue.getAlignment();
- LVal = lvalue;
- } else {
- assert(lvalue.isExtVectorElt());
- ValueTy = lvalue.getType();
- ValueSizeInBits = C.getTypeSize(ValueTy);
- AtomicTy = ValueTy = CGF.getContext().getExtVectorType(
- lvalue.getType(), lvalue.getExtVectorAddress()
- .getElementType()->getVectorNumElements());
- AtomicSizeInBits = C.getTypeSize(AtomicTy);
- AtomicAlign = ValueAlign = lvalue.getAlignment();
- LVal = lvalue;
- }
- UseLibcall = !C.getTargetInfo().hasBuiltinAtomic(
- AtomicSizeInBits, C.toBits(lvalue.getAlignment()));
- }
-
- QualType getAtomicType() const { return AtomicTy; }
- QualType getValueType() const { return ValueTy; }
- CharUnits getAtomicAlignment() const { return AtomicAlign; }
- CharUnits getValueAlignment() const { return ValueAlign; }
- uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
- uint64_t getValueSizeInBits() const { return ValueSizeInBits; }
- TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
- bool shouldUseLibcall() const { return UseLibcall; }
- const LValue &getAtomicLValue() const { return LVal; }
- llvm::Value *getAtomicPointer() const {
- if (LVal.isSimple())
- return LVal.getPointer();
- else if (LVal.isBitField())
- return LVal.getBitFieldPointer();
- else if (LVal.isVectorElt())
- return LVal.getVectorPointer();
- assert(LVal.isExtVectorElt());
- return LVal.getExtVectorPointer();
- }
- Address getAtomicAddress() const {
- return Address(getAtomicPointer(), getAtomicAlignment());
- }
-
- Address getAtomicAddressAsAtomicIntPointer() const {
- return emitCastToAtomicIntPointer(getAtomicAddress());
- }
-
- /// Is the atomic size larger than the underlying value type?
- ///
- /// Note that the absence of padding does not mean that atomic
- /// objects are completely interchangeable with non-atomic
- /// objects: we might have promoted the alignment of a type
- /// without making it bigger.
- bool hasPadding() const {
- return (ValueSizeInBits != AtomicSizeInBits);
- }
-
- bool emitMemSetZeroIfNecessary() const;
-
- llvm::Value *getAtomicSizeValue() const {
- CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits);
- return CGF.CGM.getSize(size);
- }
-
- /// Cast the given pointer to an integer pointer suitable for atomic
- /// operations if the source.
- Address emitCastToAtomicIntPointer(Address Addr) const;
-
- /// If Addr is compatible with the iN that will be used for an atomic
- /// operation, bitcast it. Otherwise, create a temporary that is suitable
- /// and copy the value across.
- Address convertToAtomicIntPointer(Address Addr) const;
-
- /// Turn an atomic-layout object into an r-value.
- RValue convertAtomicTempToRValue(Address addr, AggValueSlot resultSlot,
- SourceLocation loc, bool AsValue) const;
-
- /// Converts a rvalue to integer value.
- llvm::Value *convertRValueToInt(RValue RVal) const;
-
- RValue ConvertIntToValueOrAtomic(llvm::Value *IntVal,
- AggValueSlot ResultSlot,
- SourceLocation Loc, bool AsValue) const;
-
- /// Copy an atomic r-value into atomic-layout memory.
- void emitCopyIntoMemory(RValue rvalue) const;
-
- /// Project an l-value down to the value field.
- LValue projectValue() const {
- assert(LVal.isSimple());
- Address addr = getAtomicAddress();
- if (hasPadding())
- addr = CGF.Builder.CreateStructGEP(addr, 0, CharUnits());
-
- return LValue::MakeAddr(addr, getValueType(), CGF.getContext(),
- LVal.getBaseInfo(), LVal.getTBAAInfo());
- }
-
- /// Emits atomic load.
- /// \returns Loaded value.
- RValue EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
- bool AsValue, llvm::AtomicOrdering AO,
- bool IsVolatile);
-
- /// Emits atomic compare-and-exchange sequence.
- /// \param Expected Expected value.
- /// \param Desired Desired value.
- /// \param Success Atomic ordering for success operation.
- /// \param Failure Atomic ordering for failed operation.
- /// \param IsWeak true if atomic operation is weak, false otherwise.
- /// \returns Pair of values: previous value from storage (value type) and
- /// boolean flag (i1 type) with true if success and false otherwise.
- std::pair<RValue, llvm::Value *>
- EmitAtomicCompareExchange(RValue Expected, RValue Desired,
- llvm::AtomicOrdering Success =
- llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::AtomicOrdering Failure =
- llvm::AtomicOrdering::SequentiallyConsistent,
- bool IsWeak = false);
-
- /// Emits atomic update.
- /// \param AO Atomic ordering.
- /// \param UpdateOp Update operation for the current lvalue.
- void EmitAtomicUpdate(llvm::AtomicOrdering AO,
- const llvm::function_ref<RValue(RValue)> &UpdateOp,
- bool IsVolatile);
- /// Emits atomic update.
- /// \param AO Atomic ordering.
- void EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal,
- bool IsVolatile);
-
- /// Materialize an atomic r-value in atomic-layout memory.
- Address materializeRValue(RValue rvalue) const;
-
- /// Creates temp alloca for intermediate operations on atomic value.
- Address CreateTempAlloca() const;
- private:
- bool requiresMemSetZero(llvm::Type *type) const;
-
-
- /// Emits atomic load as a libcall.
- void EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
- llvm::AtomicOrdering AO, bool IsVolatile);
- /// Emits atomic load as LLVM instruction.
- llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile);
- /// Emits atomic compare-and-exchange op as a libcall.
- llvm::Value *EmitAtomicCompareExchangeLibcall(
- llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr,
- llvm::AtomicOrdering Success =
- llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::AtomicOrdering Failure =
- llvm::AtomicOrdering::SequentiallyConsistent);
- /// Emits atomic compare-and-exchange op as LLVM instruction.
- std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeOp(
- llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
- llvm::AtomicOrdering Success =
- llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::AtomicOrdering Failure =
- llvm::AtomicOrdering::SequentiallyConsistent,
- bool IsWeak = false);
- /// Emit atomic update as libcalls.
- void
- EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,
- const llvm::function_ref<RValue(RValue)> &UpdateOp,
- bool IsVolatile);
- /// Emit atomic update as LLVM instructions.
- void EmitAtomicUpdateOp(llvm::AtomicOrdering AO,
- const llvm::function_ref<RValue(RValue)> &UpdateOp,
- bool IsVolatile);
- /// Emit atomic update as libcalls.
- void EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, RValue UpdateRVal,
- bool IsVolatile);
- /// Emit atomic update as LLVM instructions.
- void EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRal,
- bool IsVolatile);
- };
-}
-
-Address AtomicInfo::CreateTempAlloca() const {
- Address TempAlloca = CGF.CreateMemTemp(
- (LVal.isBitField() && ValueSizeInBits > AtomicSizeInBits) ? ValueTy
- : AtomicTy,
- getAtomicAlignment(),
- "atomic-temp");
- // Cast to pointer to value type for bitfields.
- if (LVal.isBitField())
- return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- TempAlloca, getAtomicAddress().getType());
- return TempAlloca;
-}
-
-static RValue emitAtomicLibcall(CodeGenFunction &CGF,
- StringRef fnName,
- QualType resultType,
- CallArgList &args) {
- const CGFunctionInfo &fnInfo =
- CGF.CGM.getTypes().arrangeBuiltinFunctionCall(resultType, args);
- llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo);
- llvm::Constant *fn = CGF.CGM.CreateRuntimeFunction(fnTy, fnName);
- auto callee = CGCallee::forDirect(fn);
- return CGF.EmitCall(fnInfo, callee, ReturnValueSlot(), args);
-}
-
-/// Does a store of the given IR type modify the full expected width?
-static bool isFullSizeType(CodeGenModule &CGM, llvm::Type *type,
- uint64_t expectedSize) {
- return (CGM.getDataLayout().getTypeStoreSize(type) * 8 == expectedSize);
-}
-
-/// Does the atomic type require memsetting to zero before initialization?
-///
-/// The IR type is provided as a way of making certain queries faster.
-bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
- // If the atomic type has size padding, we definitely need a memset.
- if (hasPadding()) return true;
-
- // Otherwise, do some simple heuristics to try to avoid it:
- switch (getEvaluationKind()) {
- // For scalars and complexes, check whether the store size of the
- // type uses the full size.
- case TEK_Scalar:
- return !isFullSizeType(CGF.CGM, type, AtomicSizeInBits);
- case TEK_Complex:
- return !isFullSizeType(CGF.CGM, type->getStructElementType(0),
- AtomicSizeInBits / 2);
-
- // Padding in structs has an undefined bit pattern. User beware.
- case TEK_Aggregate:
- return false;
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-bool AtomicInfo::emitMemSetZeroIfNecessary() const {
- assert(LVal.isSimple());
- llvm::Value *addr = LVal.getPointer();
- if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
- return false;
-
- CGF.Builder.CreateMemSet(
- addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
- CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(),
- LVal.getAlignment().getQuantity());
- return true;
-}
-
-static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
- Address Dest, Address Ptr,
- Address Val1, Address Val2,
- uint64_t Size,
- llvm::AtomicOrdering SuccessOrder,
- llvm::AtomicOrdering FailureOrder,
- llvm::SyncScope::ID Scope) {
- // Note that cmpxchg doesn't support weak cmpxchg, at least at the moment.
- llvm::Value *Expected = CGF.Builder.CreateLoad(Val1);
- llvm::Value *Desired = CGF.Builder.CreateLoad(Val2);
-
- llvm::AtomicCmpXchgInst *Pair = CGF.Builder.CreateAtomicCmpXchg(
- Ptr.getPointer(), Expected, Desired, SuccessOrder, FailureOrder,
- Scope);
- Pair->setVolatile(E->isVolatile());
- Pair->setWeak(IsWeak);
-
- // Cmp holds the result of the compare-exchange operation: true on success,
- // false on failure.
- llvm::Value *Old = CGF.Builder.CreateExtractValue(Pair, 0);
- llvm::Value *Cmp = CGF.Builder.CreateExtractValue(Pair, 1);
-
- // This basic block is used to hold the store instruction if the operation
- // failed.
- llvm::BasicBlock *StoreExpectedBB =
- CGF.createBasicBlock("cmpxchg.store_expected", CGF.CurFn);
-
- // This basic block is the exit point of the operation, we should end up
- // here regardless of whether or not the operation succeeded.
- llvm::BasicBlock *ContinueBB =
- CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
-
- // Update Expected if Expected isn't equal to Old, otherwise branch to the
- // exit point.
- CGF.Builder.CreateCondBr(Cmp, ContinueBB, StoreExpectedBB);
-
- CGF.Builder.SetInsertPoint(StoreExpectedBB);
- // Update the memory at Expected with Old's value.
- CGF.Builder.CreateStore(Old, Val1);
- // Finally, branch to the exit point.
- CGF.Builder.CreateBr(ContinueBB);
-
- CGF.Builder.SetInsertPoint(ContinueBB);
- // Update the memory at Dest with Cmp's value.
- CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
-}
-
-/// Given an ordering required on success, emit all possible cmpxchg
-/// instructions to cope with the provided (but possibly only dynamically known)
-/// FailureOrder.
-static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
- bool IsWeak, Address Dest, Address Ptr,
- Address Val1, Address Val2,
- llvm::Value *FailureOrderVal,
- uint64_t Size,
- llvm::AtomicOrdering SuccessOrder,
- llvm::SyncScope::ID Scope) {
- llvm::AtomicOrdering FailureOrder;
- if (llvm::ConstantInt *FO = dyn_cast<llvm::ConstantInt>(FailureOrderVal)) {
- auto FOS = FO->getSExtValue();
- if (!llvm::isValidAtomicOrderingCABI(FOS))
- FailureOrder = llvm::AtomicOrdering::Monotonic;
- else
- switch ((llvm::AtomicOrderingCABI)FOS) {
- case llvm::AtomicOrderingCABI::relaxed:
- case llvm::AtomicOrderingCABI::release:
- case llvm::AtomicOrderingCABI::acq_rel:
- FailureOrder = llvm::AtomicOrdering::Monotonic;
- break;
- case llvm::AtomicOrderingCABI::consume:
- case llvm::AtomicOrderingCABI::acquire:
- FailureOrder = llvm::AtomicOrdering::Acquire;
- break;
- case llvm::AtomicOrderingCABI::seq_cst:
- FailureOrder = llvm::AtomicOrdering::SequentiallyConsistent;
- break;
- }
- if (isStrongerThan(FailureOrder, SuccessOrder)) {
- // Don't assert on undefined behavior "failure argument shall be no
- // stronger than the success argument".
- FailureOrder =
- llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrder);
- }
- emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
- FailureOrder, Scope);
- return;
- }
-
- // Create all the relevant BB's
- llvm::BasicBlock *MonotonicBB = nullptr, *AcquireBB = nullptr,
- *SeqCstBB = nullptr;
- MonotonicBB = CGF.createBasicBlock("monotonic_fail", CGF.CurFn);
- if (SuccessOrder != llvm::AtomicOrdering::Monotonic &&
- SuccessOrder != llvm::AtomicOrdering::Release)
- AcquireBB = CGF.createBasicBlock("acquire_fail", CGF.CurFn);
- if (SuccessOrder == llvm::AtomicOrdering::SequentiallyConsistent)
- SeqCstBB = CGF.createBasicBlock("seqcst_fail", CGF.CurFn);
-
- llvm::BasicBlock *ContBB = CGF.createBasicBlock("atomic.continue", CGF.CurFn);
-
- llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(FailureOrderVal, MonotonicBB);
-
- // Emit all the different atomics
-
- // MonotonicBB is arbitrarily chosen as the default case; in practice, this
- // doesn't matter unless someone is crazy enough to use something that
- // doesn't fold to a constant for the ordering.
- CGF.Builder.SetInsertPoint(MonotonicBB);
- emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
- Size, SuccessOrder, llvm::AtomicOrdering::Monotonic, Scope);
- CGF.Builder.CreateBr(ContBB);
-
- if (AcquireBB) {
- CGF.Builder.SetInsertPoint(AcquireBB);
- emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
- Size, SuccessOrder, llvm::AtomicOrdering::Acquire, Scope);
- CGF.Builder.CreateBr(ContBB);
- SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
- AcquireBB);
- SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::acquire),
- AcquireBB);
- }
- if (SeqCstBB) {
- CGF.Builder.SetInsertPoint(SeqCstBB);
- emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
- llvm::AtomicOrdering::SequentiallyConsistent, Scope);
- CGF.Builder.CreateBr(ContBB);
- SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
- SeqCstBB);
- }
-
- CGF.Builder.SetInsertPoint(ContBB);
-}
-
-static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
- Address Ptr, Address Val1, Address Val2,
- llvm::Value *IsWeak, llvm::Value *FailureOrder,
- uint64_t Size, llvm::AtomicOrdering Order,
- llvm::SyncScope::ID Scope) {
- llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
- llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- case AtomicExpr::AO__opencl_atomic_init:
- llvm_unreachable("Already handled!");
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
- emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order, Scope);
- return;
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
- emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order, Scope);
- return;
- case AtomicExpr::AO__atomic_compare_exchange:
- case AtomicExpr::AO__atomic_compare_exchange_n: {
- if (llvm::ConstantInt *IsWeakC = dyn_cast<llvm::ConstantInt>(IsWeak)) {
- emitAtomicCmpXchgFailureSet(CGF, E, IsWeakC->getZExtValue(), Dest, Ptr,
- Val1, Val2, FailureOrder, Size, Order, Scope);
- } else {
- // Create all the relevant BB's
- llvm::BasicBlock *StrongBB =
- CGF.createBasicBlock("cmpxchg.strong", CGF.CurFn);
- llvm::BasicBlock *WeakBB = CGF.createBasicBlock("cmxchg.weak", CGF.CurFn);
- llvm::BasicBlock *ContBB =
- CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
-
- llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(IsWeak, WeakBB);
- SI->addCase(CGF.Builder.getInt1(false), StrongBB);
-
- CGF.Builder.SetInsertPoint(StrongBB);
- emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order, Scope);
- CGF.Builder.CreateBr(ContBB);
-
- CGF.Builder.SetInsertPoint(WeakBB);
- emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order, Scope);
- CGF.Builder.CreateBr(ContBB);
-
- CGF.Builder.SetInsertPoint(ContBB);
- }
- return;
- }
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__opencl_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- case AtomicExpr::AO__atomic_load: {
- llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
- Load->setAtomic(Order, Scope);
- Load->setVolatile(E->isVolatile());
- CGF.Builder.CreateStore(Load, Dest);
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__opencl_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n: {
- llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
- Store->setAtomic(Order, Scope);
- Store->setVolatile(E->isVolatile());
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__opencl_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- Op = llvm::AtomicRMWInst::Xchg;
- break;
-
- case AtomicExpr::AO__atomic_add_fetch:
- PostOp = llvm::Instruction::Add;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__opencl_atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_add:
- Op = llvm::AtomicRMWInst::Add;
- break;
-
- case AtomicExpr::AO__atomic_sub_fetch:
- PostOp = llvm::Instruction::Sub;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- case AtomicExpr::AO__opencl_atomic_fetch_sub:
- case AtomicExpr::AO__atomic_fetch_sub:
- Op = llvm::AtomicRMWInst::Sub;
- break;
-
- case AtomicExpr::AO__opencl_atomic_fetch_min:
- case AtomicExpr::AO__atomic_fetch_min:
- Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min
- : llvm::AtomicRMWInst::UMin;
- break;
-
- case AtomicExpr::AO__opencl_atomic_fetch_max:
- case AtomicExpr::AO__atomic_fetch_max:
- Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max
- : llvm::AtomicRMWInst::UMax;
- break;
-
- case AtomicExpr::AO__atomic_and_fetch:
- PostOp = llvm::Instruction::And;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__opencl_atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_and:
- Op = llvm::AtomicRMWInst::And;
- break;
-
- case AtomicExpr::AO__atomic_or_fetch:
- PostOp = llvm::Instruction::Or;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__opencl_atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_or:
- Op = llvm::AtomicRMWInst::Or;
- break;
-
- case AtomicExpr::AO__atomic_xor_fetch:
- PostOp = llvm::Instruction::Xor;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__opencl_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_xor:
- Op = llvm::AtomicRMWInst::Xor;
- break;
-
- case AtomicExpr::AO__atomic_nand_fetch:
- PostOp = llvm::Instruction::And; // the NOT is special cased below
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__atomic_fetch_nand:
- Op = llvm::AtomicRMWInst::Nand;
- break;
- }
-
- llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- llvm::AtomicRMWInst *RMWI =
- CGF.Builder.CreateAtomicRMW(Op, Ptr.getPointer(), LoadVal1, Order, Scope);
- RMWI->setVolatile(E->isVolatile());
-
- // For __atomic_*_fetch operations, perform the operation again to
- // determine the value which was written.
- llvm::Value *Result = RMWI;
- if (PostOp)
- Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
- if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
- Result = CGF.Builder.CreateNot(Result);
- CGF.Builder.CreateStore(Result, Dest);
-}
-
-// This function emits any expression (scalar, complex, or aggregate)
-// into a temporary alloca.
-static Address
-EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
- Address DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
- CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
- /*Init*/ true);
- return DeclPtr;
-}
-
-static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
- Address Ptr, Address Val1, Address Val2,
- llvm::Value *IsWeak, llvm::Value *FailureOrder,
- uint64_t Size, llvm::AtomicOrdering Order,
- llvm::Value *Scope) {
- auto ScopeModel = Expr->getScopeModel();
-
- // LLVM atomic instructions always have synch scope. If clang atomic
- // expression has no scope operand, use default LLVM synch scope.
- if (!ScopeModel) {
- EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
- Order, CGF.CGM.getLLVMContext().getOrInsertSyncScopeID(""));
- return;
- }
-
- // Handle constant scope.
- if (auto SC = dyn_cast<llvm::ConstantInt>(Scope)) {
- auto SCID = CGF.getTargetHooks().getLLVMSyncScopeID(
- ScopeModel->map(SC->getZExtValue()), CGF.CGM.getLLVMContext());
- EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
- Order, SCID);
- return;
- }
-
- // Handle non-constant scope.
- auto &Builder = CGF.Builder;
- auto Scopes = ScopeModel->getRuntimeValues();
- llvm::DenseMap<unsigned, llvm::BasicBlock *> BB;
- for (auto S : Scopes)
- BB[S] = CGF.createBasicBlock(getAsString(ScopeModel->map(S)), CGF.CurFn);
-
- llvm::BasicBlock *ContBB =
- CGF.createBasicBlock("atomic.scope.continue", CGF.CurFn);
-
- auto *SC = Builder.CreateIntCast(Scope, Builder.getInt32Ty(), false);
- // If unsupported synch scope is encountered at run time, assume a fallback
- // synch scope value.
- auto FallBack = ScopeModel->getFallBackValue();
- llvm::SwitchInst *SI = Builder.CreateSwitch(SC, BB[FallBack]);
- for (auto S : Scopes) {
- auto *B = BB[S];
- if (S != FallBack)
- SI->addCase(Builder.getInt32(S), B);
-
- Builder.SetInsertPoint(B);
- EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
- Order,
- CGF.getTargetHooks().getLLVMSyncScopeID(ScopeModel->map(S),
- CGF.getLLVMContext()));
- Builder.CreateBr(ContBB);
- }
-
- Builder.SetInsertPoint(ContBB);
-}
-
-static void
-AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
- bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,
- SourceLocation Loc, CharUnits SizeInChars) {
- if (UseOptimizedLibcall) {
- // Load value and pass it to the function directly.
- CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy);
- int64_t SizeInBits = CGF.getContext().toBits(SizeInChars);
- ValTy =
- CGF.getContext().getIntTypeForBitwidth(SizeInBits, /*Signed=*/false);
- llvm::Type *IPtrTy = llvm::IntegerType::get(CGF.getLLVMContext(),
- SizeInBits)->getPointerTo();
- Address Ptr = Address(CGF.Builder.CreateBitCast(Val, IPtrTy), Align);
- Val = CGF.EmitLoadOfScalar(Ptr, false,
- CGF.getContext().getPointerType(ValTy),
- Loc);
- // Coerce the value into an appropriately sized integer type.
- Args.add(RValue::get(Val), ValTy);
- } else {
- // Non-optimized functions always take a reference.
- Args.add(RValue::get(CGF.EmitCastToVoidPtr(Val)),
- CGF.getContext().VoidPtrTy);
- }
-}
-
-RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
- QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
- QualType MemTy = AtomicTy;
- if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
- MemTy = AT->getValueType();
- llvm::Value *IsWeak = nullptr, *OrderFail = nullptr;
-
- Address Val1 = Address::invalid();
- Address Val2 = Address::invalid();
- Address Dest = Address::invalid();
- Address Ptr = EmitPointerWithAlignment(E->getPtr());
-
- if (E->getOp() == AtomicExpr::AO__c11_atomic_init ||
- E->getOp() == AtomicExpr::AO__opencl_atomic_init) {
- LValue lvalue = MakeAddrLValue(Ptr, AtomicTy);
- EmitAtomicInit(E->getVal1(), lvalue);
- return RValue::get(nullptr);
- }
-
- CharUnits sizeChars, alignChars;
- std::tie(sizeChars, alignChars) = getContext().getTypeInfoInChars(AtomicTy);
- uint64_t Size = sizeChars.getQuantity();
- unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth();
-
- bool Oversized = getContext().toBits(sizeChars) > MaxInlineWidthInBits;
- bool Misaligned = (Ptr.getAlignment() % sizeChars) != 0;
- bool UseLibcall = Misaligned | Oversized;
-
- if (UseLibcall) {
- CGM.getDiags().Report(E->getBeginLoc(), diag::warn_atomic_op_misaligned)
- << !Oversized;
- }
-
- llvm::Value *Order = EmitScalarExpr(E->getOrder());
- llvm::Value *Scope =
- E->getScopeModel() ? EmitScalarExpr(E->getScope()) : nullptr;
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- case AtomicExpr::AO__opencl_atomic_init:
- llvm_unreachable("Already handled above with EmitAtomicInit!");
-
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__opencl_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- break;
-
- case AtomicExpr::AO__atomic_load:
- Dest = EmitPointerWithAlignment(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_store:
- Val1 = EmitPointerWithAlignment(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_exchange:
- Val1 = EmitPointerWithAlignment(E->getVal1());
- Dest = EmitPointerWithAlignment(E->getVal2());
- break;
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- case AtomicExpr::AO__atomic_compare_exchange:
- Val1 = EmitPointerWithAlignment(E->getVal1());
- if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
- Val2 = EmitPointerWithAlignment(E->getVal2());
- else
- Val2 = EmitValToTemp(*this, E->getVal2());
- OrderFail = EmitScalarExpr(E->getOrderFail());
- if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
- E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
- IsWeak = EmitScalarExpr(E->getWeak());
- break;
-
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- case AtomicExpr::AO__opencl_atomic_fetch_add:
- case AtomicExpr::AO__opencl_atomic_fetch_sub:
- if (MemTy->isPointerType()) {
- // For pointer arithmetic, we're required to do a bit of math:
- // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
- // ... but only for the C11 builtins. The GNU builtins expect the
- // user to multiply by sizeof(T).
- QualType Val1Ty = E->getVal1()->getType();
- llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
- CharUnits PointeeIncAmt =
- getContext().getTypeSizeInChars(MemTy->getPointeeType());
- Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
- auto Temp = CreateMemTemp(Val1Ty, ".atomictmp");
- Val1 = Temp;
- EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Temp, Val1Ty));
- break;
- }
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_sub:
- case AtomicExpr::AO__atomic_add_fetch:
- case AtomicExpr::AO__atomic_sub_fetch:
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__opencl_atomic_store:
- case AtomicExpr::AO__opencl_atomic_exchange:
- case AtomicExpr::AO__atomic_store_n:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__opencl_atomic_fetch_and:
- case AtomicExpr::AO__opencl_atomic_fetch_or:
- case AtomicExpr::AO__opencl_atomic_fetch_xor:
- case AtomicExpr::AO__opencl_atomic_fetch_min:
- case AtomicExpr::AO__opencl_atomic_fetch_max:
- case AtomicExpr::AO__atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_nand:
- case AtomicExpr::AO__atomic_and_fetch:
- case AtomicExpr::AO__atomic_or_fetch:
- case AtomicExpr::AO__atomic_xor_fetch:
- case AtomicExpr::AO__atomic_nand_fetch:
- case AtomicExpr::AO__atomic_fetch_min:
- case AtomicExpr::AO__atomic_fetch_max:
- Val1 = EmitValToTemp(*this, E->getVal1());
- break;
- }
-
- QualType RValTy = E->getType().getUnqualifiedType();
-
- // The inlined atomics only function on iN types, where N is a power of 2. We
- // need to make sure (via temporaries if necessary) that all incoming values
- // are compatible.
- LValue AtomicVal = MakeAddrLValue(Ptr, AtomicTy);
- AtomicInfo Atomics(*this, AtomicVal);
-
- Ptr = Atomics.emitCastToAtomicIntPointer(Ptr);
- if (Val1.isValid()) Val1 = Atomics.convertToAtomicIntPointer(Val1);
- if (Val2.isValid()) Val2 = Atomics.convertToAtomicIntPointer(Val2);
- if (Dest.isValid())
- Dest = Atomics.emitCastToAtomicIntPointer(Dest);
- else if (E->isCmpXChg())
- Dest = CreateMemTemp(RValTy, "cmpxchg.bool");
- else if (!RValTy->isVoidType())
- Dest = Atomics.emitCastToAtomicIntPointer(Atomics.CreateTempAlloca());
-
- // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
- if (UseLibcall) {
- bool UseOptimizedLibcall = false;
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- case AtomicExpr::AO__opencl_atomic_init:
- llvm_unreachable("Already handled above with EmitAtomicInit!");
-
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__opencl_atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_add:
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__opencl_atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_and:
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__opencl_atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_nand:
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- case AtomicExpr::AO__opencl_atomic_fetch_sub:
- case AtomicExpr::AO__atomic_fetch_sub:
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__opencl_atomic_fetch_xor:
- case AtomicExpr::AO__opencl_atomic_fetch_min:
- case AtomicExpr::AO__opencl_atomic_fetch_max:
- case AtomicExpr::AO__atomic_fetch_xor:
- case AtomicExpr::AO__atomic_add_fetch:
- case AtomicExpr::AO__atomic_and_fetch:
- case AtomicExpr::AO__atomic_nand_fetch:
- case AtomicExpr::AO__atomic_or_fetch:
- case AtomicExpr::AO__atomic_sub_fetch:
- case AtomicExpr::AO__atomic_xor_fetch:
- case AtomicExpr::AO__atomic_fetch_min:
- case AtomicExpr::AO__atomic_fetch_max:
- // For these, only library calls for certain sizes exist.
- UseOptimizedLibcall = true;
- break;
-
- case AtomicExpr::AO__atomic_load:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_exchange:
- case AtomicExpr::AO__atomic_compare_exchange:
- // Use the generic version if we don't know that the operand will be
- // suitably aligned for the optimized version.
- if (Misaligned)
- break;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__opencl_atomic_load:
- case AtomicExpr::AO__opencl_atomic_store:
- case AtomicExpr::AO__opencl_atomic_exchange:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
- case AtomicExpr::AO__atomic_load_n:
- case AtomicExpr::AO__atomic_store_n:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- // Only use optimized library calls for sizes for which they exist.
- // FIXME: Size == 16 optimized library functions exist too.
- if (Size == 1 || Size == 2 || Size == 4 || Size == 8)
- UseOptimizedLibcall = true;
- break;
- }
-
- CallArgList Args;
- if (!UseOptimizedLibcall) {
- // For non-optimized library calls, the size is the first parameter
- Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
- getContext().getSizeType());
- }
- // Atomic address is the first or second parameter
- // The OpenCL atomic library functions only accept pointer arguments to
- // generic address space.
- auto CastToGenericAddrSpace = [&](llvm::Value *V, QualType PT) {
- if (!E->isOpenCL())
- return V;
- auto AS = PT->getAs<PointerType>()->getPointeeType().getAddressSpace();
- if (AS == LangAS::opencl_generic)
- return V;
- auto DestAS = getContext().getTargetAddressSpace(LangAS::opencl_generic);
- auto T = V->getType();
- auto *DestType = T->getPointerElementType()->getPointerTo(DestAS);
-
- return getTargetHooks().performAddrSpaceCast(
- *this, V, AS, LangAS::opencl_generic, DestType, false);
- };
-
- Args.add(RValue::get(CastToGenericAddrSpace(
- EmitCastToVoidPtr(Ptr.getPointer()), E->getPtr()->getType())),
- getContext().VoidPtrTy);
-
- std::string LibCallName;
- QualType LoweredMemTy =
- MemTy->isPointerType() ? getContext().getIntPtrType() : MemTy;
- QualType RetTy;
- bool HaveRetTy = false;
- llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- case AtomicExpr::AO__opencl_atomic_init:
- llvm_unreachable("Already handled!");
-
- // There is only one libcall for compare an exchange, because there is no
- // optimisation benefit possible from a libcall version of a weak compare
- // and exchange.
- // bool __atomic_compare_exchange(size_t size, void *mem, void *expected,
- // void *desired, int success, int failure)
- // bool __atomic_compare_exchange_N(T *mem, T *expected, T desired,
- // int success, int failure)
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
- case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
- case AtomicExpr::AO__atomic_compare_exchange:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- LibCallName = "__atomic_compare_exchange";
- RetTy = getContext().BoolTy;
- HaveRetTy = true;
- Args.add(
- RValue::get(CastToGenericAddrSpace(
- EmitCastToVoidPtr(Val1.getPointer()), E->getVal1()->getType())),
- getContext().VoidPtrTy);
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val2.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- Args.add(RValue::get(Order), getContext().IntTy);
- Order = OrderFail;
- break;
- // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
- // int order)
- // T __atomic_exchange_N(T *mem, T val, int order)
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__opencl_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- LibCallName = "__atomic_exchange";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- // void __atomic_store(size_t size, void *mem, void *val, int order)
- // void __atomic_store_N(T *mem, T val, int order)
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__opencl_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n:
- LibCallName = "__atomic_store";
- RetTy = getContext().VoidTy;
- HaveRetTy = true;
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- // void __atomic_load(size_t size, void *mem, void *return, int order)
- // T __atomic_load_N(T *mem, int order)
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__opencl_atomic_load:
- case AtomicExpr::AO__atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- LibCallName = "__atomic_load";
- break;
- // T __atomic_add_fetch_N(T *mem, T val, int order)
- // T __atomic_fetch_add_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_add_fetch:
- PostOp = llvm::Instruction::Add;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__opencl_atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_add:
- LibCallName = "__atomic_fetch_add";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- LoweredMemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_and_fetch_N(T *mem, T val, int order)
- // T __atomic_fetch_and_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_and_fetch:
- PostOp = llvm::Instruction::And;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__opencl_atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_and:
- LibCallName = "__atomic_fetch_and";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_or_fetch_N(T *mem, T val, int order)
- // T __atomic_fetch_or_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_or_fetch:
- PostOp = llvm::Instruction::Or;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__opencl_atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_or:
- LibCallName = "__atomic_fetch_or";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_sub_fetch_N(T *mem, T val, int order)
- // T __atomic_fetch_sub_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_sub_fetch:
- PostOp = llvm::Instruction::Sub;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- case AtomicExpr::AO__opencl_atomic_fetch_sub:
- case AtomicExpr::AO__atomic_fetch_sub:
- LibCallName = "__atomic_fetch_sub";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- LoweredMemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_xor_fetch_N(T *mem, T val, int order)
- // T __atomic_fetch_xor_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_xor_fetch:
- PostOp = llvm::Instruction::Xor;
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__opencl_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_xor:
- LibCallName = "__atomic_fetch_xor";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- case AtomicExpr::AO__atomic_fetch_min:
- case AtomicExpr::AO__opencl_atomic_fetch_min:
- LibCallName = E->getValueType()->isSignedIntegerType()
- ? "__atomic_fetch_min"
- : "__atomic_fetch_umin";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- LoweredMemTy, E->getExprLoc(), sizeChars);
- break;
- case AtomicExpr::AO__atomic_fetch_max:
- case AtomicExpr::AO__opencl_atomic_fetch_max:
- LibCallName = E->getValueType()->isSignedIntegerType()
- ? "__atomic_fetch_max"
- : "__atomic_fetch_umax";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- LoweredMemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_nand_fetch_N(T *mem, T val, int order)
- // T __atomic_fetch_nand_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_nand_fetch:
- PostOp = llvm::Instruction::And; // the NOT is special cased below
- LLVM_FALLTHROUGH;
- case AtomicExpr::AO__atomic_fetch_nand:
- LibCallName = "__atomic_fetch_nand";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- }
-
- if (E->isOpenCL()) {
- LibCallName = std::string("__opencl") +
- StringRef(LibCallName).drop_front(1).str();
-
- }
- // Optimized functions have the size in their name.
- if (UseOptimizedLibcall)
- LibCallName += "_" + llvm::utostr(Size);
- // By default, assume we return a value of the atomic type.
- if (!HaveRetTy) {
- if (UseOptimizedLibcall) {
- // Value is returned directly.
- // The function returns an appropriately sized integer type.
- RetTy = getContext().getIntTypeForBitwidth(
- getContext().toBits(sizeChars), /*Signed=*/false);
- } else {
- // Value is returned through parameter before the order.
- RetTy = getContext().VoidTy;
- Args.add(RValue::get(EmitCastToVoidPtr(Dest.getPointer())),
- getContext().VoidPtrTy);
- }
- }
- // order is always the last parameter
- Args.add(RValue::get(Order),
- getContext().IntTy);
- if (E->isOpenCL())
- Args.add(RValue::get(Scope), getContext().IntTy);
-
- // PostOp is only needed for the atomic_*_fetch operations, and
- // thus is only needed for and implemented in the
- // UseOptimizedLibcall codepath.
- assert(UseOptimizedLibcall || !PostOp);
-
- RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
- // The value is returned directly from the libcall.
- if (E->isCmpXChg())
- return Res;
-
- // The value is returned directly for optimized libcalls but the expr
- // provided an out-param.
- if (UseOptimizedLibcall && Res.getScalarVal()) {
- llvm::Value *ResVal = Res.getScalarVal();
- if (PostOp) {
- llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal();
- ResVal = Builder.CreateBinOp(PostOp, ResVal, LoadVal1);
- }
- if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
- ResVal = Builder.CreateNot(ResVal);
-
- Builder.CreateStore(
- ResVal,
- Builder.CreateBitCast(Dest, ResVal->getType()->getPointerTo()));
- }
-
- if (RValTy->isVoidType())
- return RValue::get(nullptr);
-
- return convertTempToRValue(
- Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo()),
- RValTy, E->getExprLoc());
- }
-
- bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
- E->getOp() == AtomicExpr::AO__opencl_atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store_n;
- bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
- E->getOp() == AtomicExpr::AO__opencl_atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load_n;
-
- if (isa<llvm::ConstantInt>(Order)) {
- auto ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- // We should not ever get to a case where the ordering isn't a valid C ABI
- // value, but it's hard to enforce that in general.
- if (llvm::isValidAtomicOrderingCABI(ord))
- switch ((llvm::AtomicOrderingCABI)ord) {
- case llvm::AtomicOrderingCABI::relaxed:
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Monotonic, Scope);
- break;
- case llvm::AtomicOrderingCABI::consume:
- case llvm::AtomicOrderingCABI::acquire:
- if (IsStore)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Acquire, Scope);
- break;
- case llvm::AtomicOrderingCABI::release:
- if (IsLoad)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Release, Scope);
- break;
- case llvm::AtomicOrderingCABI::acq_rel:
- if (IsLoad || IsStore)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::AcquireRelease, Scope);
- break;
- case llvm::AtomicOrderingCABI::seq_cst:
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::SequentiallyConsistent, Scope);
- break;
- }
- if (RValTy->isVoidType())
- return RValue::get(nullptr);
-
- return convertTempToRValue(
- Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo(
- Dest.getAddressSpace())),
- RValTy, E->getExprLoc());
- }
-
- // Long case, when Order isn't obviously constant.
-
- // Create all the relevant BB's
- llvm::BasicBlock *MonotonicBB = nullptr, *AcquireBB = nullptr,
- *ReleaseBB = nullptr, *AcqRelBB = nullptr,
- *SeqCstBB = nullptr;
- MonotonicBB = createBasicBlock("monotonic", CurFn);
- if (!IsStore)
- AcquireBB = createBasicBlock("acquire", CurFn);
- if (!IsLoad)
- ReleaseBB = createBasicBlock("release", CurFn);
- if (!IsLoad && !IsStore)
- AcqRelBB = createBasicBlock("acqrel", CurFn);
- SeqCstBB = createBasicBlock("seqcst", CurFn);
- llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
-
- // Create the switch for the split
- // MonotonicBB is arbitrarily chosen as the default case; in practice, this
- // doesn't matter unless someone is crazy enough to use something that
- // doesn't fold to a constant for the ordering.
- Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
- llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
-
- // Emit all the different atomics
- Builder.SetInsertPoint(MonotonicBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Monotonic, Scope);
- Builder.CreateBr(ContBB);
- if (!IsStore) {
- Builder.SetInsertPoint(AcquireBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Acquire, Scope);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
- AcquireBB);
- SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acquire),
- AcquireBB);
- }
- if (!IsLoad) {
- Builder.SetInsertPoint(ReleaseBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Release, Scope);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::release),
- ReleaseBB);
- }
- if (!IsLoad && !IsStore) {
- Builder.SetInsertPoint(AcqRelBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::AcquireRelease, Scope);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acq_rel),
- AcqRelBB);
- }
- Builder.SetInsertPoint(SeqCstBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::SequentiallyConsistent, Scope);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
- SeqCstBB);
-
- // Cleanup and return
- Builder.SetInsertPoint(ContBB);
- if (RValTy->isVoidType())
- return RValue::get(nullptr);
-
- assert(Atomics.getValueSizeInBits() <= Atomics.getAtomicSizeInBits());
- return convertTempToRValue(
- Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo(
- Dest.getAddressSpace())),
- RValTy, E->getExprLoc());
-}
-
-Address AtomicInfo::emitCastToAtomicIntPointer(Address addr) const {
- unsigned addrspace =
- cast<llvm::PointerType>(addr.getPointer()->getType())->getAddressSpace();
- llvm::IntegerType *ty =
- llvm::IntegerType::get(CGF.getLLVMContext(), AtomicSizeInBits);
- return CGF.Builder.CreateBitCast(addr, ty->getPointerTo(addrspace));
-}
-
-Address AtomicInfo::convertToAtomicIntPointer(Address Addr) const {
- llvm::Type *Ty = Addr.getElementType();
- uint64_t SourceSizeInBits = CGF.CGM.getDataLayout().getTypeSizeInBits(Ty);
- if (SourceSizeInBits != AtomicSizeInBits) {
- Address Tmp = CreateTempAlloca();
- CGF.Builder.CreateMemCpy(Tmp, Addr,
- std::min(AtomicSizeInBits, SourceSizeInBits) / 8);
- Addr = Tmp;
- }
-
- return emitCastToAtomicIntPointer(Addr);
-}
-
-RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
- AggValueSlot resultSlot,
- SourceLocation loc,
- bool asValue) const {
- if (LVal.isSimple()) {
- if (EvaluationKind == TEK_Aggregate)
- return resultSlot.asRValue();
-
- // Drill into the padding structure if we have one.
- if (hasPadding())
- addr = CGF.Builder.CreateStructGEP(addr, 0, CharUnits());
-
- // Otherwise, just convert the temporary to an r-value using the
- // normal conversion routine.
- return CGF.convertTempToRValue(addr, getValueType(), loc);
- }
- if (!asValue)
- // Get RValue from temp memory as atomic for non-simple lvalues
- return RValue::get(CGF.Builder.CreateLoad(addr));
- if (LVal.isBitField())
- return CGF.EmitLoadOfBitfieldLValue(
- LValue::MakeBitfield(addr, LVal.getBitFieldInfo(), LVal.getType(),
- LVal.getBaseInfo(), TBAAAccessInfo()), loc);
- if (LVal.isVectorElt())
- return CGF.EmitLoadOfLValue(
- LValue::MakeVectorElt(addr, LVal.getVectorIdx(), LVal.getType(),
- LVal.getBaseInfo(), TBAAAccessInfo()), loc);
- assert(LVal.isExtVectorElt());
- return CGF.EmitLoadOfExtVectorElementLValue(LValue::MakeExtVectorElt(
- addr, LVal.getExtVectorElts(), LVal.getType(),
- LVal.getBaseInfo(), TBAAAccessInfo()));
-}
-
-RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
- AggValueSlot ResultSlot,
- SourceLocation Loc,
- bool AsValue) const {
- // Try not to in some easy cases.
- assert(IntVal->getType()->isIntegerTy() && "Expected integer value");
- if (getEvaluationKind() == TEK_Scalar &&
- (((!LVal.isBitField() ||
- LVal.getBitFieldInfo().Size == ValueSizeInBits) &&
- !hasPadding()) ||
- !AsValue)) {
- auto *ValTy = AsValue
- ? CGF.ConvertTypeForMem(ValueTy)
- : getAtomicAddress().getType()->getPointerElementType();
- if (ValTy->isIntegerTy()) {
- assert(IntVal->getType() == ValTy && "Different integer types.");
- return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy));
- } else if (ValTy->isPointerTy())
- return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy));
- else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy))
- return RValue::get(CGF.Builder.CreateBitCast(IntVal, ValTy));
- }
-
- // Create a temporary. This needs to be big enough to hold the
- // atomic integer.
- Address Temp = Address::invalid();
- bool TempIsVolatile = false;
- if (AsValue && getEvaluationKind() == TEK_Aggregate) {
- assert(!ResultSlot.isIgnored());
- Temp = ResultSlot.getAddress();
- TempIsVolatile = ResultSlot.isVolatile();
- } else {
- Temp = CreateTempAlloca();
- }
-
- // Slam the integer into the temporary.
- Address CastTemp = emitCastToAtomicIntPointer(Temp);
- CGF.Builder.CreateStore(IntVal, CastTemp)
- ->setVolatile(TempIsVolatile);
-
- return convertAtomicTempToRValue(Temp, ResultSlot, Loc, AsValue);
-}
-
-void AtomicInfo::EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
- llvm::AtomicOrdering AO, bool) {
- // void __atomic_load(size_t size, void *mem, void *return, int order);
- CallArgList Args;
- Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
- Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicPointer())),
- CGF.getContext().VoidPtrTy);
- Args.add(RValue::get(CGF.EmitCastToVoidPtr(AddForLoaded)),
- CGF.getContext().VoidPtrTy);
- Args.add(
- RValue::get(llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(AO))),
- CGF.getContext().IntTy);
- emitAtomicLibcall(CGF, "__atomic_load", CGF.getContext().VoidTy, Args);
-}
-
-llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO,
- bool IsVolatile) {
- // Okay, we're doing this natively.
- Address Addr = getAtomicAddressAsAtomicIntPointer();
- llvm::LoadInst *Load = CGF.Builder.CreateLoad(Addr, "atomic-load");
- Load->setAtomic(AO);
-
- // Other decoration.
- if (IsVolatile)
- Load->setVolatile(true);
- CGF.CGM.DecorateInstructionWithTBAA(Load, LVal.getTBAAInfo());
- return Load;
-}
-
-/// An LValue is a candidate for having its loads and stores be made atomic if
-/// we are operating under /volatile:ms *and* the LValue itself is volatile and
-/// performing such an operation can be performed without a libcall.
-bool CodeGenFunction::LValueIsSuitableForInlineAtomic(LValue LV) {
- if (!CGM.getCodeGenOpts().MSVolatile) return false;
- AtomicInfo AI(*this, LV);
- bool IsVolatile = LV.isVolatile() || hasVolatileMember(LV.getType());
- // An atomic is inline if we don't need to use a libcall.
- bool AtomicIsInline = !AI.shouldUseLibcall();
- // MSVC doesn't seem to do this for types wider than a pointer.
- if (getContext().getTypeSize(LV.getType()) >
- getContext().getTypeSize(getContext().getIntPtrType()))
- return false;
- return IsVolatile && AtomicIsInline;
-}
-
-RValue CodeGenFunction::EmitAtomicLoad(LValue LV, SourceLocation SL,
- AggValueSlot Slot) {
- llvm::AtomicOrdering AO;
- bool IsVolatile = LV.isVolatileQualified();
- if (LV.getType()->isAtomicType()) {
- AO = llvm::AtomicOrdering::SequentiallyConsistent;
- } else {
- AO = llvm::AtomicOrdering::Acquire;
- IsVolatile = true;
- }
- return EmitAtomicLoad(LV, SL, AO, IsVolatile, Slot);
-}
-
-RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
- bool AsValue, llvm::AtomicOrdering AO,
- bool IsVolatile) {
- // Check whether we should use a library call.
- if (shouldUseLibcall()) {
- Address TempAddr = Address::invalid();
- if (LVal.isSimple() && !ResultSlot.isIgnored()) {
- assert(getEvaluationKind() == TEK_Aggregate);
- TempAddr = ResultSlot.getAddress();
- } else
- TempAddr = CreateTempAlloca();
-
- EmitAtomicLoadLibcall(TempAddr.getPointer(), AO, IsVolatile);
-
- // Okay, turn that back into the original value or whole atomic (for
- // non-simple lvalues) type.
- return convertAtomicTempToRValue(TempAddr, ResultSlot, Loc, AsValue);
- }
-
- // Okay, we're doing this natively.
- auto *Load = EmitAtomicLoadOp(AO, IsVolatile);
-
- // If we're ignoring an aggregate return, don't do anything.
- if (getEvaluationKind() == TEK_Aggregate && ResultSlot.isIgnored())
- return RValue::getAggregate(Address::invalid(), false);
-
- // Okay, turn that back into the original value or atomic (for non-simple
- // lvalues) type.
- return ConvertIntToValueOrAtomic(Load, ResultSlot, Loc, AsValue);
-}
-
-/// Emit a load from an l-value of atomic type. Note that the r-value
-/// we produce is an r-value of the atomic *value* type.
-RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
- llvm::AtomicOrdering AO, bool IsVolatile,
- AggValueSlot resultSlot) {
- AtomicInfo Atomics(*this, src);
- return Atomics.EmitAtomicLoad(resultSlot, loc, /*AsValue=*/true, AO,
- IsVolatile);
-}
-
-/// Copy an r-value into memory as part of storing to an atomic type.
-/// This needs to create a bit-pattern suitable for atomic operations.
-void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
- assert(LVal.isSimple());
- // If we have an r-value, the rvalue should be of the atomic type,
- // which means that the caller is responsible for having zeroed
- // any padding. Just do an aggregate copy of that type.
- if (rvalue.isAggregate()) {
- LValue Dest = CGF.MakeAddrLValue(getAtomicAddress(), getAtomicType());
- LValue Src = CGF.MakeAddrLValue(rvalue.getAggregateAddress(),
- getAtomicType());
- bool IsVolatile = rvalue.isVolatileQualified() ||
- LVal.isVolatileQualified();
- CGF.EmitAggregateCopy(Dest, Src, getAtomicType(),
- AggValueSlot::DoesNotOverlap, IsVolatile);
- return;
- }
-
- // Okay, otherwise we're copying stuff.
-
- // Zero out the buffer if necessary.
- emitMemSetZeroIfNecessary();
-
- // Drill past the padding if present.
- LValue TempLVal = projectValue();
-
- // Okay, store the rvalue in.
- if (rvalue.isScalar()) {
- CGF.EmitStoreOfScalar(rvalue.getScalarVal(), TempLVal, /*init*/ true);
- } else {
- CGF.EmitStoreOfComplex(rvalue.getComplexVal(), TempLVal, /*init*/ true);
- }
-}
-
-
-/// Materialize an r-value into memory for the purposes of storing it
-/// to an atomic type.
-Address AtomicInfo::materializeRValue(RValue rvalue) const {
- // Aggregate r-values are already in memory, and EmitAtomicStore
- // requires them to be values of the atomic type.
- if (rvalue.isAggregate())
- return rvalue.getAggregateAddress();
-
- // Otherwise, make a temporary and materialize into it.
- LValue TempLV = CGF.MakeAddrLValue(CreateTempAlloca(), getAtomicType());
- AtomicInfo Atomics(CGF, TempLV);
- Atomics.emitCopyIntoMemory(rvalue);
- return TempLV.getAddress();
-}
-
-llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
- // If we've got a scalar value of the right size, try to avoid going
- // through memory.
- if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple())) {
- llvm::Value *Value = RVal.getScalarVal();
- if (isa<llvm::IntegerType>(Value->getType()))
- return CGF.EmitToMemory(Value, ValueTy);
- else {
- llvm::IntegerType *InputIntTy = llvm::IntegerType::get(
- CGF.getLLVMContext(),
- LVal.isSimple() ? getValueSizeInBits() : getAtomicSizeInBits());
- if (isa<llvm::PointerType>(Value->getType()))
- return CGF.Builder.CreatePtrToInt(Value, InputIntTy);
- else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy))
- return CGF.Builder.CreateBitCast(Value, InputIntTy);
- }
- }
- // Otherwise, we need to go through memory.
- // Put the r-value in memory.
- Address Addr = materializeRValue(RVal);
-
- // Cast the temporary to the atomic int type and pull a value out.
- Addr = emitCastToAtomicIntPointer(Addr);
- return CGF.Builder.CreateLoad(Addr);
-}
-
-std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
- llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
- llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak) {
- // Do the atomic store.
- Address Addr = getAtomicAddressAsAtomicIntPointer();
- auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr.getPointer(),
- ExpectedVal, DesiredVal,
- Success, Failure);
- // Other decoration.
- Inst->setVolatile(LVal.isVolatileQualified());
- Inst->setWeak(IsWeak);
-
- // Okay, turn that back into the original value type.
- auto *PreviousVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/0);
- auto *SuccessFailureVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/1);
- return std::make_pair(PreviousVal, SuccessFailureVal);
-}
-
-llvm::Value *
-AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr,
- llvm::Value *DesiredAddr,
- llvm::AtomicOrdering Success,
- llvm::AtomicOrdering Failure) {
- // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
- // void *desired, int success, int failure);
- CallArgList Args;
- Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
- Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicPointer())),
- CGF.getContext().VoidPtrTy);
- Args.add(RValue::get(CGF.EmitCastToVoidPtr(ExpectedAddr)),
- CGF.getContext().VoidPtrTy);
- Args.add(RValue::get(CGF.EmitCastToVoidPtr(DesiredAddr)),
- CGF.getContext().VoidPtrTy);
- Args.add(RValue::get(
- llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(Success))),
- CGF.getContext().IntTy);
- Args.add(RValue::get(
- llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(Failure))),
- CGF.getContext().IntTy);
- auto SuccessFailureRVal = emitAtomicLibcall(CGF, "__atomic_compare_exchange",
- CGF.getContext().BoolTy, Args);
-
- return SuccessFailureRVal.getScalarVal();
-}
-
-std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
- RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
- llvm::AtomicOrdering Failure, bool IsWeak) {
- if (isStrongerThan(Failure, Success))
- // Don't assert on undefined behavior "failure argument shall be no stronger
- // than the success argument".
- Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(Success);
-
- // Check whether we should use a library call.
- if (shouldUseLibcall()) {
- // Produce a source address.
- Address ExpectedAddr = materializeRValue(Expected);
- Address DesiredAddr = materializeRValue(Desired);
- auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(),
- DesiredAddr.getPointer(),
- Success, Failure);
- return std::make_pair(
- convertAtomicTempToRValue(ExpectedAddr, AggValueSlot::ignored(),
- SourceLocation(), /*AsValue=*/false),
- Res);
- }
-
- // If we've got a scalar value of the right size, try to avoid going
- // through memory.
- auto *ExpectedVal = convertRValueToInt(Expected);
- auto *DesiredVal = convertRValueToInt(Desired);
- auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
- Failure, IsWeak);
- return std::make_pair(
- ConvertIntToValueOrAtomic(Res.first, AggValueSlot::ignored(),
- SourceLocation(), /*AsValue=*/false),
- Res.second);
-}
-
-static void
-EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, RValue OldRVal,
- const llvm::function_ref<RValue(RValue)> &UpdateOp,
- Address DesiredAddr) {
- RValue UpRVal;
- LValue AtomicLVal = Atomics.getAtomicLValue();
- LValue DesiredLVal;
- if (AtomicLVal.isSimple()) {
- UpRVal = OldRVal;
- DesiredLVal = CGF.MakeAddrLValue(DesiredAddr, AtomicLVal.getType());
- } else {
- // Build new lvalue for temp address
- Address Ptr = Atomics.materializeRValue(OldRVal);
- LValue UpdateLVal;
- if (AtomicLVal.isBitField()) {
- UpdateLVal =
- LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(),
- AtomicLVal.getType(),
- AtomicLVal.getBaseInfo(),
- AtomicLVal.getTBAAInfo());
- DesiredLVal =
- LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
- AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
- AtomicLVal.getTBAAInfo());
- } else if (AtomicLVal.isVectorElt()) {
- UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(),
- AtomicLVal.getType(),
- AtomicLVal.getBaseInfo(),
- AtomicLVal.getTBAAInfo());
- DesiredLVal = LValue::MakeVectorElt(
- DesiredAddr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(),
- AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
- } else {
- assert(AtomicLVal.isExtVectorElt());
- UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(),
- AtomicLVal.getType(),
- AtomicLVal.getBaseInfo(),
- AtomicLVal.getTBAAInfo());
- DesiredLVal = LValue::MakeExtVectorElt(
- DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
- AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
- }
- UpRVal = CGF.EmitLoadOfLValue(UpdateLVal, SourceLocation());
- }
- // Store new value in the corresponding memory area
- RValue NewRVal = UpdateOp(UpRVal);
- if (NewRVal.isScalar()) {
- CGF.EmitStoreThroughLValue(NewRVal, DesiredLVal);
- } else {
- assert(NewRVal.isComplex());
- CGF.EmitStoreOfComplex(NewRVal.getComplexVal(), DesiredLVal,
- /*isInit=*/false);
- }
-}
-
-void AtomicInfo::EmitAtomicUpdateLibcall(
- llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
- bool IsVolatile) {
- auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
-
- Address ExpectedAddr = CreateTempAlloca();
-
- EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile);
- auto *ContBB = CGF.createBasicBlock("atomic_cont");
- auto *ExitBB = CGF.createBasicBlock("atomic_exit");
- CGF.EmitBlock(ContBB);
- Address DesiredAddr = CreateTempAlloca();
- if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
- requiresMemSetZero(getAtomicAddress().getElementType())) {
- auto *OldVal = CGF.Builder.CreateLoad(ExpectedAddr);
- CGF.Builder.CreateStore(OldVal, DesiredAddr);
- }
- auto OldRVal = convertAtomicTempToRValue(ExpectedAddr,
- AggValueSlot::ignored(),
- SourceLocation(), /*AsValue=*/false);
- EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, DesiredAddr);
- auto *Res =
- EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(),
- DesiredAddr.getPointer(),
- AO, Failure);
- CGF.Builder.CreateCondBr(Res, ExitBB, ContBB);
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
-}
-
-void AtomicInfo::EmitAtomicUpdateOp(
- llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
- bool IsVolatile) {
- auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
-
- // Do the atomic load.
- auto *OldVal = EmitAtomicLoadOp(AO, IsVolatile);
- // For non-simple lvalues perform compare-and-swap procedure.
- auto *ContBB = CGF.createBasicBlock("atomic_cont");
- auto *ExitBB = CGF.createBasicBlock("atomic_exit");
- auto *CurBB = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(ContBB);
- llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(),
- /*NumReservedValues=*/2);
- PHI->addIncoming(OldVal, CurBB);
- Address NewAtomicAddr = CreateTempAlloca();
- Address NewAtomicIntAddr = emitCastToAtomicIntPointer(NewAtomicAddr);
- if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
- requiresMemSetZero(getAtomicAddress().getElementType())) {
- CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
- }
- auto OldRVal = ConvertIntToValueOrAtomic(PHI, AggValueSlot::ignored(),
- SourceLocation(), /*AsValue=*/false);
- EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, NewAtomicAddr);
- auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr);
- // Try to write new value using cmpxchg operation
- auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure);
- PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock());
- CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB);
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
-}
-
-static void EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics,
- RValue UpdateRVal, Address DesiredAddr) {
- LValue AtomicLVal = Atomics.getAtomicLValue();
- LValue DesiredLVal;
- // Build new lvalue for temp address
- if (AtomicLVal.isBitField()) {
- DesiredLVal =
- LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
- AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
- AtomicLVal.getTBAAInfo());
- } else if (AtomicLVal.isVectorElt()) {
- DesiredLVal =
- LValue::MakeVectorElt(DesiredAddr, AtomicLVal.getVectorIdx(),
- AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
- AtomicLVal.getTBAAInfo());
- } else {
- assert(AtomicLVal.isExtVectorElt());
- DesiredLVal = LValue::MakeExtVectorElt(
- DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
- AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
- }
- // Store new value in the corresponding memory area
- assert(UpdateRVal.isScalar());
- CGF.EmitStoreThroughLValue(UpdateRVal, DesiredLVal);
-}
-
-void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,
- RValue UpdateRVal, bool IsVolatile) {
- auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
-
- Address ExpectedAddr = CreateTempAlloca();
-
- EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile);
- auto *ContBB = CGF.createBasicBlock("atomic_cont");
- auto *ExitBB = CGF.createBasicBlock("atomic_exit");
- CGF.EmitBlock(ContBB);
- Address DesiredAddr = CreateTempAlloca();
- if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
- requiresMemSetZero(getAtomicAddress().getElementType())) {
- auto *OldVal = CGF.Builder.CreateLoad(ExpectedAddr);
- CGF.Builder.CreateStore(OldVal, DesiredAddr);
- }
- EmitAtomicUpdateValue(CGF, *this, UpdateRVal, DesiredAddr);
- auto *Res =
- EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(),
- DesiredAddr.getPointer(),
- AO, Failure);
- CGF.Builder.CreateCondBr(Res, ExitBB, ContBB);
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
-}
-
-void AtomicInfo::EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRVal,
- bool IsVolatile) {
- auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
-
- // Do the atomic load.
- auto *OldVal = EmitAtomicLoadOp(AO, IsVolatile);
- // For non-simple lvalues perform compare-and-swap procedure.
- auto *ContBB = CGF.createBasicBlock("atomic_cont");
- auto *ExitBB = CGF.createBasicBlock("atomic_exit");
- auto *CurBB = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(ContBB);
- llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(),
- /*NumReservedValues=*/2);
- PHI->addIncoming(OldVal, CurBB);
- Address NewAtomicAddr = CreateTempAlloca();
- Address NewAtomicIntAddr = emitCastToAtomicIntPointer(NewAtomicAddr);
- if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
- requiresMemSetZero(getAtomicAddress().getElementType())) {
- CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
- }
- EmitAtomicUpdateValue(CGF, *this, UpdateRVal, NewAtomicAddr);
- auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr);
- // Try to write new value using cmpxchg operation
- auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure);
- PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock());
- CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB);
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
-}
-
-void AtomicInfo::EmitAtomicUpdate(
- llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
- bool IsVolatile) {
- if (shouldUseLibcall()) {
- EmitAtomicUpdateLibcall(AO, UpdateOp, IsVolatile);
- } else {
- EmitAtomicUpdateOp(AO, UpdateOp, IsVolatile);
- }
-}
-
-void AtomicInfo::EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal,
- bool IsVolatile) {
- if (shouldUseLibcall()) {
- EmitAtomicUpdateLibcall(AO, UpdateRVal, IsVolatile);
- } else {
- EmitAtomicUpdateOp(AO, UpdateRVal, IsVolatile);
- }
-}
-
-void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue lvalue,
- bool isInit) {
- bool IsVolatile = lvalue.isVolatileQualified();
- llvm::AtomicOrdering AO;
- if (lvalue.getType()->isAtomicType()) {
- AO = llvm::AtomicOrdering::SequentiallyConsistent;
- } else {
- AO = llvm::AtomicOrdering::Release;
- IsVolatile = true;
- }
- return EmitAtomicStore(rvalue, lvalue, AO, IsVolatile, isInit);
-}
-
-/// Emit a store to an l-value of atomic type.
-///
-/// Note that the r-value is expected to be an r-value *of the atomic
-/// type*; this means that for aggregate r-values, it should include
-/// storage for any padding that was necessary.
-void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
- llvm::AtomicOrdering AO, bool IsVolatile,
- bool isInit) {
- // If this is an aggregate r-value, it should agree in type except
- // maybe for address-space qualification.
- assert(!rvalue.isAggregate() ||
- rvalue.getAggregateAddress().getElementType()
- == dest.getAddress().getElementType());
-
- AtomicInfo atomics(*this, dest);
- LValue LVal = atomics.getAtomicLValue();
-
- // If this is an initialization, just put the value there normally.
- if (LVal.isSimple()) {
- if (isInit) {
- atomics.emitCopyIntoMemory(rvalue);
- return;
- }
-
- // Check whether we should use a library call.
- if (atomics.shouldUseLibcall()) {
- // Produce a source address.
- Address srcAddr = atomics.materializeRValue(rvalue);
-
- // void __atomic_store(size_t size, void *mem, void *val, int order)
- CallArgList args;
- args.add(RValue::get(atomics.getAtomicSizeValue()),
- getContext().getSizeType());
- args.add(RValue::get(EmitCastToVoidPtr(atomics.getAtomicPointer())),
- getContext().VoidPtrTy);
- args.add(RValue::get(EmitCastToVoidPtr(srcAddr.getPointer())),
- getContext().VoidPtrTy);
- args.add(
- RValue::get(llvm::ConstantInt::get(IntTy, (int)llvm::toCABI(AO))),
- getContext().IntTy);
- emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
- return;
- }
-
- // Okay, we're doing this natively.
- llvm::Value *intValue = atomics.convertRValueToInt(rvalue);
-
- // Do the atomic store.
- Address addr =
- atomics.emitCastToAtomicIntPointer(atomics.getAtomicAddress());
- intValue = Builder.CreateIntCast(
- intValue, addr.getElementType(), /*isSigned=*/false);
- llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
-
- // Initializations don't need to be atomic.
- if (!isInit)
- store->setAtomic(AO);
-
- // Other decoration.
- if (IsVolatile)
- store->setVolatile(true);
- CGM.DecorateInstructionWithTBAA(store, dest.getTBAAInfo());
- return;
- }
-
- // Emit simple atomic update operation.
- atomics.EmitAtomicUpdate(AO, rvalue, IsVolatile);
-}
-
-/// Emit a compare-and-exchange op for atomic type.
-///
-std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange(
- LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
- llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak,
- AggValueSlot Slot) {
- // If this is an aggregate r-value, it should agree in type except
- // maybe for address-space qualification.
- assert(!Expected.isAggregate() ||
- Expected.getAggregateAddress().getElementType() ==
- Obj.getAddress().getElementType());
- assert(!Desired.isAggregate() ||
- Desired.getAggregateAddress().getElementType() ==
- Obj.getAddress().getElementType());
- AtomicInfo Atomics(*this, Obj);
-
- return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure,
- IsWeak);
-}
-
-void CodeGenFunction::EmitAtomicUpdate(
- LValue LVal, llvm::AtomicOrdering AO,
- const llvm::function_ref<RValue(RValue)> &UpdateOp, bool IsVolatile) {
- AtomicInfo Atomics(*this, LVal);
- Atomics.EmitAtomicUpdate(AO, UpdateOp, IsVolatile);
-}
-
-void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
- AtomicInfo atomics(*this, dest);
-
- switch (atomics.getEvaluationKind()) {
- case TEK_Scalar: {
- llvm::Value *value = EmitScalarExpr(init);
- atomics.emitCopyIntoMemory(RValue::get(value));
- return;
- }
-
- case TEK_Complex: {
- ComplexPairTy value = EmitComplexExpr(init);
- atomics.emitCopyIntoMemory(RValue::getComplex(value));
- return;
- }
-
- case TEK_Aggregate: {
- // Fix up the destination if the initializer isn't an expression
- // of atomic type.
- bool Zeroed = false;
- if (!init->getType()->isAtomicType()) {
- Zeroed = atomics.emitMemSetZeroIfNecessary();
- dest = atomics.projectValue();
- }
-
- // Evaluate the expression directly into the destination.
- AggValueSlot slot = AggValueSlot::forLValue(dest,
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap,
- Zeroed ? AggValueSlot::IsZeroed :
- AggValueSlot::IsNotZeroed);
-
- EmitAggExpr(init, slot);
- return;
- }
- }
- llvm_unreachable("bad evaluation kind");
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp
deleted file mode 100644
index fa3c3ee8610..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp
+++ /dev/null
@@ -1,3036 +0,0 @@
-//===--- CGBlocks.cpp - Emit LLVM Code for declarations ---------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit blocks.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGBlocks.h"
-#include "CGCXXABI.h"
-#include "CGDebugInfo.h"
-#include "CGObjCRuntime.h"
-#include "CGOpenCLRuntime.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "ConstantEmitter.h"
-#include "TargetInfo.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include <algorithm>
-#include <cstdio>
-
-using namespace clang;
-using namespace CodeGen;
-
-CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
- : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
- CapturesNonExternalType(false), LocalAddress(Address::invalid()),
- StructureType(nullptr), Block(block), DominatingIP(nullptr) {
-
- // Skip asm prefix, if any. 'name' is usually taken directly from
- // the mangled name of the enclosing function.
- if (!name.empty() && name[0] == '\01')
- name = name.substr(1);
-}
-
-// Anchor the vtable to this translation unit.
-BlockByrefHelpers::~BlockByrefHelpers() {}
-
-/// Build the given block as a global block.
-static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo,
- llvm::Constant *blockFn);
-
-/// Build the helper function to copy a block.
-static llvm::Constant *buildCopyHelper(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- return CodeGenFunction(CGM).GenerateCopyHelperFunction(blockInfo);
-}
-
-/// Build the helper function to dispose of a block.
-static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo);
-}
-
-namespace {
-
-/// Represents a type of copy/destroy operation that should be performed for an
-/// entity that's captured by a block.
-enum class BlockCaptureEntityKind {
- CXXRecord, // Copy or destroy
- ARCWeak,
- ARCStrong,
- NonTrivialCStruct,
- BlockObject, // Assign or release
- None
-};
-
-/// Represents a captured entity that requires extra operations in order for
-/// this entity to be copied or destroyed correctly.
-struct BlockCaptureManagedEntity {
- BlockCaptureEntityKind CopyKind, DisposeKind;
- BlockFieldFlags CopyFlags, DisposeFlags;
- const BlockDecl::Capture *CI;
- const CGBlockInfo::Capture *Capture;
-
- BlockCaptureManagedEntity(BlockCaptureEntityKind CopyType,
- BlockCaptureEntityKind DisposeType,
- BlockFieldFlags CopyFlags,
- BlockFieldFlags DisposeFlags,
- const BlockDecl::Capture &CI,
- const CGBlockInfo::Capture &Capture)
- : CopyKind(CopyType), DisposeKind(DisposeType), CopyFlags(CopyFlags),
- DisposeFlags(DisposeFlags), CI(&CI), Capture(&Capture) {}
-
- bool operator<(const BlockCaptureManagedEntity &Other) const {
- return Capture->getOffset() < Other.Capture->getOffset();
- }
-};
-
-enum class CaptureStrKind {
- // String for the copy helper.
- CopyHelper,
- // String for the dispose helper.
- DisposeHelper,
- // Merge the strings for the copy helper and dispose helper.
- Merged
-};
-
-} // end anonymous namespace
-
-static void findBlockCapturedManagedEntities(
- const CGBlockInfo &BlockInfo, const LangOptions &LangOpts,
- SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures);
-
-static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E,
- CaptureStrKind StrKind,
- CharUnits BlockAlignment,
- CodeGenModule &CGM);
-
-static std::string getBlockDescriptorName(const CGBlockInfo &BlockInfo,
- CodeGenModule &CGM) {
- std::string Name = "__block_descriptor_";
- Name += llvm::to_string(BlockInfo.BlockSize.getQuantity()) + "_";
-
- if (BlockInfo.needsCopyDisposeHelpers()) {
- if (CGM.getLangOpts().Exceptions)
- Name += "e";
- if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
- Name += "a";
- Name += llvm::to_string(BlockInfo.BlockAlign.getQuantity()) + "_";
-
- SmallVector<BlockCaptureManagedEntity, 4> ManagedCaptures;
- findBlockCapturedManagedEntities(BlockInfo, CGM.getContext().getLangOpts(),
- ManagedCaptures);
-
- for (const BlockCaptureManagedEntity &E : ManagedCaptures) {
- Name += llvm::to_string(E.Capture->getOffset().getQuantity());
-
- if (E.CopyKind == E.DisposeKind) {
- // If CopyKind and DisposeKind are the same, merge the capture
- // information.
- assert(E.CopyKind != BlockCaptureEntityKind::None &&
- "shouldn't see BlockCaptureManagedEntity that is None");
- Name += getBlockCaptureStr(E, CaptureStrKind::Merged,
- BlockInfo.BlockAlign, CGM);
- } else {
- // If CopyKind and DisposeKind are not the same, which can happen when
- // either Kind is None or the captured object is a __strong block,
- // concatenate the copy and dispose strings.
- Name += getBlockCaptureStr(E, CaptureStrKind::CopyHelper,
- BlockInfo.BlockAlign, CGM);
- Name += getBlockCaptureStr(E, CaptureStrKind::DisposeHelper,
- BlockInfo.BlockAlign, CGM);
- }
- }
- Name += "_";
- }
-
- std::string TypeAtEncoding =
- CGM.getContext().getObjCEncodingForBlock(BlockInfo.getBlockExpr());
- /// Replace occurrences of '@' with '\1'. '@' is reserved on ELF platforms as
- /// a separator between symbol name and symbol version.
- std::replace(TypeAtEncoding.begin(), TypeAtEncoding.end(), '@', '\1');
- Name += "e" + llvm::to_string(TypeAtEncoding.size()) + "_" + TypeAtEncoding;
- Name += "l" + CGM.getObjCRuntime().getRCBlockLayoutStr(CGM, BlockInfo);
- return Name;
-}
-
-/// buildBlockDescriptor - Build the block descriptor meta-data for a block.
-/// buildBlockDescriptor is accessed from 5th field of the Block_literal
-/// meta-data and contains stationary information about the block literal.
-/// Its definition will have 4 (or optionally 6) words.
-/// \code
-/// struct Block_descriptor {
-/// unsigned long reserved;
-/// unsigned long size; // size of Block_literal metadata in bytes.
-/// void *copy_func_helper_decl; // optional copy helper.
-/// void *destroy_func_decl; // optional destructor helper.
-/// void *block_method_encoding_address; // @encode for block literal signature.
-/// void *block_layout_info; // encoding of captured block variables.
-/// };
-/// \endcode
-static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- ASTContext &C = CGM.getContext();
-
- llvm::IntegerType *ulong =
- cast<llvm::IntegerType>(CGM.getTypes().ConvertType(C.UnsignedLongTy));
- llvm::PointerType *i8p = nullptr;
- if (CGM.getLangOpts().OpenCL)
- i8p =
- llvm::Type::getInt8PtrTy(
- CGM.getLLVMContext(), C.getTargetAddressSpace(LangAS::opencl_constant));
- else
- i8p = CGM.VoidPtrTy;
-
- std::string descName;
-
- // If an equivalent block descriptor global variable exists, return it.
- if (C.getLangOpts().ObjC &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC) {
- descName = getBlockDescriptorName(blockInfo, CGM);
- if (llvm::GlobalValue *desc = CGM.getModule().getNamedValue(descName))
- return llvm::ConstantExpr::getBitCast(desc,
- CGM.getBlockDescriptorType());
- }
-
- // If there isn't an equivalent block descriptor global variable, create a new
- // one.
- ConstantInitBuilder builder(CGM);
- auto elements = builder.beginStruct();
-
- // reserved
- elements.addInt(ulong, 0);
-
- // Size
- // FIXME: What is the right way to say this doesn't fit? We should give
- // a user diagnostic in that case. Better fix would be to change the
- // API to size_t.
- elements.addInt(ulong, blockInfo.BlockSize.getQuantity());
-
- // Optional copy/dispose helpers.
- bool hasInternalHelper = false;
- if (blockInfo.needsCopyDisposeHelpers()) {
- // copy_func_helper_decl
- llvm::Constant *copyHelper = buildCopyHelper(CGM, blockInfo);
- elements.add(copyHelper);
-
- // destroy_func_decl
- llvm::Constant *disposeHelper = buildDisposeHelper(CGM, blockInfo);
- elements.add(disposeHelper);
-
- if (cast<llvm::Function>(copyHelper->getOperand(0))->hasInternalLinkage() ||
- cast<llvm::Function>(disposeHelper->getOperand(0))
- ->hasInternalLinkage())
- hasInternalHelper = true;
- }
-
- // Signature. Mandatory ObjC-style method descriptor @encode sequence.
- std::string typeAtEncoding =
- CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr());
- elements.add(llvm::ConstantExpr::getBitCast(
- CGM.GetAddrOfConstantCString(typeAtEncoding).getPointer(), i8p));
-
- // GC layout.
- if (C.getLangOpts().ObjC) {
- if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
- elements.add(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
- else
- elements.add(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo));
- }
- else
- elements.addNullPointer(i8p);
-
- unsigned AddrSpace = 0;
- if (C.getLangOpts().OpenCL)
- AddrSpace = C.getTargetAddressSpace(LangAS::opencl_constant);
-
- llvm::GlobalValue::LinkageTypes linkage;
- if (descName.empty()) {
- linkage = llvm::GlobalValue::InternalLinkage;
- descName = "__block_descriptor_tmp";
- } else if (hasInternalHelper) {
- // If either the copy helper or the dispose helper has internal linkage,
- // the block descriptor must have internal linkage too.
- linkage = llvm::GlobalValue::InternalLinkage;
- } else {
- linkage = llvm::GlobalValue::LinkOnceODRLinkage;
- }
-
- llvm::GlobalVariable *global =
- elements.finishAndCreateGlobal(descName, CGM.getPointerAlign(),
- /*constant*/ true, linkage, AddrSpace);
-
- if (linkage == llvm::GlobalValue::LinkOnceODRLinkage) {
- global->setVisibility(llvm::GlobalValue::HiddenVisibility);
- global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- }
-
- return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType());
-}
-
-/*
- Purely notional variadic template describing the layout of a block.
-
- template <class _ResultType, class... _ParamTypes, class... _CaptureTypes>
- struct Block_literal {
- /// Initialized to one of:
- /// extern void *_NSConcreteStackBlock[];
- /// extern void *_NSConcreteGlobalBlock[];
- ///
- /// In theory, we could start one off malloc'ed by setting
- /// BLOCK_NEEDS_FREE, giving it a refcount of 1, and using
- /// this isa:
- /// extern void *_NSConcreteMallocBlock[];
- struct objc_class *isa;
-
- /// These are the flags (with corresponding bit number) that the
- /// compiler is actually supposed to know about.
- /// 23. BLOCK_IS_NOESCAPE - indicates that the block is non-escaping
- /// 25. BLOCK_HAS_COPY_DISPOSE - indicates that the block
- /// descriptor provides copy and dispose helper functions
- /// 26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured
- /// object with a nontrivial destructor or copy constructor
- /// 28. BLOCK_IS_GLOBAL - indicates that the block is allocated
- /// as global memory
- /// 29. BLOCK_USE_STRET - indicates that the block function
- /// uses stret, which objc_msgSend needs to know about
- /// 30. BLOCK_HAS_SIGNATURE - indicates that the block has an
- /// @encoded signature string
- /// And we're not supposed to manipulate these:
- /// 24. BLOCK_NEEDS_FREE - indicates that the block has been moved
- /// to malloc'ed memory
- /// 27. BLOCK_IS_GC - indicates that the block has been moved to
- /// to GC-allocated memory
- /// Additionally, the bottom 16 bits are a reference count which
- /// should be zero on the stack.
- int flags;
-
- /// Reserved; should be zero-initialized.
- int reserved;
-
- /// Function pointer generated from block literal.
- _ResultType (*invoke)(Block_literal *, _ParamTypes...);
-
- /// Block description metadata generated from block literal.
- struct Block_descriptor *block_descriptor;
-
- /// Captured values follow.
- _CapturesTypes captures...;
- };
- */
-
-namespace {
- /// A chunk of data that we actually have to capture in the block.
- struct BlockLayoutChunk {
- CharUnits Alignment;
- CharUnits Size;
- Qualifiers::ObjCLifetime Lifetime;
- const BlockDecl::Capture *Capture; // null for 'this'
- llvm::Type *Type;
- QualType FieldType;
-
- BlockLayoutChunk(CharUnits align, CharUnits size,
- Qualifiers::ObjCLifetime lifetime,
- const BlockDecl::Capture *capture,
- llvm::Type *type, QualType fieldType)
- : Alignment(align), Size(size), Lifetime(lifetime),
- Capture(capture), Type(type), FieldType(fieldType) {}
-
- /// Tell the block info that this chunk has the given field index.
- void setIndex(CGBlockInfo &info, unsigned index, CharUnits offset) {
- if (!Capture) {
- info.CXXThisIndex = index;
- info.CXXThisOffset = offset;
- } else {
- auto C = CGBlockInfo::Capture::makeIndex(index, offset, FieldType);
- info.Captures.insert({Capture->getVariable(), C});
- }
- }
- };
-
- /// Order by 1) all __strong together 2) next, all byfref together 3) next,
- /// all __weak together. Preserve descending alignment in all situations.
- bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) {
- if (left.Alignment != right.Alignment)
- return left.Alignment > right.Alignment;
-
- auto getPrefOrder = [](const BlockLayoutChunk &chunk) {
- if (chunk.Capture && chunk.Capture->isByRef())
- return 1;
- if (chunk.Lifetime == Qualifiers::OCL_Strong)
- return 0;
- if (chunk.Lifetime == Qualifiers::OCL_Weak)
- return 2;
- return 3;
- };
-
- return getPrefOrder(left) < getPrefOrder(right);
- }
-} // end anonymous namespace
-
-/// Determines if the given type is safe for constant capture in C++.
-static bool isSafeForCXXConstantCapture(QualType type) {
- const RecordType *recordType =
- type->getBaseElementTypeUnsafe()->getAs<RecordType>();
-
- // Only records can be unsafe.
- if (!recordType) return true;
-
- const auto *record = cast<CXXRecordDecl>(recordType->getDecl());
-
- // Maintain semantics for classes with non-trivial dtors or copy ctors.
- if (!record->hasTrivialDestructor()) return false;
- if (record->hasNonTrivialCopyConstructor()) return false;
-
- // Otherwise, we just have to make sure there aren't any mutable
- // fields that might have changed since initialization.
- return !record->hasMutableFields();
-}
-
-/// It is illegal to modify a const object after initialization.
-/// Therefore, if a const object has a constant initializer, we don't
-/// actually need to keep storage for it in the block; we'll just
-/// rematerialize it at the start of the block function. This is
-/// acceptable because we make no promises about address stability of
-/// captured variables.
-static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
- CodeGenFunction *CGF,
- const VarDecl *var) {
- // Return if this is a function parameter. We shouldn't try to
- // rematerialize default arguments of function parameters.
- if (isa<ParmVarDecl>(var))
- return nullptr;
-
- QualType type = var->getType();
-
- // We can only do this if the variable is const.
- if (!type.isConstQualified()) return nullptr;
-
- // Furthermore, in C++ we have to worry about mutable fields:
- // C++ [dcl.type.cv]p4:
- // Except that any class member declared mutable can be
- // modified, any attempt to modify a const object during its
- // lifetime results in undefined behavior.
- if (CGM.getLangOpts().CPlusPlus && !isSafeForCXXConstantCapture(type))
- return nullptr;
-
- // If the variable doesn't have any initializer (shouldn't this be
- // invalid?), it's not clear what we should do. Maybe capture as
- // zero?
- const Expr *init = var->getInit();
- if (!init) return nullptr;
-
- return ConstantEmitter(CGM, CGF).tryEmitAbstractForInitializer(*var);
-}
-
-/// Get the low bit of a nonzero character count. This is the
-/// alignment of the nth byte if the 0th byte is universally aligned.
-static CharUnits getLowBit(CharUnits v) {
- return CharUnits::fromQuantity(v.getQuantity() & (~v.getQuantity() + 1));
-}
-
-static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
- SmallVectorImpl<llvm::Type*> &elementTypes) {
-
- assert(elementTypes.empty());
- if (CGM.getLangOpts().OpenCL) {
- // The header is basically 'struct { int; int; generic void *;
- // custom_fields; }'. Assert that struct is packed.
- auto GenericAS =
- CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic);
- auto GenPtrAlign =
- CharUnits::fromQuantity(CGM.getTarget().getPointerAlign(GenericAS) / 8);
- auto GenPtrSize =
- CharUnits::fromQuantity(CGM.getTarget().getPointerWidth(GenericAS) / 8);
- assert(CGM.getIntSize() <= GenPtrSize);
- assert(CGM.getIntAlign() <= GenPtrAlign);
- assert((2 * CGM.getIntSize()).isMultipleOf(GenPtrAlign));
- elementTypes.push_back(CGM.IntTy); /* total size */
- elementTypes.push_back(CGM.IntTy); /* align */
- elementTypes.push_back(
- CGM.getOpenCLRuntime()
- .getGenericVoidPointerType()); /* invoke function */
- unsigned Offset =
- 2 * CGM.getIntSize().getQuantity() + GenPtrSize.getQuantity();
- unsigned BlockAlign = GenPtrAlign.getQuantity();
- if (auto *Helper =
- CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
- for (auto I : Helper->getCustomFieldTypes()) /* custom fields */ {
- // TargetOpenCLBlockHelp needs to make sure the struct is packed.
- // If necessary, add padding fields to the custom fields.
- unsigned Align = CGM.getDataLayout().getABITypeAlignment(I);
- if (BlockAlign < Align)
- BlockAlign = Align;
- assert(Offset % Align == 0);
- Offset += CGM.getDataLayout().getTypeAllocSize(I);
- elementTypes.push_back(I);
- }
- }
- info.BlockAlign = CharUnits::fromQuantity(BlockAlign);
- info.BlockSize = CharUnits::fromQuantity(Offset);
- } else {
- // The header is basically 'struct { void *; int; int; void *; void *; }'.
- // Assert that the struct is packed.
- assert(CGM.getIntSize() <= CGM.getPointerSize());
- assert(CGM.getIntAlign() <= CGM.getPointerAlign());
- assert((2 * CGM.getIntSize()).isMultipleOf(CGM.getPointerAlign()));
- info.BlockAlign = CGM.getPointerAlign();
- info.BlockSize = 3 * CGM.getPointerSize() + 2 * CGM.getIntSize();
- elementTypes.push_back(CGM.VoidPtrTy);
- elementTypes.push_back(CGM.IntTy);
- elementTypes.push_back(CGM.IntTy);
- elementTypes.push_back(CGM.VoidPtrTy);
- elementTypes.push_back(CGM.getBlockDescriptorType());
- }
-}
-
-static QualType getCaptureFieldType(const CodeGenFunction &CGF,
- const BlockDecl::Capture &CI) {
- const VarDecl *VD = CI.getVariable();
-
- // If the variable is captured by an enclosing block or lambda expression,
- // use the type of the capture field.
- if (CGF.BlockInfo && CI.isNested())
- return CGF.BlockInfo->getCapture(VD).fieldType();
- if (auto *FD = CGF.LambdaCaptureFields.lookup(VD))
- return FD->getType();
- // If the captured variable is a non-escaping __block variable, the field
- // type is the reference type. If the variable is a __block variable that
- // already has a reference type, the field type is the variable's type.
- return VD->isNonEscapingByref() ?
- CGF.getContext().getLValueReferenceType(VD->getType()) : VD->getType();
-}
-
-/// Compute the layout of the given block. Attempts to lay the block
-/// out with minimal space requirements.
-static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
- CGBlockInfo &info) {
- ASTContext &C = CGM.getContext();
- const BlockDecl *block = info.getBlockDecl();
-
- SmallVector<llvm::Type*, 8> elementTypes;
- initializeForBlockHeader(CGM, info, elementTypes);
- bool hasNonConstantCustomFields = false;
- if (auto *OpenCLHelper =
- CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper())
- hasNonConstantCustomFields =
- !OpenCLHelper->areAllCustomFieldValuesConstant(info);
- if (!block->hasCaptures() && !hasNonConstantCustomFields) {
- info.StructureType =
- llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
- info.CanBeGlobal = true;
- return;
- }
- else if (C.getLangOpts().ObjC &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC)
- info.HasCapturedVariableLayout = true;
-
- // Collect the layout chunks.
- SmallVector<BlockLayoutChunk, 16> layout;
- layout.reserve(block->capturesCXXThis() +
- (block->capture_end() - block->capture_begin()));
-
- CharUnits maxFieldAlign;
-
- // First, 'this'.
- if (block->capturesCXXThis()) {
- assert(CGF && CGF->CurFuncDecl && isa<CXXMethodDecl>(CGF->CurFuncDecl) &&
- "Can't capture 'this' outside a method");
- QualType thisType = cast<CXXMethodDecl>(CGF->CurFuncDecl)->getThisType();
-
- // Theoretically, this could be in a different address space, so
- // don't assume standard pointer size/align.
- llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
- std::pair<CharUnits,CharUnits> tinfo
- = CGM.getContext().getTypeInfoInChars(thisType);
- maxFieldAlign = std::max(maxFieldAlign, tinfo.second);
-
- layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first,
- Qualifiers::OCL_None,
- nullptr, llvmType, thisType));
- }
-
- // Next, all the block captures.
- for (const auto &CI : block->captures()) {
- const VarDecl *variable = CI.getVariable();
-
- if (CI.isEscapingByref()) {
- // We have to copy/dispose of the __block reference.
- info.NeedsCopyDispose = true;
-
- // Just use void* instead of a pointer to the byref type.
- CharUnits align = CGM.getPointerAlign();
- maxFieldAlign = std::max(maxFieldAlign, align);
-
- // Since a __block variable cannot be captured by lambdas, its type and
- // the capture field type should always match.
- assert(getCaptureFieldType(*CGF, CI) == variable->getType() &&
- "capture type differs from the variable type");
- layout.push_back(BlockLayoutChunk(align, CGM.getPointerSize(),
- Qualifiers::OCL_None, &CI,
- CGM.VoidPtrTy, variable->getType()));
- continue;
- }
-
- // Otherwise, build a layout chunk with the size and alignment of
- // the declaration.
- if (llvm::Constant *constant = tryCaptureAsConstant(CGM, CGF, variable)) {
- info.Captures[variable] = CGBlockInfo::Capture::makeConstant(constant);
- continue;
- }
-
- QualType VT = getCaptureFieldType(*CGF, CI);
-
- // If we have a lifetime qualifier, honor it for capture purposes.
- // That includes *not* copying it if it's __unsafe_unretained.
- Qualifiers::ObjCLifetime lifetime = VT.getObjCLifetime();
- if (lifetime) {
- switch (lifetime) {
- case Qualifiers::OCL_None: llvm_unreachable("impossible");
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- break;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- info.NeedsCopyDispose = true;
- }
-
- // Block pointers require copy/dispose. So do Objective-C pointers.
- } else if (VT->isObjCRetainableType()) {
- // But honor the inert __unsafe_unretained qualifier, which doesn't
- // actually make it into the type system.
- if (VT->isObjCInertUnsafeUnretainedType()) {
- lifetime = Qualifiers::OCL_ExplicitNone;
- } else {
- info.NeedsCopyDispose = true;
- // used for mrr below.
- lifetime = Qualifiers::OCL_Strong;
- }
-
- // So do types that require non-trivial copy construction.
- } else if (CI.hasCopyExpr()) {
- info.NeedsCopyDispose = true;
- info.HasCXXObject = true;
- if (!VT->getAsCXXRecordDecl()->isExternallyVisible())
- info.CapturesNonExternalType = true;
-
- // So do C structs that require non-trivial copy construction or
- // destruction.
- } else if (VT.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct ||
- VT.isDestructedType() == QualType::DK_nontrivial_c_struct) {
- info.NeedsCopyDispose = true;
-
- // And so do types with destructors.
- } else if (CGM.getLangOpts().CPlusPlus) {
- if (const CXXRecordDecl *record = VT->getAsCXXRecordDecl()) {
- if (!record->hasTrivialDestructor()) {
- info.HasCXXObject = true;
- info.NeedsCopyDispose = true;
- if (!record->isExternallyVisible())
- info.CapturesNonExternalType = true;
- }
- }
- }
-
- CharUnits size = C.getTypeSizeInChars(VT);
- CharUnits align = C.getDeclAlign(variable);
-
- maxFieldAlign = std::max(maxFieldAlign, align);
-
- llvm::Type *llvmType =
- CGM.getTypes().ConvertTypeForMem(VT);
-
- layout.push_back(
- BlockLayoutChunk(align, size, lifetime, &CI, llvmType, VT));
- }
-
- // If that was everything, we're done here.
- if (layout.empty()) {
- info.StructureType =
- llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
- info.CanBeGlobal = true;
- return;
- }
-
- // Sort the layout by alignment. We have to use a stable sort here
- // to get reproducible results. There should probably be an
- // llvm::array_pod_stable_sort.
- std::stable_sort(layout.begin(), layout.end());
-
- // Needed for blocks layout info.
- info.BlockHeaderForcedGapOffset = info.BlockSize;
- info.BlockHeaderForcedGapSize = CharUnits::Zero();
-
- CharUnits &blockSize = info.BlockSize;
- info.BlockAlign = std::max(maxFieldAlign, info.BlockAlign);
-
- // Assuming that the first byte in the header is maximally aligned,
- // get the alignment of the first byte following the header.
- CharUnits endAlign = getLowBit(blockSize);
-
- // If the end of the header isn't satisfactorily aligned for the
- // maximum thing, look for things that are okay with the header-end
- // alignment, and keep appending them until we get something that's
- // aligned right. This algorithm is only guaranteed optimal if
- // that condition is satisfied at some point; otherwise we can get
- // things like:
- // header // next byte has alignment 4
- // something_with_size_5; // next byte has alignment 1
- // something_with_alignment_8;
- // which has 7 bytes of padding, as opposed to the naive solution
- // which might have less (?).
- if (endAlign < maxFieldAlign) {
- SmallVectorImpl<BlockLayoutChunk>::iterator
- li = layout.begin() + 1, le = layout.end();
-
- // Look for something that the header end is already
- // satisfactorily aligned for.
- for (; li != le && endAlign < li->Alignment; ++li)
- ;
-
- // If we found something that's naturally aligned for the end of
- // the header, keep adding things...
- if (li != le) {
- SmallVectorImpl<BlockLayoutChunk>::iterator first = li;
- for (; li != le; ++li) {
- assert(endAlign >= li->Alignment);
-
- li->setIndex(info, elementTypes.size(), blockSize);
- elementTypes.push_back(li->Type);
- blockSize += li->Size;
- endAlign = getLowBit(blockSize);
-
- // ...until we get to the alignment of the maximum field.
- if (endAlign >= maxFieldAlign) {
- break;
- }
- }
- // Don't re-append everything we just appended.
- layout.erase(first, li);
- }
- }
-
- assert(endAlign == getLowBit(blockSize));
-
- // At this point, we just have to add padding if the end align still
- // isn't aligned right.
- if (endAlign < maxFieldAlign) {
- CharUnits newBlockSize = blockSize.alignTo(maxFieldAlign);
- CharUnits padding = newBlockSize - blockSize;
-
- // If we haven't yet added any fields, remember that there was an
- // initial gap; this need to go into the block layout bit map.
- if (blockSize == info.BlockHeaderForcedGapOffset) {
- info.BlockHeaderForcedGapSize = padding;
- }
-
- elementTypes.push_back(llvm::ArrayType::get(CGM.Int8Ty,
- padding.getQuantity()));
- blockSize = newBlockSize;
- endAlign = getLowBit(blockSize); // might be > maxFieldAlign
- }
-
- assert(endAlign >= maxFieldAlign);
- assert(endAlign == getLowBit(blockSize));
- // Slam everything else on now. This works because they have
- // strictly decreasing alignment and we expect that size is always a
- // multiple of alignment.
- for (SmallVectorImpl<BlockLayoutChunk>::iterator
- li = layout.begin(), le = layout.end(); li != le; ++li) {
- if (endAlign < li->Alignment) {
- // size may not be multiple of alignment. This can only happen with
- // an over-aligned variable. We will be adding a padding field to
- // make the size be multiple of alignment.
- CharUnits padding = li->Alignment - endAlign;
- elementTypes.push_back(llvm::ArrayType::get(CGM.Int8Ty,
- padding.getQuantity()));
- blockSize += padding;
- endAlign = getLowBit(blockSize);
- }
- assert(endAlign >= li->Alignment);
- li->setIndex(info, elementTypes.size(), blockSize);
- elementTypes.push_back(li->Type);
- blockSize += li->Size;
- endAlign = getLowBit(blockSize);
- }
-
- info.StructureType =
- llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
-}
-
-/// Enter the scope of a block. This should be run at the entrance to
-/// a full-expression so that the block's cleanups are pushed at the
-/// right place in the stack.
-static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
- assert(CGF.HaveInsertPoint());
-
- // Allocate the block info and place it at the head of the list.
- CGBlockInfo &blockInfo =
- *new CGBlockInfo(block, CGF.CurFn->getName());
- blockInfo.NextBlockInfo = CGF.FirstBlockInfo;
- CGF.FirstBlockInfo = &blockInfo;
-
- // Compute information about the layout, etc., of this block,
- // pushing cleanups as necessary.
- computeBlockInfo(CGF.CGM, &CGF, blockInfo);
-
- // Nothing else to do if it can be global.
- if (blockInfo.CanBeGlobal) return;
-
- // Make the allocation for the block.
- blockInfo.LocalAddress = CGF.CreateTempAlloca(blockInfo.StructureType,
- blockInfo.BlockAlign, "block");
-
- // If there are cleanups to emit, enter them (but inactive).
- if (!blockInfo.NeedsCopyDispose) return;
-
- // Walk through the captures (in order) and find the ones not
- // captured by constant.
- for (const auto &CI : block->captures()) {
- // Ignore __block captures; there's nothing special in the
- // on-stack block that we need to do for them.
- if (CI.isByRef()) continue;
-
- // Ignore variables that are constant-captured.
- const VarDecl *variable = CI.getVariable();
- CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
- if (capture.isConstant()) continue;
-
- // Ignore objects that aren't destructed.
- QualType VT = getCaptureFieldType(CGF, CI);
- QualType::DestructionKind dtorKind = VT.isDestructedType();
- if (dtorKind == QualType::DK_none) continue;
-
- CodeGenFunction::Destroyer *destroyer;
-
- // Block captures count as local values and have imprecise semantics.
- // They also can't be arrays, so need to worry about that.
- //
- // For const-qualified captures, emit clang.arc.use to ensure the captured
- // object doesn't get released while we are still depending on its validity
- // within the block.
- if (VT.isConstQualified() &&
- VT.getObjCLifetime() == Qualifiers::OCL_Strong &&
- CGF.CGM.getCodeGenOpts().OptimizationLevel != 0) {
- assert(CGF.CGM.getLangOpts().ObjCAutoRefCount &&
- "expected ObjC ARC to be enabled");
- destroyer = CodeGenFunction::emitARCIntrinsicUse;
- } else if (dtorKind == QualType::DK_objc_strong_lifetime) {
- destroyer = CodeGenFunction::destroyARCStrongImprecise;
- } else {
- destroyer = CGF.getDestroyer(dtorKind);
- }
-
- // GEP down to the address.
- Address addr = CGF.Builder.CreateStructGEP(blockInfo.LocalAddress,
- capture.getIndex(),
- capture.getOffset());
-
- // We can use that GEP as the dominating IP.
- if (!blockInfo.DominatingIP)
- blockInfo.DominatingIP = cast<llvm::Instruction>(addr.getPointer());
-
- CleanupKind cleanupKind = InactiveNormalCleanup;
- bool useArrayEHCleanup = CGF.needsEHCleanup(dtorKind);
- if (useArrayEHCleanup)
- cleanupKind = InactiveNormalAndEHCleanup;
-
- CGF.pushDestroy(cleanupKind, addr, VT,
- destroyer, useArrayEHCleanup);
-
- // Remember where that cleanup was.
- capture.setCleanup(CGF.EHStack.stable_begin());
- }
-}
-
-/// Enter a full-expression with a non-trivial number of objects to
-/// clean up. This is in this file because, at the moment, the only
-/// kind of cleanup object is a BlockDecl*.
-void CodeGenFunction::enterNonTrivialFullExpression(const FullExpr *E) {
- if (const auto EWC = dyn_cast<ExprWithCleanups>(E)) {
- assert(EWC->getNumObjects() != 0);
- for (const ExprWithCleanups::CleanupObject &C : EWC->getObjects())
- enterBlockScope(*this, C);
- }
-}
-
-/// Find the layout for the given block in a linked list and remove it.
-static CGBlockInfo *findAndRemoveBlockInfo(CGBlockInfo **head,
- const BlockDecl *block) {
- while (true) {
- assert(head && *head);
- CGBlockInfo *cur = *head;
-
- // If this is the block we're looking for, splice it out of the list.
- if (cur->getBlockDecl() == block) {
- *head = cur->NextBlockInfo;
- return cur;
- }
-
- head = &cur->NextBlockInfo;
- }
-}
-
-/// Destroy a chain of block layouts.
-void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) {
- assert(head && "destroying an empty chain");
- do {
- CGBlockInfo *cur = head;
- head = cur->NextBlockInfo;
- delete cur;
- } while (head != nullptr);
-}
-
-/// Emit a block literal expression in the current function.
-llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
- // If the block has no captures, we won't have a pre-computed
- // layout for it.
- if (!blockExpr->getBlockDecl()->hasCaptures()) {
- // The block literal is emitted as a global variable, and the block invoke
- // function has to be extracted from its initializer.
- if (llvm::Constant *Block = CGM.getAddrOfGlobalBlockIfEmitted(blockExpr)) {
- return Block;
- }
- CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName());
- computeBlockInfo(CGM, this, blockInfo);
- blockInfo.BlockExpression = blockExpr;
- return EmitBlockLiteral(blockInfo);
- }
-
- // Find the block info for this block and take ownership of it.
- std::unique_ptr<CGBlockInfo> blockInfo;
- blockInfo.reset(findAndRemoveBlockInfo(&FirstBlockInfo,
- blockExpr->getBlockDecl()));
-
- blockInfo->BlockExpression = blockExpr;
- return EmitBlockLiteral(*blockInfo);
-}
-
-llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
- bool IsOpenCL = CGM.getContext().getLangOpts().OpenCL;
- auto GenVoidPtrTy =
- IsOpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy;
- LangAS GenVoidPtrAddr = IsOpenCL ? LangAS::opencl_generic : LangAS::Default;
- auto GenVoidPtrSize = CharUnits::fromQuantity(
- CGM.getTarget().getPointerWidth(
- CGM.getContext().getTargetAddressSpace(GenVoidPtrAddr)) /
- 8);
- // Using the computed layout, generate the actual block function.
- bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
- CodeGenFunction BlockCGF{CGM, true};
- BlockCGF.SanOpts = SanOpts;
- auto *InvokeFn = BlockCGF.GenerateBlockFunction(
- CurGD, blockInfo, LocalDeclMap, isLambdaConv, blockInfo.CanBeGlobal);
- auto *blockFn = llvm::ConstantExpr::getPointerCast(InvokeFn, GenVoidPtrTy);
-
- // If there is nothing to capture, we can emit this as a global block.
- if (blockInfo.CanBeGlobal)
- return CGM.getAddrOfGlobalBlockIfEmitted(blockInfo.BlockExpression);
-
- // Otherwise, we have to emit this as a local block.
-
- Address blockAddr = blockInfo.LocalAddress;
- assert(blockAddr.isValid() && "block has no address!");
-
- llvm::Constant *isa;
- llvm::Constant *descriptor;
- BlockFlags flags;
- if (!IsOpenCL) {
- // If the block is non-escaping, set field 'isa 'to NSConcreteGlobalBlock
- // and set the BLOCK_IS_GLOBAL bit of field 'flags'. Copying a non-escaping
- // block just returns the original block and releasing it is a no-op.
- llvm::Constant *blockISA = blockInfo.getBlockDecl()->doesNotEscape()
- ? CGM.getNSConcreteGlobalBlock()
- : CGM.getNSConcreteStackBlock();
- isa = llvm::ConstantExpr::getBitCast(blockISA, VoidPtrTy);
-
- // Build the block descriptor.
- descriptor = buildBlockDescriptor(CGM, blockInfo);
-
- // Compute the initial on-stack block flags.
- flags = BLOCK_HAS_SIGNATURE;
- if (blockInfo.HasCapturedVariableLayout)
- flags |= BLOCK_HAS_EXTENDED_LAYOUT;
- if (blockInfo.needsCopyDisposeHelpers())
- flags |= BLOCK_HAS_COPY_DISPOSE;
- if (blockInfo.HasCXXObject)
- flags |= BLOCK_HAS_CXX_OBJ;
- if (blockInfo.UsesStret)
- flags |= BLOCK_USE_STRET;
- if (blockInfo.getBlockDecl()->doesNotEscape())
- flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL;
- }
-
- auto projectField =
- [&](unsigned index, CharUnits offset, const Twine &name) -> Address {
- return Builder.CreateStructGEP(blockAddr, index, offset, name);
- };
- auto storeField =
- [&](llvm::Value *value, unsigned index, CharUnits offset,
- const Twine &name) {
- Builder.CreateStore(value, projectField(index, offset, name));
- };
-
- // Initialize the block header.
- {
- // We assume all the header fields are densely packed.
- unsigned index = 0;
- CharUnits offset;
- auto addHeaderField =
- [&](llvm::Value *value, CharUnits size, const Twine &name) {
- storeField(value, index, offset, name);
- offset += size;
- index++;
- };
-
- if (!IsOpenCL) {
- addHeaderField(isa, getPointerSize(), "block.isa");
- addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
- getIntSize(), "block.flags");
- addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(),
- "block.reserved");
- } else {
- addHeaderField(
- llvm::ConstantInt::get(IntTy, blockInfo.BlockSize.getQuantity()),
- getIntSize(), "block.size");
- addHeaderField(
- llvm::ConstantInt::get(IntTy, blockInfo.BlockAlign.getQuantity()),
- getIntSize(), "block.align");
- }
- addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
- if (!IsOpenCL)
- addHeaderField(descriptor, getPointerSize(), "block.descriptor");
- else if (auto *Helper =
- CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
- for (auto I : Helper->getCustomFieldValues(*this, blockInfo)) {
- addHeaderField(
- I.first,
- CharUnits::fromQuantity(
- CGM.getDataLayout().getTypeAllocSize(I.first->getType())),
- I.second);
- }
- }
- }
-
- // Finally, capture all the values into the block.
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
- // First, 'this'.
- if (blockDecl->capturesCXXThis()) {
- Address addr = projectField(blockInfo.CXXThisIndex, blockInfo.CXXThisOffset,
- "block.captured-this.addr");
- Builder.CreateStore(LoadCXXThis(), addr);
- }
-
- // Next, captured variables.
- for (const auto &CI : blockDecl->captures()) {
- const VarDecl *variable = CI.getVariable();
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
-
- // Ignore constant captures.
- if (capture.isConstant()) continue;
-
- QualType type = capture.fieldType();
-
- // This will be a [[type]]*, except that a byref entry will just be
- // an i8**.
- Address blockField =
- projectField(capture.getIndex(), capture.getOffset(), "block.captured");
-
- // Compute the address of the thing we're going to move into the
- // block literal.
- Address src = Address::invalid();
-
- if (blockDecl->isConversionFromLambda()) {
- // The lambda capture in a lambda's conversion-to-block-pointer is
- // special; we'll simply emit it directly.
- src = Address::invalid();
- } else if (CI.isEscapingByref()) {
- if (BlockInfo && CI.isNested()) {
- // We need to use the capture from the enclosing block.
- const CGBlockInfo::Capture &enclosingCapture =
- BlockInfo->getCapture(variable);
-
- // This is a [[type]]*, except that a byref entry will just be an i8**.
- src = Builder.CreateStructGEP(LoadBlockStruct(),
- enclosingCapture.getIndex(),
- enclosingCapture.getOffset(),
- "block.capture.addr");
- } else {
- auto I = LocalDeclMap.find(variable);
- assert(I != LocalDeclMap.end());
- src = I->second;
- }
- } else {
- DeclRefExpr declRef(getContext(), const_cast<VarDecl *>(variable),
- /*RefersToEnclosingVariableOrCapture*/ CI.isNested(),
- type.getNonReferenceType(), VK_LValue,
- SourceLocation());
- src = EmitDeclRefLValue(&declRef).getAddress();
- };
-
- // For byrefs, we just write the pointer to the byref struct into
- // the block field. There's no need to chase the forwarding
- // pointer at this point, since we're building something that will
- // live a shorter life than the stack byref anyway.
- if (CI.isEscapingByref()) {
- // Get a void* that points to the byref struct.
- llvm::Value *byrefPointer;
- if (CI.isNested())
- byrefPointer = Builder.CreateLoad(src, "byref.capture");
- else
- byrefPointer = Builder.CreateBitCast(src.getPointer(), VoidPtrTy);
-
- // Write that void* into the capture field.
- Builder.CreateStore(byrefPointer, blockField);
-
- // If we have a copy constructor, evaluate that into the block field.
- } else if (const Expr *copyExpr = CI.getCopyExpr()) {
- if (blockDecl->isConversionFromLambda()) {
- // If we have a lambda conversion, emit the expression
- // directly into the block instead.
- AggValueSlot Slot =
- AggValueSlot::forAddr(blockField, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap);
- EmitAggExpr(copyExpr, Slot);
- } else {
- EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr);
- }
-
- // If it's a reference variable, copy the reference into the block field.
- } else if (type->isReferenceType()) {
- Builder.CreateStore(src.getPointer(), blockField);
-
- // If type is const-qualified, copy the value into the block field.
- } else if (type.isConstQualified() &&
- type.getObjCLifetime() == Qualifiers::OCL_Strong &&
- CGM.getCodeGenOpts().OptimizationLevel != 0) {
- llvm::Value *value = Builder.CreateLoad(src, "captured");
- Builder.CreateStore(value, blockField);
-
- // If this is an ARC __strong block-pointer variable, don't do a
- // block copy.
- //
- // TODO: this can be generalized into the normal initialization logic:
- // we should never need to do a block-copy when initializing a local
- // variable, because the local variable's lifetime should be strictly
- // contained within the stack block's.
- } else if (type.getObjCLifetime() == Qualifiers::OCL_Strong &&
- type->isBlockPointerType()) {
- // Load the block and do a simple retain.
- llvm::Value *value = Builder.CreateLoad(src, "block.captured_block");
- value = EmitARCRetainNonBlock(value);
-
- // Do a primitive store to the block field.
- Builder.CreateStore(value, blockField);
-
- // Otherwise, fake up a POD copy into the block field.
- } else {
- // Fake up a new variable so that EmitScalarInit doesn't think
- // we're referring to the variable in its own initializer.
- ImplicitParamDecl BlockFieldPseudoVar(getContext(), type,
- ImplicitParamDecl::Other);
-
- // We use one of these or the other depending on whether the
- // reference is nested.
- DeclRefExpr declRef(getContext(), const_cast<VarDecl *>(variable),
- /*RefersToEnclosingVariableOrCapture*/ CI.isNested(),
- type, VK_LValue, SourceLocation());
-
- ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
- &declRef, VK_RValue);
- // FIXME: Pass a specific location for the expr init so that the store is
- // attributed to a reasonable location - otherwise it may be attributed to
- // locations of subexpressions in the initialization.
- EmitExprAsInit(&l2r, &BlockFieldPseudoVar,
- MakeAddrLValue(blockField, type, AlignmentSource::Decl),
- /*captured by init*/ false);
- }
-
- // Activate the cleanup if layout pushed one.
- if (!CI.isByRef()) {
- EHScopeStack::stable_iterator cleanup = capture.getCleanup();
- if (cleanup.isValid())
- ActivateCleanupBlock(cleanup, blockInfo.DominatingIP);
- }
- }
-
- // Cast to the converted block-pointer type, which happens (somewhat
- // unfortunately) to be a pointer to function type.
- llvm::Value *result = Builder.CreatePointerCast(
- blockAddr.getPointer(), ConvertType(blockInfo.getBlockExpr()->getType()));
-
- if (IsOpenCL) {
- CGM.getOpenCLRuntime().recordBlockInfo(blockInfo.BlockExpression, InvokeFn,
- result);
- }
-
- return result;
-}
-
-
-llvm::Type *CodeGenModule::getBlockDescriptorType() {
- if (BlockDescriptorType)
- return BlockDescriptorType;
-
- llvm::Type *UnsignedLongTy =
- getTypes().ConvertType(getContext().UnsignedLongTy);
-
- // struct __block_descriptor {
- // unsigned long reserved;
- // unsigned long block_size;
- //
- // // later, the following will be added
- //
- // struct {
- // void (*copyHelper)();
- // void (*copyHelper)();
- // } helpers; // !!! optional
- //
- // const char *signature; // the block signature
- // const char *layout; // reserved
- // };
- BlockDescriptorType = llvm::StructType::create(
- "struct.__block_descriptor", UnsignedLongTy, UnsignedLongTy);
-
- // Now form a pointer to that.
- unsigned AddrSpace = 0;
- if (getLangOpts().OpenCL)
- AddrSpace = getContext().getTargetAddressSpace(LangAS::opencl_constant);
- BlockDescriptorType = llvm::PointerType::get(BlockDescriptorType, AddrSpace);
- return BlockDescriptorType;
-}
-
-llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
- if (GenericBlockLiteralType)
- return GenericBlockLiteralType;
-
- llvm::Type *BlockDescPtrTy = getBlockDescriptorType();
-
- if (getLangOpts().OpenCL) {
- // struct __opencl_block_literal_generic {
- // int __size;
- // int __align;
- // __generic void *__invoke;
- // /* custom fields */
- // };
- SmallVector<llvm::Type *, 8> StructFields(
- {IntTy, IntTy, getOpenCLRuntime().getGenericVoidPointerType()});
- if (auto *Helper = getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
- for (auto I : Helper->getCustomFieldTypes())
- StructFields.push_back(I);
- }
- GenericBlockLiteralType = llvm::StructType::create(
- StructFields, "struct.__opencl_block_literal_generic");
- } else {
- // struct __block_literal_generic {
- // void *__isa;
- // int __flags;
- // int __reserved;
- // void (*__invoke)(void *);
- // struct __block_descriptor *__descriptor;
- // };
- GenericBlockLiteralType =
- llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy,
- IntTy, IntTy, VoidPtrTy, BlockDescPtrTy);
- }
-
- return GenericBlockLiteralType;
-}
-
-RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue) {
- const BlockPointerType *BPT =
- E->getCallee()->getType()->getAs<BlockPointerType>();
-
- llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee());
-
- // Get a pointer to the generic block literal.
- // For OpenCL we generate generic AS void ptr to be able to reuse the same
- // block definition for blocks with captures generated as private AS local
- // variables and without captures generated as global AS program scope
- // variables.
- unsigned AddrSpace = 0;
- if (getLangOpts().OpenCL)
- AddrSpace = getContext().getTargetAddressSpace(LangAS::opencl_generic);
-
- llvm::Type *BlockLiteralTy =
- llvm::PointerType::get(CGM.getGenericBlockLiteralType(), AddrSpace);
-
- // Bitcast the callee to a block literal.
- BlockPtr =
- Builder.CreatePointerCast(BlockPtr, BlockLiteralTy, "block.literal");
-
- // Get the function pointer from the literal.
- llvm::Value *FuncPtr =
- Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr,
- CGM.getLangOpts().OpenCL ? 2 : 3);
-
- // Add the block literal.
- CallArgList Args;
-
- QualType VoidPtrQualTy = getContext().VoidPtrTy;
- llvm::Type *GenericVoidPtrTy = VoidPtrTy;
- if (getLangOpts().OpenCL) {
- GenericVoidPtrTy = CGM.getOpenCLRuntime().getGenericVoidPointerType();
- VoidPtrQualTy =
- getContext().getPointerType(getContext().getAddrSpaceQualType(
- getContext().VoidTy, LangAS::opencl_generic));
- }
-
- BlockPtr = Builder.CreatePointerCast(BlockPtr, GenericVoidPtrTy);
- Args.add(RValue::get(BlockPtr), VoidPtrQualTy);
-
- QualType FnType = BPT->getPointeeType();
-
- // And the rest of the arguments.
- EmitCallArgs(Args, FnType->getAs<FunctionProtoType>(), E->arguments());
-
- // Load the function.
- llvm::Value *Func = Builder.CreateAlignedLoad(FuncPtr, getPointerAlign());
-
- const FunctionType *FuncTy = FnType->castAs<FunctionType>();
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeBlockFunctionCall(Args, FuncTy);
-
- // Cast the function pointer to the right type.
- llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo);
-
- llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
- Func = Builder.CreatePointerCast(Func, BlockFTyPtr);
-
- // Prepare the callee.
- CGCallee Callee(CGCalleeInfo(), Func);
-
- // And call the block.
- return EmitCall(FnInfo, Callee, ReturnValue, Args);
-}
-
-Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable) {
- assert(BlockInfo && "evaluating block ref without block information?");
- const CGBlockInfo::Capture &capture = BlockInfo->getCapture(variable);
-
- // Handle constant captures.
- if (capture.isConstant()) return LocalDeclMap.find(variable)->second;
-
- Address addr =
- Builder.CreateStructGEP(LoadBlockStruct(), capture.getIndex(),
- capture.getOffset(), "block.capture.addr");
-
- if (variable->isEscapingByref()) {
- // addr should be a void** right now. Load, then cast the result
- // to byref*.
-
- auto &byrefInfo = getBlockByrefInfo(variable);
- addr = Address(Builder.CreateLoad(addr), byrefInfo.ByrefAlignment);
-
- auto byrefPointerType = llvm::PointerType::get(byrefInfo.Type, 0);
- addr = Builder.CreateBitCast(addr, byrefPointerType, "byref.addr");
-
- addr = emitBlockByrefAddress(addr, byrefInfo, /*follow*/ true,
- variable->getName());
- }
-
- assert((!variable->isNonEscapingByref() ||
- capture.fieldType()->isReferenceType()) &&
- "the capture field of a non-escaping variable should have a "
- "reference type");
- if (capture.fieldType()->isReferenceType())
- addr = EmitLoadOfReference(MakeAddrLValue(addr, capture.fieldType()));
-
- return addr;
-}
-
-void CodeGenModule::setAddrOfGlobalBlock(const BlockExpr *BE,
- llvm::Constant *Addr) {
- bool Ok = EmittedGlobalBlocks.insert(std::make_pair(BE, Addr)).second;
- (void)Ok;
- assert(Ok && "Trying to replace an already-existing global block!");
-}
-
-llvm::Constant *
-CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE,
- StringRef Name) {
- if (llvm::Constant *Block = getAddrOfGlobalBlockIfEmitted(BE))
- return Block;
-
- CGBlockInfo blockInfo(BE->getBlockDecl(), Name);
- blockInfo.BlockExpression = BE;
-
- // Compute information about the layout, etc., of this block.
- computeBlockInfo(*this, nullptr, blockInfo);
-
- // Using that metadata, generate the actual block function.
- {
- CodeGenFunction::DeclMapTy LocalDeclMap;
- CodeGenFunction(*this).GenerateBlockFunction(
- GlobalDecl(), blockInfo, LocalDeclMap,
- /*IsLambdaConversionToBlock*/ false, /*BuildGlobalBlock*/ true);
- }
-
- return getAddrOfGlobalBlockIfEmitted(BE);
-}
-
-static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo,
- llvm::Constant *blockFn) {
- assert(blockInfo.CanBeGlobal);
- // Callers should detect this case on their own: calling this function
- // generally requires computing layout information, which is a waste of time
- // if we've already emitted this block.
- assert(!CGM.getAddrOfGlobalBlockIfEmitted(blockInfo.BlockExpression) &&
- "Refusing to re-emit a global block.");
-
- // Generate the constants for the block literal initializer.
- ConstantInitBuilder builder(CGM);
- auto fields = builder.beginStruct();
-
- bool IsOpenCL = CGM.getLangOpts().OpenCL;
- bool IsWindows = CGM.getTarget().getTriple().isOSWindows();
- if (!IsOpenCL) {
- // isa
- if (IsWindows)
- fields.addNullPointer(CGM.Int8PtrPtrTy);
- else
- fields.add(CGM.getNSConcreteGlobalBlock());
-
- // __flags
- BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
- if (blockInfo.UsesStret)
- flags |= BLOCK_USE_STRET;
-
- fields.addInt(CGM.IntTy, flags.getBitMask());
-
- // Reserved
- fields.addInt(CGM.IntTy, 0);
- } else {
- fields.addInt(CGM.IntTy, blockInfo.BlockSize.getQuantity());
- fields.addInt(CGM.IntTy, blockInfo.BlockAlign.getQuantity());
- }
-
- // Function
- fields.add(blockFn);
-
- if (!IsOpenCL) {
- // Descriptor
- fields.add(buildBlockDescriptor(CGM, blockInfo));
- } else if (auto *Helper =
- CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
- for (auto I : Helper->getCustomFieldValues(CGM, blockInfo)) {
- fields.add(I);
- }
- }
-
- unsigned AddrSpace = 0;
- if (CGM.getContext().getLangOpts().OpenCL)
- AddrSpace = CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
-
- llvm::Constant *literal = fields.finishAndCreateGlobal(
- "__block_literal_global", blockInfo.BlockAlign,
- /*constant*/ !IsWindows, llvm::GlobalVariable::InternalLinkage, AddrSpace);
-
- // Windows does not allow globals to be initialised to point to globals in
- // different DLLs. Any such variables must run code to initialise them.
- if (IsWindows) {
- auto *Init = llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy,
- {}), llvm::GlobalValue::InternalLinkage, ".block_isa_init",
- &CGM.getModule());
- llvm::IRBuilder<> b(llvm::BasicBlock::Create(CGM.getLLVMContext(), "entry",
- Init));
- b.CreateAlignedStore(CGM.getNSConcreteGlobalBlock(),
- b.CreateStructGEP(literal, 0), CGM.getPointerAlign().getQuantity());
- b.CreateRetVoid();
- // We can't use the normal LLVM global initialisation array, because we
- // need to specify that this runs early in library initialisation.
- auto *InitVar = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
- /*isConstant*/true, llvm::GlobalValue::InternalLinkage,
- Init, ".block_isa_init_ptr");
- InitVar->setSection(".CRT$XCLa");
- CGM.addUsedGlobal(InitVar);
- }
-
- // Return a constant of the appropriately-casted type.
- llvm::Type *RequiredType =
- CGM.getTypes().ConvertType(blockInfo.getBlockExpr()->getType());
- llvm::Constant *Result =
- llvm::ConstantExpr::getPointerCast(literal, RequiredType);
- CGM.setAddrOfGlobalBlock(blockInfo.BlockExpression, Result);
- if (CGM.getContext().getLangOpts().OpenCL)
- CGM.getOpenCLRuntime().recordBlockInfo(
- blockInfo.BlockExpression,
- cast<llvm::Function>(blockFn->stripPointerCasts()), Result);
- return Result;
-}
-
-void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D,
- unsigned argNum,
- llvm::Value *arg) {
- assert(BlockInfo && "not emitting prologue of block invocation function?!");
-
- // Allocate a stack slot like for any local variable to guarantee optimal
- // debug info at -O0. The mem2reg pass will eliminate it when optimizing.
- Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
- Builder.CreateStore(arg, alloc);
- if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo) {
- DI->setLocation(D->getLocation());
- DI->EmitDeclareOfBlockLiteralArgVariable(
- *BlockInfo, D->getName(), argNum,
- cast<llvm::AllocaInst>(alloc.getPointer()), Builder);
- }
- }
-
- SourceLocation StartLoc = BlockInfo->getBlockExpr()->getBody()->getBeginLoc();
- ApplyDebugLocation Scope(*this, StartLoc);
-
- // Instead of messing around with LocalDeclMap, just set the value
- // directly as BlockPointer.
- BlockPointer = Builder.CreatePointerCast(
- arg,
- BlockInfo->StructureType->getPointerTo(
- getContext().getLangOpts().OpenCL
- ? getContext().getTargetAddressSpace(LangAS::opencl_generic)
- : 0),
- "block");
-}
-
-Address CodeGenFunction::LoadBlockStruct() {
- assert(BlockInfo && "not in a block invocation function!");
- assert(BlockPointer && "no block pointer set!");
- return Address(BlockPointer, BlockInfo->BlockAlign);
-}
-
-llvm::Function *
-CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
- const CGBlockInfo &blockInfo,
- const DeclMapTy &ldm,
- bool IsLambdaConversionToBlock,
- bool BuildGlobalBlock) {
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
- CurGD = GD;
-
- CurEHLocation = blockInfo.getBlockExpr()->getEndLoc();
-
- BlockInfo = &blockInfo;
-
- // Arrange for local static and local extern declarations to appear
- // to be local to this function as well, in case they're directly
- // referenced in a block.
- for (DeclMapTy::const_iterator i = ldm.begin(), e = ldm.end(); i != e; ++i) {
- const auto *var = dyn_cast<VarDecl>(i->first);
- if (var && !var->hasLocalStorage())
- setAddrOfLocalVar(var, i->second);
- }
-
- // Begin building the function declaration.
-
- // Build the argument list.
- FunctionArgList args;
-
- // The first argument is the block pointer. Just take it as a void*
- // and cast it later.
- QualType selfTy = getContext().VoidPtrTy;
-
- // For OpenCL passed block pointer can be private AS local variable or
- // global AS program scope variable (for the case with and without captures).
- // Generic AS is used therefore to be able to accommodate both private and
- // generic AS in one implementation.
- if (getLangOpts().OpenCL)
- selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType(
- getContext().VoidTy, LangAS::opencl_generic));
-
- IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
-
- ImplicitParamDecl SelfDecl(getContext(), const_cast<BlockDecl *>(blockDecl),
- SourceLocation(), II, selfTy,
- ImplicitParamDecl::ObjCSelf);
- args.push_back(&SelfDecl);
-
- // Now add the rest of the parameters.
- args.append(blockDecl->param_begin(), blockDecl->param_end());
-
- // Create the function declaration.
- const FunctionProtoType *fnType = blockInfo.getBlockExpr()->getFunctionType();
- const CGFunctionInfo &fnInfo =
- CGM.getTypes().arrangeBlockFunctionDeclaration(fnType, args);
- if (CGM.ReturnSlotInterferesWithArgs(fnInfo))
- blockInfo.UsesStret = true;
-
- llvm::FunctionType *fnLLVMType = CGM.getTypes().GetFunctionType(fnInfo);
-
- StringRef name = CGM.getBlockMangledName(GD, blockDecl);
- llvm::Function *fn = llvm::Function::Create(
- fnLLVMType, llvm::GlobalValue::InternalLinkage, name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo);
-
- if (BuildGlobalBlock) {
- auto GenVoidPtrTy = getContext().getLangOpts().OpenCL
- ? CGM.getOpenCLRuntime().getGenericVoidPointerType()
- : VoidPtrTy;
- buildGlobalBlock(CGM, blockInfo,
- llvm::ConstantExpr::getPointerCast(fn, GenVoidPtrTy));
- }
-
- // Begin generating the function.
- StartFunction(blockDecl, fnType->getReturnType(), fn, fnInfo, args,
- blockDecl->getLocation(),
- blockInfo.getBlockExpr()->getBody()->getBeginLoc());
-
- // Okay. Undo some of what StartFunction did.
-
- // At -O0 we generate an explicit alloca for the BlockPointer, so the RA
- // won't delete the dbg.declare intrinsics for captured variables.
- llvm::Value *BlockPointerDbgLoc = BlockPointer;
- if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
- // Allocate a stack slot for it, so we can point the debugger to it
- Address Alloca = CreateTempAlloca(BlockPointer->getType(),
- getPointerAlign(),
- "block.addr");
- // Set the DebugLocation to empty, so the store is recognized as a
- // frame setup instruction by llvm::DwarfDebug::beginFunction().
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
- Builder.CreateStore(BlockPointer, Alloca);
- BlockPointerDbgLoc = Alloca.getPointer();
- }
-
- // If we have a C++ 'this' reference, go ahead and force it into
- // existence now.
- if (blockDecl->capturesCXXThis()) {
- Address addr =
- Builder.CreateStructGEP(LoadBlockStruct(), blockInfo.CXXThisIndex,
- blockInfo.CXXThisOffset, "block.captured-this");
- CXXThisValue = Builder.CreateLoad(addr, "this");
- }
-
- // Also force all the constant captures.
- for (const auto &CI : blockDecl->captures()) {
- const VarDecl *variable = CI.getVariable();
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
- if (!capture.isConstant()) continue;
-
- CharUnits align = getContext().getDeclAlign(variable);
- Address alloca =
- CreateMemTemp(variable->getType(), align, "block.captured-const");
-
- Builder.CreateStore(capture.getConstant(), alloca);
-
- setAddrOfLocalVar(variable, alloca);
- }
-
- // Save a spot to insert the debug information for all the DeclRefExprs.
- llvm::BasicBlock *entry = Builder.GetInsertBlock();
- llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint();
- --entry_ptr;
-
- if (IsLambdaConversionToBlock)
- EmitLambdaBlockInvokeBody();
- else {
- PGO.assignRegionCounters(GlobalDecl(blockDecl), fn);
- incrementProfileCounter(blockDecl->getBody());
- EmitStmt(blockDecl->getBody());
- }
-
- // Remember where we were...
- llvm::BasicBlock *resume = Builder.GetInsertBlock();
-
- // Go back to the entry.
- ++entry_ptr;
- Builder.SetInsertPoint(entry, entry_ptr);
-
- // Emit debug information for all the DeclRefExprs.
- // FIXME: also for 'this'
- if (CGDebugInfo *DI = getDebugInfo()) {
- for (const auto &CI : blockDecl->captures()) {
- const VarDecl *variable = CI.getVariable();
- DI->EmitLocation(Builder, variable->getLocation());
-
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo) {
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
- if (capture.isConstant()) {
- auto addr = LocalDeclMap.find(variable)->second;
- (void)DI->EmitDeclareOfAutoVariable(variable, addr.getPointer(),
- Builder);
- continue;
- }
-
- DI->EmitDeclareOfBlockDeclRefVariable(
- variable, BlockPointerDbgLoc, Builder, blockInfo,
- entry_ptr == entry->end() ? nullptr : &*entry_ptr);
- }
- }
- // Recover location if it was changed in the above loop.
- DI->EmitLocation(Builder,
- cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc());
- }
-
- // And resume where we left off.
- if (resume == nullptr)
- Builder.ClearInsertionPoint();
- else
- Builder.SetInsertPoint(resume);
-
- FinishFunction(cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc());
-
- return fn;
-}
-
-static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
-computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
- const LangOptions &LangOpts) {
- if (CI.getCopyExpr()) {
- assert(!CI.isByRef());
- // don't bother computing flags
- return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags());
- }
- BlockFieldFlags Flags;
- if (CI.isEscapingByref()) {
- Flags = BLOCK_FIELD_IS_BYREF;
- if (T.isObjCGCWeak())
- Flags |= BLOCK_FIELD_IS_WEAK;
- return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
- }
-
- Flags = BLOCK_FIELD_IS_OBJECT;
- bool isBlockPointer = T->isBlockPointerType();
- if (isBlockPointer)
- Flags = BLOCK_FIELD_IS_BLOCK;
-
- switch (T.isNonTrivialToPrimitiveCopy()) {
- case QualType::PCK_Struct:
- return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct,
- BlockFieldFlags());
- case QualType::PCK_ARCWeak:
- // We need to register __weak direct captures with the runtime.
- return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags);
- case QualType::PCK_ARCStrong:
- // We need to retain the copied value for __strong direct captures.
- // If it's a block pointer, we have to copy the block and assign that to
- // the destination pointer, so we might as well use _Block_object_assign.
- // Otherwise we can avoid that.
- return std::make_pair(!isBlockPointer ? BlockCaptureEntityKind::ARCStrong
- : BlockCaptureEntityKind::BlockObject,
- Flags);
- case QualType::PCK_Trivial:
- case QualType::PCK_VolatileTrivial: {
- if (!T->isObjCRetainableType())
- // For all other types, the memcpy is fine.
- return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags());
-
- // Special rules for ARC captures:
- Qualifiers QS = T.getQualifiers();
-
- // Non-ARC captures of retainable pointers are strong and
- // therefore require a call to _Block_object_assign.
- if (!QS.getObjCLifetime() && !LangOpts.ObjCAutoRefCount)
- return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
-
- // Otherwise the memcpy is fine.
- return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags());
- }
- }
- llvm_unreachable("after exhaustive PrimitiveCopyKind switch");
-}
-
-static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
-computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
- const LangOptions &LangOpts);
-
-/// Find the set of block captures that need to be explicitly copied or destroy.
-static void findBlockCapturedManagedEntities(
- const CGBlockInfo &BlockInfo, const LangOptions &LangOpts,
- SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures) {
- for (const auto &CI : BlockInfo.getBlockDecl()->captures()) {
- const VarDecl *Variable = CI.getVariable();
- const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable);
- if (Capture.isConstant())
- continue;
-
- QualType VT = Capture.fieldType();
- auto CopyInfo = computeCopyInfoForBlockCapture(CI, VT, LangOpts);
- auto DisposeInfo = computeDestroyInfoForBlockCapture(CI, VT, LangOpts);
- if (CopyInfo.first != BlockCaptureEntityKind::None ||
- DisposeInfo.first != BlockCaptureEntityKind::None)
- ManagedCaptures.emplace_back(CopyInfo.first, DisposeInfo.first,
- CopyInfo.second, DisposeInfo.second, CI,
- Capture);
- }
-
- // Sort the captures by offset.
- llvm::sort(ManagedCaptures);
-}
-
-namespace {
-/// Release a __block variable.
-struct CallBlockRelease final : EHScopeStack::Cleanup {
- Address Addr;
- BlockFieldFlags FieldFlags;
- bool LoadBlockVarAddr, CanThrow;
-
- CallBlockRelease(Address Addr, BlockFieldFlags Flags, bool LoadValue,
- bool CT)
- : Addr(Addr), FieldFlags(Flags), LoadBlockVarAddr(LoadValue),
- CanThrow(CT) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- llvm::Value *BlockVarAddr;
- if (LoadBlockVarAddr) {
- BlockVarAddr = CGF.Builder.CreateLoad(Addr);
- BlockVarAddr = CGF.Builder.CreateBitCast(BlockVarAddr, CGF.VoidPtrTy);
- } else {
- BlockVarAddr = Addr.getPointer();
- }
-
- CGF.BuildBlockRelease(BlockVarAddr, FieldFlags, CanThrow);
- }
-};
-} // end anonymous namespace
-
-/// Check if \p T is a C++ class that has a destructor that can throw.
-bool CodeGenFunction::cxxDestructorCanThrow(QualType T) {
- if (const auto *RD = T->getAsCXXRecordDecl())
- if (const CXXDestructorDecl *DD = RD->getDestructor())
- return DD->getType()->getAs<FunctionProtoType>()->canThrow();
- return false;
-}
-
-// Return a string that has the information about a capture.
-static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E,
- CaptureStrKind StrKind,
- CharUnits BlockAlignment,
- CodeGenModule &CGM) {
- std::string Str;
- ASTContext &Ctx = CGM.getContext();
- const BlockDecl::Capture &CI = *E.CI;
- QualType CaptureTy = CI.getVariable()->getType();
-
- BlockCaptureEntityKind Kind;
- BlockFieldFlags Flags;
-
- // CaptureStrKind::Merged should be passed only when the operations and the
- // flags are the same for copy and dispose.
- assert((StrKind != CaptureStrKind::Merged ||
- (E.CopyKind == E.DisposeKind && E.CopyFlags == E.DisposeFlags)) &&
- "different operations and flags");
-
- if (StrKind == CaptureStrKind::DisposeHelper) {
- Kind = E.DisposeKind;
- Flags = E.DisposeFlags;
- } else {
- Kind = E.CopyKind;
- Flags = E.CopyFlags;
- }
-
- switch (Kind) {
- case BlockCaptureEntityKind::CXXRecord: {
- Str += "c";
- SmallString<256> TyStr;
- llvm::raw_svector_ostream Out(TyStr);
- CGM.getCXXABI().getMangleContext().mangleTypeName(CaptureTy, Out);
- Str += llvm::to_string(TyStr.size()) + TyStr.c_str();
- break;
- }
- case BlockCaptureEntityKind::ARCWeak:
- Str += "w";
- break;
- case BlockCaptureEntityKind::ARCStrong:
- Str += "s";
- break;
- case BlockCaptureEntityKind::BlockObject: {
- const VarDecl *Var = CI.getVariable();
- unsigned F = Flags.getBitMask();
- if (F & BLOCK_FIELD_IS_BYREF) {
- Str += "r";
- if (F & BLOCK_FIELD_IS_WEAK)
- Str += "w";
- else {
- // If CaptureStrKind::Merged is passed, check both the copy expression
- // and the destructor.
- if (StrKind != CaptureStrKind::DisposeHelper) {
- if (Ctx.getBlockVarCopyInit(Var).canThrow())
- Str += "c";
- }
- if (StrKind != CaptureStrKind::CopyHelper) {
- if (CodeGenFunction::cxxDestructorCanThrow(CaptureTy))
- Str += "d";
- }
- }
- } else {
- assert((F & BLOCK_FIELD_IS_OBJECT) && "unexpected flag value");
- if (F == BLOCK_FIELD_IS_BLOCK)
- Str += "b";
- else
- Str += "o";
- }
- break;
- }
- case BlockCaptureEntityKind::NonTrivialCStruct: {
- bool IsVolatile = CaptureTy.isVolatileQualified();
- CharUnits Alignment =
- BlockAlignment.alignmentAtOffset(E.Capture->getOffset());
-
- Str += "n";
- std::string FuncStr;
- if (StrKind == CaptureStrKind::DisposeHelper)
- FuncStr = CodeGenFunction::getNonTrivialDestructorStr(
- CaptureTy, Alignment, IsVolatile, Ctx);
- else
- // If CaptureStrKind::Merged is passed, use the copy constructor string.
- // It has all the information that the destructor string has.
- FuncStr = CodeGenFunction::getNonTrivialCopyConstructorStr(
- CaptureTy, Alignment, IsVolatile, Ctx);
- // The underscore is necessary here because non-trivial copy constructor
- // and destructor strings can start with a number.
- Str += llvm::to_string(FuncStr.size()) + "_" + FuncStr;
- break;
- }
- case BlockCaptureEntityKind::None:
- break;
- }
-
- return Str;
-}
-
-static std::string getCopyDestroyHelperFuncName(
- const SmallVectorImpl<BlockCaptureManagedEntity> &Captures,
- CharUnits BlockAlignment, CaptureStrKind StrKind, CodeGenModule &CGM) {
- assert((StrKind == CaptureStrKind::CopyHelper ||
- StrKind == CaptureStrKind::DisposeHelper) &&
- "unexpected CaptureStrKind");
- std::string Name = StrKind == CaptureStrKind::CopyHelper
- ? "__copy_helper_block_"
- : "__destroy_helper_block_";
- if (CGM.getLangOpts().Exceptions)
- Name += "e";
- if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
- Name += "a";
- Name += llvm::to_string(BlockAlignment.getQuantity()) + "_";
-
- for (const BlockCaptureManagedEntity &E : Captures) {
- Name += llvm::to_string(E.Capture->getOffset().getQuantity());
- Name += getBlockCaptureStr(E, StrKind, BlockAlignment, CGM);
- }
-
- return Name;
-}
-
-static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
- Address Field, QualType CaptureType,
- BlockFieldFlags Flags, bool ForCopyHelper,
- VarDecl *Var, CodeGenFunction &CGF) {
- bool EHOnly = ForCopyHelper;
-
- switch (CaptureKind) {
- case BlockCaptureEntityKind::CXXRecord:
- case BlockCaptureEntityKind::ARCWeak:
- case BlockCaptureEntityKind::NonTrivialCStruct:
- case BlockCaptureEntityKind::ARCStrong: {
- if (CaptureType.isDestructedType() &&
- (!EHOnly || CGF.needsEHCleanup(CaptureType.isDestructedType()))) {
- CodeGenFunction::Destroyer *Destroyer =
- CaptureKind == BlockCaptureEntityKind::ARCStrong
- ? CodeGenFunction::destroyARCStrongImprecise
- : CGF.getDestroyer(CaptureType.isDestructedType());
- CleanupKind Kind =
- EHOnly ? EHCleanup
- : CGF.getCleanupKind(CaptureType.isDestructedType());
- CGF.pushDestroy(Kind, Field, CaptureType, Destroyer, Kind & EHCleanup);
- }
- break;
- }
- case BlockCaptureEntityKind::BlockObject: {
- if (!EHOnly || CGF.getLangOpts().Exceptions) {
- CleanupKind Kind = EHOnly ? EHCleanup : NormalAndEHCleanup;
- // Calls to _Block_object_dispose along the EH path in the copy helper
- // function don't throw as newly-copied __block variables always have a
- // reference count of 2.
- bool CanThrow =
- !ForCopyHelper && CGF.cxxDestructorCanThrow(CaptureType);
- CGF.enterByrefCleanup(Kind, Field, Flags, /*LoadBlockVarAddr*/ true,
- CanThrow);
- }
- break;
- }
- case BlockCaptureEntityKind::None:
- break;
- }
-}
-
-static void setBlockHelperAttributesVisibility(bool CapturesNonExternalType,
- llvm::Function *Fn,
- const CGFunctionInfo &FI,
- CodeGenModule &CGM) {
- if (CapturesNonExternalType) {
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
- } else {
- Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Fn->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, Fn);
- CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Fn);
- }
-}
-/// Generate the copy-helper function for a block closure object:
-/// static void block_copy_helper(block_t *dst, block_t *src);
-/// The runtime will have previously initialized 'dst' by doing a
-/// bit-copy of 'src'.
-///
-/// Note that this copies an entire block closure object to the heap;
-/// it should not be confused with a 'byref copy helper', which moves
-/// the contents of an individual __block variable to the heap.
-llvm::Constant *
-CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
- SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures);
- std::string FuncName =
- getCopyDestroyHelperFuncName(CopiedCaptures, blockInfo.BlockAlign,
- CaptureStrKind::CopyHelper, CGM);
-
- if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
- return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy);
-
- ASTContext &C = getContext();
-
- QualType ReturnTy = C.VoidTy;
-
- FunctionArgList args;
- ImplicitParamDecl DstDecl(C, C.VoidPtrTy, ImplicitParamDecl::Other);
- args.push_back(&DstDecl);
- ImplicitParamDecl SrcDecl(C, C.VoidPtrTy, ImplicitParamDecl::Other);
- args.push_back(&SrcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
-
- // FIXME: it would be nice if these were mergeable with things with
- // identical semantics.
- llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
-
- llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::LinkOnceODRLinkage,
- FuncName, &CGM.getModule());
-
- IdentifierInfo *II = &C.Idents.get(FuncName);
-
- SmallVector<QualType, 2> ArgTys;
- ArgTys.push_back(C.VoidPtrTy);
- ArgTys.push_back(C.VoidPtrTy);
- QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
-
- FunctionDecl *FD = FunctionDecl::Create(
- C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
- FunctionTy, nullptr, SC_Static, false, false);
-
- setBlockHelperAttributesVisibility(blockInfo.CapturesNonExternalType, Fn, FI,
- CGM);
- StartFunction(FD, ReturnTy, Fn, FI, args);
- ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getBeginLoc()};
- llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
-
- Address src = GetAddrOfLocalVar(&SrcDecl);
- src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign);
- src = Builder.CreateBitCast(src, structPtrTy, "block.source");
-
- Address dst = GetAddrOfLocalVar(&DstDecl);
- dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
- dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
-
- for (const auto &CopiedCapture : CopiedCaptures) {
- const BlockDecl::Capture &CI = *CopiedCapture.CI;
- const CGBlockInfo::Capture &capture = *CopiedCapture.Capture;
- QualType captureType = CI.getVariable()->getType();
- BlockFieldFlags flags = CopiedCapture.CopyFlags;
-
- unsigned index = capture.getIndex();
- Address srcField = Builder.CreateStructGEP(src, index, capture.getOffset());
- Address dstField = Builder.CreateStructGEP(dst, index, capture.getOffset());
-
- switch (CopiedCapture.CopyKind) {
- case BlockCaptureEntityKind::CXXRecord:
- // If there's an explicit copy expression, we do that.
- assert(CI.getCopyExpr() && "copy expression for variable is missing");
- EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr());
- break;
- case BlockCaptureEntityKind::ARCWeak:
- EmitARCCopyWeak(dstField, srcField);
- break;
- case BlockCaptureEntityKind::NonTrivialCStruct: {
- // If this is a C struct that requires non-trivial copy construction,
- // emit a call to its copy constructor.
- QualType varType = CI.getVariable()->getType();
- callCStructCopyConstructor(MakeAddrLValue(dstField, varType),
- MakeAddrLValue(srcField, varType));
- break;
- }
- case BlockCaptureEntityKind::ARCStrong: {
- llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
- // At -O0, store null into the destination field (so that the
- // storeStrong doesn't over-release) and then call storeStrong.
- // This is a workaround to not having an initStrong call.
- if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
- auto *ty = cast<llvm::PointerType>(srcValue->getType());
- llvm::Value *null = llvm::ConstantPointerNull::get(ty);
- Builder.CreateStore(null, dstField);
- EmitARCStoreStrongCall(dstField, srcValue, true);
-
- // With optimization enabled, take advantage of the fact that
- // the blocks runtime guarantees a memcpy of the block data, and
- // just emit a retain of the src field.
- } else {
- EmitARCRetainNonBlock(srcValue);
-
- // Unless EH cleanup is required, we don't need this anymore, so kill
- // it. It's not quite worth the annoyance to avoid creating it in the
- // first place.
- if (!needsEHCleanup(captureType.isDestructedType()))
- cast<llvm::Instruction>(dstField.getPointer())->eraseFromParent();
- }
- break;
- }
- case BlockCaptureEntityKind::BlockObject: {
- llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
- srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
- llvm::Value *dstAddr =
- Builder.CreateBitCast(dstField.getPointer(), VoidPtrTy);
- llvm::Value *args[] = {
- dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
- };
-
- if (CI.isByRef() && C.getBlockVarCopyInit(CI.getVariable()).canThrow())
- EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
- else
- EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
- break;
- }
- case BlockCaptureEntityKind::None:
- continue;
- }
-
- // Ensure that we destroy the copied object if an exception is thrown later
- // in the helper function.
- pushCaptureCleanup(CopiedCapture.CopyKind, dstField, captureType, flags,
- /*ForCopyHelper*/ true, CI.getVariable(), *this);
- }
-
- FinishFunction();
-
- return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
-}
-
-static BlockFieldFlags
-getBlockFieldFlagsForObjCObjectPointer(const BlockDecl::Capture &CI,
- QualType T) {
- BlockFieldFlags Flags = BLOCK_FIELD_IS_OBJECT;
- if (T->isBlockPointerType())
- Flags = BLOCK_FIELD_IS_BLOCK;
- return Flags;
-}
-
-static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
-computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
- const LangOptions &LangOpts) {
- if (CI.isEscapingByref()) {
- BlockFieldFlags Flags = BLOCK_FIELD_IS_BYREF;
- if (T.isObjCGCWeak())
- Flags |= BLOCK_FIELD_IS_WEAK;
- return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
- }
-
- switch (T.isDestructedType()) {
- case QualType::DK_cxx_destructor:
- return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags());
- case QualType::DK_objc_strong_lifetime:
- // Use objc_storeStrong for __strong direct captures; the
- // dynamic tools really like it when we do this.
- return std::make_pair(BlockCaptureEntityKind::ARCStrong,
- getBlockFieldFlagsForObjCObjectPointer(CI, T));
- case QualType::DK_objc_weak_lifetime:
- // Support __weak direct captures.
- return std::make_pair(BlockCaptureEntityKind::ARCWeak,
- getBlockFieldFlagsForObjCObjectPointer(CI, T));
- case QualType::DK_nontrivial_c_struct:
- return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct,
- BlockFieldFlags());
- case QualType::DK_none: {
- // Non-ARC captures are strong, and we need to use _Block_object_dispose.
- if (T->isObjCRetainableType() && !T.getQualifiers().hasObjCLifetime() &&
- !LangOpts.ObjCAutoRefCount)
- return std::make_pair(BlockCaptureEntityKind::BlockObject,
- getBlockFieldFlagsForObjCObjectPointer(CI, T));
- // Otherwise, we have nothing to do.
- return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags());
- }
- }
- llvm_unreachable("after exhaustive DestructionKind switch");
-}
-
-/// Generate the destroy-helper function for a block closure object:
-/// static void block_destroy_helper(block_t *theBlock);
-///
-/// Note that this destroys a heap-allocated block closure object;
-/// it should not be confused with a 'byref destroy helper', which
-/// destroys the heap-allocated contents of an individual __block
-/// variable.
-llvm::Constant *
-CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
- SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures);
- std::string FuncName =
- getCopyDestroyHelperFuncName(DestroyedCaptures, blockInfo.BlockAlign,
- CaptureStrKind::DisposeHelper, CGM);
-
- if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
- return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy);
-
- ASTContext &C = getContext();
-
- QualType ReturnTy = C.VoidTy;
-
- FunctionArgList args;
- ImplicitParamDecl SrcDecl(C, C.VoidPtrTy, ImplicitParamDecl::Other);
- args.push_back(&SrcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
-
- // FIXME: We'd like to put these into a mergable by content, with
- // internal linkage.
- llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
-
- llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::LinkOnceODRLinkage,
- FuncName, &CGM.getModule());
-
- IdentifierInfo *II = &C.Idents.get(FuncName);
-
- SmallVector<QualType, 1> ArgTys;
- ArgTys.push_back(C.VoidPtrTy);
- QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
-
- FunctionDecl *FD = FunctionDecl::Create(
- C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
- FunctionTy, nullptr, SC_Static, false, false);
-
- setBlockHelperAttributesVisibility(blockInfo.CapturesNonExternalType, Fn, FI,
- CGM);
- StartFunction(FD, ReturnTy, Fn, FI, args);
- markAsIgnoreThreadCheckingAtRuntime(Fn);
-
- ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getBeginLoc()};
-
- llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
-
- Address src = GetAddrOfLocalVar(&SrcDecl);
- src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign);
- src = Builder.CreateBitCast(src, structPtrTy, "block");
-
- CodeGenFunction::RunCleanupsScope cleanups(*this);
-
- for (const auto &DestroyedCapture : DestroyedCaptures) {
- const BlockDecl::Capture &CI = *DestroyedCapture.CI;
- const CGBlockInfo::Capture &capture = *DestroyedCapture.Capture;
- BlockFieldFlags flags = DestroyedCapture.DisposeFlags;
-
- Address srcField =
- Builder.CreateStructGEP(src, capture.getIndex(), capture.getOffset());
-
- pushCaptureCleanup(DestroyedCapture.DisposeKind, srcField,
- CI.getVariable()->getType(), flags,
- /*ForCopyHelper*/ false, CI.getVariable(), *this);
- }
-
- cleanups.ForceCleanup();
-
- FinishFunction();
-
- return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
-}
-
-namespace {
-
-/// Emits the copy/dispose helper functions for a __block object of id type.
-class ObjectByrefHelpers final : public BlockByrefHelpers {
- BlockFieldFlags Flags;
-
-public:
- ObjectByrefHelpers(CharUnits alignment, BlockFieldFlags flags)
- : BlockByrefHelpers(alignment), Flags(flags) {}
-
- void emitCopy(CodeGenFunction &CGF, Address destField,
- Address srcField) override {
- destField = CGF.Builder.CreateBitCast(destField, CGF.VoidPtrTy);
-
- srcField = CGF.Builder.CreateBitCast(srcField, CGF.VoidPtrPtrTy);
- llvm::Value *srcValue = CGF.Builder.CreateLoad(srcField);
-
- unsigned flags = (Flags | BLOCK_BYREF_CALLER).getBitMask();
-
- llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags);
- llvm::Value *fn = CGF.CGM.getBlockObjectAssign();
-
- llvm::Value *args[] = { destField.getPointer(), srcValue, flagsVal };
- CGF.EmitNounwindRuntimeCall(fn, args);
- }
-
- void emitDispose(CodeGenFunction &CGF, Address field) override {
- field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0));
- llvm::Value *value = CGF.Builder.CreateLoad(field);
-
- CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER, false);
- }
-
- void profileImpl(llvm::FoldingSetNodeID &id) const override {
- id.AddInteger(Flags.getBitMask());
- }
-};
-
-/// Emits the copy/dispose helpers for an ARC __block __weak variable.
-class ARCWeakByrefHelpers final : public BlockByrefHelpers {
-public:
- ARCWeakByrefHelpers(CharUnits alignment) : BlockByrefHelpers(alignment) {}
-
- void emitCopy(CodeGenFunction &CGF, Address destField,
- Address srcField) override {
- CGF.EmitARCMoveWeak(destField, srcField);
- }
-
- void emitDispose(CodeGenFunction &CGF, Address field) override {
- CGF.EmitARCDestroyWeak(field);
- }
-
- void profileImpl(llvm::FoldingSetNodeID &id) const override {
- // 0 is distinguishable from all pointers and byref flags
- id.AddInteger(0);
- }
-};
-
-/// Emits the copy/dispose helpers for an ARC __block __strong variable
-/// that's not of block-pointer type.
-class ARCStrongByrefHelpers final : public BlockByrefHelpers {
-public:
- ARCStrongByrefHelpers(CharUnits alignment) : BlockByrefHelpers(alignment) {}
-
- void emitCopy(CodeGenFunction &CGF, Address destField,
- Address srcField) override {
- // Do a "move" by copying the value and then zeroing out the old
- // variable.
-
- llvm::Value *value = CGF.Builder.CreateLoad(srcField);
-
- llvm::Value *null =
- llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType()));
-
- if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
- CGF.Builder.CreateStore(null, destField);
- CGF.EmitARCStoreStrongCall(destField, value, /*ignored*/ true);
- CGF.EmitARCStoreStrongCall(srcField, null, /*ignored*/ true);
- return;
- }
- CGF.Builder.CreateStore(value, destField);
- CGF.Builder.CreateStore(null, srcField);
- }
-
- void emitDispose(CodeGenFunction &CGF, Address field) override {
- CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
- }
-
- void profileImpl(llvm::FoldingSetNodeID &id) const override {
- // 1 is distinguishable from all pointers and byref flags
- id.AddInteger(1);
- }
-};
-
-/// Emits the copy/dispose helpers for an ARC __block __strong
-/// variable that's of block-pointer type.
-class ARCStrongBlockByrefHelpers final : public BlockByrefHelpers {
-public:
- ARCStrongBlockByrefHelpers(CharUnits alignment)
- : BlockByrefHelpers(alignment) {}
-
- void emitCopy(CodeGenFunction &CGF, Address destField,
- Address srcField) override {
- // Do the copy with objc_retainBlock; that's all that
- // _Block_object_assign would do anyway, and we'd have to pass the
- // right arguments to make sure it doesn't get no-op'ed.
- llvm::Value *oldValue = CGF.Builder.CreateLoad(srcField);
- llvm::Value *copy = CGF.EmitARCRetainBlock(oldValue, /*mandatory*/ true);
- CGF.Builder.CreateStore(copy, destField);
- }
-
- void emitDispose(CodeGenFunction &CGF, Address field) override {
- CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
- }
-
- void profileImpl(llvm::FoldingSetNodeID &id) const override {
- // 2 is distinguishable from all pointers and byref flags
- id.AddInteger(2);
- }
-};
-
-/// Emits the copy/dispose helpers for a __block variable with a
-/// nontrivial copy constructor or destructor.
-class CXXByrefHelpers final : public BlockByrefHelpers {
- QualType VarType;
- const Expr *CopyExpr;
-
-public:
- CXXByrefHelpers(CharUnits alignment, QualType type,
- const Expr *copyExpr)
- : BlockByrefHelpers(alignment), VarType(type), CopyExpr(copyExpr) {}
-
- bool needsCopy() const override { return CopyExpr != nullptr; }
- void emitCopy(CodeGenFunction &CGF, Address destField,
- Address srcField) override {
- if (!CopyExpr) return;
- CGF.EmitSynthesizedCXXCopyCtor(destField, srcField, CopyExpr);
- }
-
- void emitDispose(CodeGenFunction &CGF, Address field) override {
- EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin();
- CGF.PushDestructorCleanup(VarType, field);
- CGF.PopCleanupBlocks(cleanupDepth);
- }
-
- void profileImpl(llvm::FoldingSetNodeID &id) const override {
- id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
- }
-};
-
-/// Emits the copy/dispose helpers for a __block variable that is a non-trivial
-/// C struct.
-class NonTrivialCStructByrefHelpers final : public BlockByrefHelpers {
- QualType VarType;
-
-public:
- NonTrivialCStructByrefHelpers(CharUnits alignment, QualType type)
- : BlockByrefHelpers(alignment), VarType(type) {}
-
- void emitCopy(CodeGenFunction &CGF, Address destField,
- Address srcField) override {
- CGF.callCStructMoveConstructor(CGF.MakeAddrLValue(destField, VarType),
- CGF.MakeAddrLValue(srcField, VarType));
- }
-
- bool needsDispose() const override {
- return VarType.isDestructedType();
- }
-
- void emitDispose(CodeGenFunction &CGF, Address field) override {
- EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin();
- CGF.pushDestroy(VarType.isDestructedType(), field, VarType);
- CGF.PopCleanupBlocks(cleanupDepth);
- }
-
- void profileImpl(llvm::FoldingSetNodeID &id) const override {
- id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
- }
-};
-} // end anonymous namespace
-
-static llvm::Constant *
-generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo,
- BlockByrefHelpers &generator) {
- ASTContext &Context = CGF.getContext();
-
- QualType ReturnTy = Context.VoidTy;
-
- FunctionArgList args;
- ImplicitParamDecl Dst(Context, Context.VoidPtrTy, ImplicitParamDecl::Other);
- args.push_back(&Dst);
-
- ImplicitParamDecl Src(Context, Context.VoidPtrTy, ImplicitParamDecl::Other);
- args.push_back(&Src);
-
- const CGFunctionInfo &FI =
- CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
-
- llvm::FunctionType *LTy = CGF.CGM.getTypes().GetFunctionType(FI);
-
- // FIXME: We'd like to put these into a mergable by content, with
- // internal linkage.
- llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__Block_byref_object_copy_", &CGF.CGM.getModule());
-
- IdentifierInfo *II
- = &Context.Idents.get("__Block_byref_object_copy_");
-
- SmallVector<QualType, 2> ArgTys;
- ArgTys.push_back(Context.VoidPtrTy);
- ArgTys.push_back(Context.VoidPtrTy);
- QualType FunctionTy = Context.getFunctionType(ReturnTy, ArgTys, {});
-
- FunctionDecl *FD = FunctionDecl::Create(
- Context, Context.getTranslationUnitDecl(), SourceLocation(),
- SourceLocation(), II, FunctionTy, nullptr, SC_Static, false, false);
-
- CGF.CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
- CGF.StartFunction(FD, ReturnTy, Fn, FI, args);
-
- if (generator.needsCopy()) {
- llvm::Type *byrefPtrType = byrefInfo.Type->getPointerTo(0);
-
- // dst->x
- Address destField = CGF.GetAddrOfLocalVar(&Dst);
- destField = Address(CGF.Builder.CreateLoad(destField),
- byrefInfo.ByrefAlignment);
- destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
- destField = CGF.emitBlockByrefAddress(destField, byrefInfo, false,
- "dest-object");
-
- // src->x
- Address srcField = CGF.GetAddrOfLocalVar(&Src);
- srcField = Address(CGF.Builder.CreateLoad(srcField),
- byrefInfo.ByrefAlignment);
- srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
- srcField = CGF.emitBlockByrefAddress(srcField, byrefInfo, false,
- "src-object");
-
- generator.emitCopy(CGF, destField, srcField);
- }
-
- CGF.FinishFunction();
-
- return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
-}
-
-/// Build the copy helper for a __block variable.
-static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
- const BlockByrefInfo &byrefInfo,
- BlockByrefHelpers &generator) {
- CodeGenFunction CGF(CGM);
- return generateByrefCopyHelper(CGF, byrefInfo, generator);
-}
-
-/// Generate code for a __block variable's dispose helper.
-static llvm::Constant *
-generateByrefDisposeHelper(CodeGenFunction &CGF,
- const BlockByrefInfo &byrefInfo,
- BlockByrefHelpers &generator) {
- ASTContext &Context = CGF.getContext();
- QualType R = Context.VoidTy;
-
- FunctionArgList args;
- ImplicitParamDecl Src(CGF.getContext(), Context.VoidPtrTy,
- ImplicitParamDecl::Other);
- args.push_back(&Src);
-
- const CGFunctionInfo &FI =
- CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(R, args);
-
- llvm::FunctionType *LTy = CGF.CGM.getTypes().GetFunctionType(FI);
-
- // FIXME: We'd like to put these into a mergable by content, with
- // internal linkage.
- llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__Block_byref_object_dispose_",
- &CGF.CGM.getModule());
-
- IdentifierInfo *II
- = &Context.Idents.get("__Block_byref_object_dispose_");
-
- SmallVector<QualType, 1> ArgTys;
- ArgTys.push_back(Context.VoidPtrTy);
- QualType FunctionTy = Context.getFunctionType(R, ArgTys, {});
-
- FunctionDecl *FD = FunctionDecl::Create(
- Context, Context.getTranslationUnitDecl(), SourceLocation(),
- SourceLocation(), II, FunctionTy, nullptr, SC_Static, false, false);
-
- CGF.CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
- CGF.StartFunction(FD, R, Fn, FI, args);
-
- if (generator.needsDispose()) {
- Address addr = CGF.GetAddrOfLocalVar(&Src);
- addr = Address(CGF.Builder.CreateLoad(addr), byrefInfo.ByrefAlignment);
- auto byrefPtrType = byrefInfo.Type->getPointerTo(0);
- addr = CGF.Builder.CreateBitCast(addr, byrefPtrType);
- addr = CGF.emitBlockByrefAddress(addr, byrefInfo, false, "object");
-
- generator.emitDispose(CGF, addr);
- }
-
- CGF.FinishFunction();
-
- return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
-}
-
-/// Build the dispose helper for a __block variable.
-static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
- const BlockByrefInfo &byrefInfo,
- BlockByrefHelpers &generator) {
- CodeGenFunction CGF(CGM);
- return generateByrefDisposeHelper(CGF, byrefInfo, generator);
-}
-
-/// Lazily build the copy and dispose helpers for a __block variable
-/// with the given information.
-template <class T>
-static T *buildByrefHelpers(CodeGenModule &CGM, const BlockByrefInfo &byrefInfo,
- T &&generator) {
- llvm::FoldingSetNodeID id;
- generator.Profile(id);
-
- void *insertPos;
- BlockByrefHelpers *node
- = CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos);
- if (node) return static_cast<T*>(node);
-
- generator.CopyHelper = buildByrefCopyHelper(CGM, byrefInfo, generator);
- generator.DisposeHelper = buildByrefDisposeHelper(CGM, byrefInfo, generator);
-
- T *copy = new (CGM.getContext()) T(std::forward<T>(generator));
- CGM.ByrefHelpersCache.InsertNode(copy, insertPos);
- return copy;
-}
-
-/// Build the copy and dispose helpers for the given __block variable
-/// emission. Places the helpers in the global cache. Returns null
-/// if no helpers are required.
-BlockByrefHelpers *
-CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
- const AutoVarEmission &emission) {
- const VarDecl &var = *emission.Variable;
- assert(var.isEscapingByref() &&
- "only escaping __block variables need byref helpers");
-
- QualType type = var.getType();
-
- auto &byrefInfo = getBlockByrefInfo(&var);
-
- // The alignment we care about for the purposes of uniquing byref
- // helpers is the alignment of the actual byref value field.
- CharUnits valueAlignment =
- byrefInfo.ByrefAlignment.alignmentAtOffset(byrefInfo.FieldOffset);
-
- if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
- const Expr *copyExpr =
- CGM.getContext().getBlockVarCopyInit(&var).getCopyExpr();
- if (!copyExpr && record->hasTrivialDestructor()) return nullptr;
-
- return ::buildByrefHelpers(
- CGM, byrefInfo, CXXByrefHelpers(valueAlignment, type, copyExpr));
- }
-
- // If type is a non-trivial C struct type that is non-trivial to
- // destructly move or destroy, build the copy and dispose helpers.
- if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct ||
- type.isDestructedType() == QualType::DK_nontrivial_c_struct)
- return ::buildByrefHelpers(
- CGM, byrefInfo, NonTrivialCStructByrefHelpers(valueAlignment, type));
-
- // Otherwise, if we don't have a retainable type, there's nothing to do.
- // that the runtime does extra copies.
- if (!type->isObjCRetainableType()) return nullptr;
-
- Qualifiers qs = type.getQualifiers();
-
- // If we have lifetime, that dominates.
- if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
- switch (lifetime) {
- case Qualifiers::OCL_None: llvm_unreachable("impossible");
-
- // These are just bits as far as the runtime is concerned.
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- return nullptr;
-
- // Tell the runtime that this is ARC __weak, called by the
- // byref routines.
- case Qualifiers::OCL_Weak:
- return ::buildByrefHelpers(CGM, byrefInfo,
- ARCWeakByrefHelpers(valueAlignment));
-
- // ARC __strong __block variables need to be retained.
- case Qualifiers::OCL_Strong:
- // Block pointers need to be copied, and there's no direct
- // transfer possible.
- if (type->isBlockPointerType()) {
- return ::buildByrefHelpers(CGM, byrefInfo,
- ARCStrongBlockByrefHelpers(valueAlignment));
-
- // Otherwise, we transfer ownership of the retain from the stack
- // to the heap.
- } else {
- return ::buildByrefHelpers(CGM, byrefInfo,
- ARCStrongByrefHelpers(valueAlignment));
- }
- }
- llvm_unreachable("fell out of lifetime switch!");
- }
-
- BlockFieldFlags flags;
- if (type->isBlockPointerType()) {
- flags |= BLOCK_FIELD_IS_BLOCK;
- } else if (CGM.getContext().isObjCNSObjectType(type) ||
- type->isObjCObjectPointerType()) {
- flags |= BLOCK_FIELD_IS_OBJECT;
- } else {
- return nullptr;
- }
-
- if (type.isObjCGCWeak())
- flags |= BLOCK_FIELD_IS_WEAK;
-
- return ::buildByrefHelpers(CGM, byrefInfo,
- ObjectByrefHelpers(valueAlignment, flags));
-}
-
-Address CodeGenFunction::emitBlockByrefAddress(Address baseAddr,
- const VarDecl *var,
- bool followForward) {
- auto &info = getBlockByrefInfo(var);
- return emitBlockByrefAddress(baseAddr, info, followForward, var->getName());
-}
-
-Address CodeGenFunction::emitBlockByrefAddress(Address baseAddr,
- const BlockByrefInfo &info,
- bool followForward,
- const llvm::Twine &name) {
- // Chase the forwarding address if requested.
- if (followForward) {
- Address forwardingAddr =
- Builder.CreateStructGEP(baseAddr, 1, getPointerSize(), "forwarding");
- baseAddr = Address(Builder.CreateLoad(forwardingAddr), info.ByrefAlignment);
- }
-
- return Builder.CreateStructGEP(baseAddr, info.FieldIndex,
- info.FieldOffset, name);
-}
-
-/// BuildByrefInfo - This routine changes a __block variable declared as T x
-/// into:
-///
-/// struct {
-/// void *__isa;
-/// void *__forwarding;
-/// int32_t __flags;
-/// int32_t __size;
-/// void *__copy_helper; // only if needed
-/// void *__destroy_helper; // only if needed
-/// void *__byref_variable_layout;// only if needed
-/// char padding[X]; // only if needed
-/// T x;
-/// } x
-///
-const BlockByrefInfo &CodeGenFunction::getBlockByrefInfo(const VarDecl *D) {
- auto it = BlockByrefInfos.find(D);
- if (it != BlockByrefInfos.end())
- return it->second;
-
- llvm::StructType *byrefType =
- llvm::StructType::create(getLLVMContext(),
- "struct.__block_byref_" + D->getNameAsString());
-
- QualType Ty = D->getType();
-
- CharUnits size;
- SmallVector<llvm::Type *, 8> types;
-
- // void *__isa;
- types.push_back(Int8PtrTy);
- size += getPointerSize();
-
- // void *__forwarding;
- types.push_back(llvm::PointerType::getUnqual(byrefType));
- size += getPointerSize();
-
- // int32_t __flags;
- types.push_back(Int32Ty);
- size += CharUnits::fromQuantity(4);
-
- // int32_t __size;
- types.push_back(Int32Ty);
- size += CharUnits::fromQuantity(4);
-
- // Note that this must match *exactly* the logic in buildByrefHelpers.
- bool hasCopyAndDispose = getContext().BlockRequiresCopying(Ty, D);
- if (hasCopyAndDispose) {
- /// void *__copy_helper;
- types.push_back(Int8PtrTy);
- size += getPointerSize();
-
- /// void *__destroy_helper;
- types.push_back(Int8PtrTy);
- size += getPointerSize();
- }
-
- bool HasByrefExtendedLayout = false;
- Qualifiers::ObjCLifetime Lifetime;
- if (getContext().getByrefLifetime(Ty, Lifetime, HasByrefExtendedLayout) &&
- HasByrefExtendedLayout) {
- /// void *__byref_variable_layout;
- types.push_back(Int8PtrTy);
- size += CharUnits::fromQuantity(PointerSizeInBytes);
- }
-
- // T x;
- llvm::Type *varTy = ConvertTypeForMem(Ty);
-
- bool packed = false;
- CharUnits varAlign = getContext().getDeclAlign(D);
- CharUnits varOffset = size.alignTo(varAlign);
-
- // We may have to insert padding.
- if (varOffset != size) {
- llvm::Type *paddingTy =
- llvm::ArrayType::get(Int8Ty, (varOffset - size).getQuantity());
-
- types.push_back(paddingTy);
- size = varOffset;
-
- // Conversely, we might have to prevent LLVM from inserting padding.
- } else if (CGM.getDataLayout().getABITypeAlignment(varTy)
- > varAlign.getQuantity()) {
- packed = true;
- }
- types.push_back(varTy);
-
- byrefType->setBody(types, packed);
-
- BlockByrefInfo info;
- info.Type = byrefType;
- info.FieldIndex = types.size() - 1;
- info.FieldOffset = varOffset;
- info.ByrefAlignment = std::max(varAlign, getPointerAlign());
-
- auto pair = BlockByrefInfos.insert({D, info});
- assert(pair.second && "info was inserted recursively?");
- return pair.first->second;
-}
-
-/// Initialize the structural components of a __block variable, i.e.
-/// everything but the actual object.
-void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
- // Find the address of the local.
- Address addr = emission.Addr;
-
- // That's an alloca of the byref structure type.
- llvm::StructType *byrefType = cast<llvm::StructType>(
- cast<llvm::PointerType>(addr.getPointer()->getType())->getElementType());
-
- unsigned nextHeaderIndex = 0;
- CharUnits nextHeaderOffset;
- auto storeHeaderField = [&](llvm::Value *value, CharUnits fieldSize,
- const Twine &name) {
- auto fieldAddr = Builder.CreateStructGEP(addr, nextHeaderIndex,
- nextHeaderOffset, name);
- Builder.CreateStore(value, fieldAddr);
-
- nextHeaderIndex++;
- nextHeaderOffset += fieldSize;
- };
-
- // Build the byref helpers if necessary. This is null if we don't need any.
- BlockByrefHelpers *helpers = buildByrefHelpers(*byrefType, emission);
-
- const VarDecl &D = *emission.Variable;
- QualType type = D.getType();
-
- bool HasByrefExtendedLayout;
- Qualifiers::ObjCLifetime ByrefLifetime;
- bool ByRefHasLifetime =
- getContext().getByrefLifetime(type, ByrefLifetime, HasByrefExtendedLayout);
-
- llvm::Value *V;
-
- // Initialize the 'isa', which is just 0 or 1.
- int isa = 0;
- if (type.isObjCGCWeak())
- isa = 1;
- V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa");
- storeHeaderField(V, getPointerSize(), "byref.isa");
-
- // Store the address of the variable into its own forwarding pointer.
- storeHeaderField(addr.getPointer(), getPointerSize(), "byref.forwarding");
-
- // Blocks ABI:
- // c) the flags field is set to either 0 if no helper functions are
- // needed or BLOCK_BYREF_HAS_COPY_DISPOSE if they are,
- BlockFlags flags;
- if (helpers) flags |= BLOCK_BYREF_HAS_COPY_DISPOSE;
- if (ByRefHasLifetime) {
- if (HasByrefExtendedLayout) flags |= BLOCK_BYREF_LAYOUT_EXTENDED;
- else switch (ByrefLifetime) {
- case Qualifiers::OCL_Strong:
- flags |= BLOCK_BYREF_LAYOUT_STRONG;
- break;
- case Qualifiers::OCL_Weak:
- flags |= BLOCK_BYREF_LAYOUT_WEAK;
- break;
- case Qualifiers::OCL_ExplicitNone:
- flags |= BLOCK_BYREF_LAYOUT_UNRETAINED;
- break;
- case Qualifiers::OCL_None:
- if (!type->isObjCObjectPointerType() && !type->isBlockPointerType())
- flags |= BLOCK_BYREF_LAYOUT_NON_OBJECT;
- break;
- default:
- break;
- }
- if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- printf("\n Inline flag for BYREF variable layout (%d):", flags.getBitMask());
- if (flags & BLOCK_BYREF_HAS_COPY_DISPOSE)
- printf(" BLOCK_BYREF_HAS_COPY_DISPOSE");
- if (flags & BLOCK_BYREF_LAYOUT_MASK) {
- BlockFlags ThisFlag(flags.getBitMask() & BLOCK_BYREF_LAYOUT_MASK);
- if (ThisFlag == BLOCK_BYREF_LAYOUT_EXTENDED)
- printf(" BLOCK_BYREF_LAYOUT_EXTENDED");
- if (ThisFlag == BLOCK_BYREF_LAYOUT_STRONG)
- printf(" BLOCK_BYREF_LAYOUT_STRONG");
- if (ThisFlag == BLOCK_BYREF_LAYOUT_WEAK)
- printf(" BLOCK_BYREF_LAYOUT_WEAK");
- if (ThisFlag == BLOCK_BYREF_LAYOUT_UNRETAINED)
- printf(" BLOCK_BYREF_LAYOUT_UNRETAINED");
- if (ThisFlag == BLOCK_BYREF_LAYOUT_NON_OBJECT)
- printf(" BLOCK_BYREF_LAYOUT_NON_OBJECT");
- }
- printf("\n");
- }
- }
- storeHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
- getIntSize(), "byref.flags");
-
- CharUnits byrefSize = CGM.GetTargetTypeStoreSize(byrefType);
- V = llvm::ConstantInt::get(IntTy, byrefSize.getQuantity());
- storeHeaderField(V, getIntSize(), "byref.size");
-
- if (helpers) {
- storeHeaderField(helpers->CopyHelper, getPointerSize(),
- "byref.copyHelper");
- storeHeaderField(helpers->DisposeHelper, getPointerSize(),
- "byref.disposeHelper");
- }
-
- if (ByRefHasLifetime && HasByrefExtendedLayout) {
- auto layoutInfo = CGM.getObjCRuntime().BuildByrefLayout(CGM, type);
- storeHeaderField(layoutInfo, getPointerSize(), "byref.layout");
- }
-}
-
-void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags,
- bool CanThrow) {
- llvm::Value *F = CGM.getBlockObjectDispose();
- llvm::Value *args[] = {
- Builder.CreateBitCast(V, Int8PtrTy),
- llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
- };
-
- if (CanThrow)
- EmitRuntimeCallOrInvoke(F, args);
- else
- EmitNounwindRuntimeCall(F, args);
-}
-
-void CodeGenFunction::enterByrefCleanup(CleanupKind Kind, Address Addr,
- BlockFieldFlags Flags,
- bool LoadBlockVarAddr, bool CanThrow) {
- EHStack.pushCleanup<CallBlockRelease>(Kind, Addr, Flags, LoadBlockVarAddr,
- CanThrow);
-}
-
-/// Adjust the declaration of something from the blocks API.
-static void configureBlocksRuntimeObject(CodeGenModule &CGM,
- llvm::Constant *C) {
- auto *GV = cast<llvm::GlobalValue>(C->stripPointerCasts());
-
- if (CGM.getTarget().getTriple().isOSBinFormatCOFF()) {
- IdentifierInfo &II = CGM.getContext().Idents.get(C->getName());
- TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl();
- DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
-
- assert((isa<llvm::Function>(C->stripPointerCasts()) ||
- isa<llvm::GlobalVariable>(C->stripPointerCasts())) &&
- "expected Function or GlobalVariable");
-
- const NamedDecl *ND = nullptr;
- for (const auto &Result : DC->lookup(&II))
- if ((ND = dyn_cast<FunctionDecl>(Result)) ||
- (ND = dyn_cast<VarDecl>(Result)))
- break;
-
- // TODO: support static blocks runtime
- if (GV->isDeclaration() && (!ND || !ND->hasAttr<DLLExportAttr>())) {
- GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- } else {
- GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- }
- }
-
- if (CGM.getLangOpts().BlocksRuntimeOptional && GV->isDeclaration() &&
- GV->hasExternalLinkage())
- GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
-
- CGM.setDSOLocal(GV);
-}
-
-llvm::Constant *CodeGenModule::getBlockObjectDispose() {
- if (BlockObjectDispose)
- return BlockObjectDispose;
-
- llvm::Type *args[] = { Int8PtrTy, Int32Ty };
- llvm::FunctionType *fty
- = llvm::FunctionType::get(VoidTy, args, false);
- BlockObjectDispose = CreateRuntimeFunction(fty, "_Block_object_dispose");
- configureBlocksRuntimeObject(*this, BlockObjectDispose);
- return BlockObjectDispose;
-}
-
-llvm::Constant *CodeGenModule::getBlockObjectAssign() {
- if (BlockObjectAssign)
- return BlockObjectAssign;
-
- llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
- llvm::FunctionType *fty
- = llvm::FunctionType::get(VoidTy, args, false);
- BlockObjectAssign = CreateRuntimeFunction(fty, "_Block_object_assign");
- configureBlocksRuntimeObject(*this, BlockObjectAssign);
- return BlockObjectAssign;
-}
-
-llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
- if (NSConcreteGlobalBlock)
- return NSConcreteGlobalBlock;
-
- NSConcreteGlobalBlock = GetOrCreateLLVMGlobal("_NSConcreteGlobalBlock",
- Int8PtrTy->getPointerTo(),
- nullptr);
- configureBlocksRuntimeObject(*this, NSConcreteGlobalBlock);
- return NSConcreteGlobalBlock;
-}
-
-llvm::Constant *CodeGenModule::getNSConcreteStackBlock() {
- if (NSConcreteStackBlock)
- return NSConcreteStackBlock;
-
- NSConcreteStackBlock = GetOrCreateLLVMGlobal("_NSConcreteStackBlock",
- Int8PtrTy->getPointerTo(),
- nullptr);
- configureBlocksRuntimeObject(*this, NSConcreteStackBlock);
- return NSConcreteStackBlock;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.h b/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.h
deleted file mode 100644
index 3f9fc16d9b1..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGBlocks.h
+++ /dev/null
@@ -1,299 +0,0 @@
-//===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the internal state used for llvm translation for block literals.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
-#define LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
-
-#include "CGBuilder.h"
-#include "CGCall.h"
-#include "CGValue.h"
-#include "CodeGenFunction.h"
-#include "CodeGenTypes.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/TargetInfo.h"
-
-namespace llvm {
-class Constant;
-class Function;
-class GlobalValue;
-class DataLayout;
-class FunctionType;
-class PointerType;
-class Value;
-class LLVMContext;
-}
-
-namespace clang {
-namespace CodeGen {
-
-class CGBlockInfo;
-
-// Flags stored in __block variables.
-enum BlockByrefFlags {
- BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler
- BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler
- BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28),
- BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28),
- BLOCK_BYREF_LAYOUT_STRONG = (3 << 28),
- BLOCK_BYREF_LAYOUT_WEAK = (4 << 28),
- BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28)
-};
-
-enum BlockLiteralFlags {
- BLOCK_IS_NOESCAPE = (1 << 23),
- BLOCK_HAS_COPY_DISPOSE = (1 << 25),
- BLOCK_HAS_CXX_OBJ = (1 << 26),
- BLOCK_IS_GLOBAL = (1 << 28),
- BLOCK_USE_STRET = (1 << 29),
- BLOCK_HAS_SIGNATURE = (1 << 30),
- BLOCK_HAS_EXTENDED_LAYOUT = (1u << 31)
-};
-class BlockFlags {
- uint32_t flags;
-
-public:
- BlockFlags(uint32_t flags) : flags(flags) {}
- BlockFlags() : flags(0) {}
- BlockFlags(BlockLiteralFlags flag) : flags(flag) {}
- BlockFlags(BlockByrefFlags flag) : flags(flag) {}
-
- uint32_t getBitMask() const { return flags; }
- bool empty() const { return flags == 0; }
-
- friend BlockFlags operator|(BlockFlags l, BlockFlags r) {
- return BlockFlags(l.flags | r.flags);
- }
- friend BlockFlags &operator|=(BlockFlags &l, BlockFlags r) {
- l.flags |= r.flags;
- return l;
- }
- friend bool operator&(BlockFlags l, BlockFlags r) {
- return (l.flags & r.flags);
- }
- bool operator==(BlockFlags r) {
- return (flags == r.flags);
- }
-};
-inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {
- return BlockFlags(l) | BlockFlags(r);
-}
-
-enum BlockFieldFlag_t {
- BLOCK_FIELD_IS_OBJECT = 0x03, /* id, NSObject, __attribute__((NSObject)),
- block, ... */
- BLOCK_FIELD_IS_BLOCK = 0x07, /* a block variable */
-
- BLOCK_FIELD_IS_BYREF = 0x08, /* the on stack structure holding the __block
- variable */
- BLOCK_FIELD_IS_WEAK = 0x10, /* declared __weak, only used in byref copy
- helpers */
- BLOCK_FIELD_IS_ARC = 0x40, /* field has ARC-specific semantics */
- BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose
- support routines */
- BLOCK_BYREF_CURRENT_MAX = 256
-};
-
-class BlockFieldFlags {
- uint32_t flags;
-
- BlockFieldFlags(uint32_t flags) : flags(flags) {}
-public:
- BlockFieldFlags() : flags(0) {}
- BlockFieldFlags(BlockFieldFlag_t flag) : flags(flag) {}
-
- uint32_t getBitMask() const { return flags; }
- bool empty() const { return flags == 0; }
-
- /// Answers whether the flags indicate that this field is an object
- /// or block pointer that requires _Block_object_assign/dispose.
- bool isSpecialPointer() const { return flags & BLOCK_FIELD_IS_OBJECT; }
-
- friend BlockFieldFlags operator|(BlockFieldFlags l, BlockFieldFlags r) {
- return BlockFieldFlags(l.flags | r.flags);
- }
- friend BlockFieldFlags &operator|=(BlockFieldFlags &l, BlockFieldFlags r) {
- l.flags |= r.flags;
- return l;
- }
- friend bool operator&(BlockFieldFlags l, BlockFieldFlags r) {
- return (l.flags & r.flags);
- }
- bool operator==(BlockFieldFlags Other) const {
- return flags == Other.flags;
- }
-};
-inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {
- return BlockFieldFlags(l) | BlockFieldFlags(r);
-}
-
-/// Information about the layout of a __block variable.
-class BlockByrefInfo {
-public:
- llvm::StructType *Type;
- unsigned FieldIndex;
- CharUnits ByrefAlignment;
- CharUnits FieldOffset;
-};
-
-/// CGBlockInfo - Information to generate a block literal.
-class CGBlockInfo {
-public:
- /// Name - The name of the block, kindof.
- StringRef Name;
-
- /// The field index of 'this' within the block, if there is one.
- unsigned CXXThisIndex;
-
- class Capture {
- uintptr_t Data;
- EHScopeStack::stable_iterator Cleanup;
- CharUnits::QuantityType Offset;
-
- /// Type of the capture field. Normally, this is identical to the type of
- /// the capture's VarDecl, but can be different if there is an enclosing
- /// lambda.
- QualType FieldType;
-
- public:
- bool isIndex() const { return (Data & 1) != 0; }
- bool isConstant() const { return !isIndex(); }
-
- unsigned getIndex() const {
- assert(isIndex());
- return Data >> 1;
- }
- CharUnits getOffset() const {
- assert(isIndex());
- return CharUnits::fromQuantity(Offset);
- }
- EHScopeStack::stable_iterator getCleanup() const {
- assert(isIndex());
- return Cleanup;
- }
- void setCleanup(EHScopeStack::stable_iterator cleanup) {
- assert(isIndex());
- Cleanup = cleanup;
- }
-
- llvm::Value *getConstant() const {
- assert(isConstant());
- return reinterpret_cast<llvm::Value*>(Data);
- }
-
- QualType fieldType() const {
- return FieldType;
- }
-
- static Capture makeIndex(unsigned index, CharUnits offset,
- QualType FieldType) {
- Capture v;
- v.Data = (index << 1) | 1;
- v.Offset = offset.getQuantity();
- v.FieldType = FieldType;
- return v;
- }
-
- static Capture makeConstant(llvm::Value *value) {
- Capture v;
- v.Data = reinterpret_cast<uintptr_t>(value);
- return v;
- }
- };
-
- /// CanBeGlobal - True if the block can be global, i.e. it has
- /// no non-constant captures.
- bool CanBeGlobal : 1;
-
- /// True if the block has captures that would necessitate custom copy or
- /// dispose helper functions if the block were escaping.
- bool NeedsCopyDispose : 1;
-
- /// HasCXXObject - True if the block's custom copy/dispose functions
- /// need to be run even in GC mode.
- bool HasCXXObject : 1;
-
- /// UsesStret : True if the block uses an stret return. Mutable
- /// because it gets set later in the block-creation process.
- mutable bool UsesStret : 1;
-
- /// HasCapturedVariableLayout : True if block has captured variables
- /// and their layout meta-data has been generated.
- bool HasCapturedVariableLayout : 1;
-
- /// Indicates whether an object of a non-external C++ class is captured. This
- /// bit is used to determine the linkage of the block copy/destroy helper
- /// functions.
- bool CapturesNonExternalType : 1;
-
- /// The mapping of allocated indexes within the block.
- llvm::DenseMap<const VarDecl*, Capture> Captures;
-
- Address LocalAddress;
- llvm::StructType *StructureType;
- const BlockDecl *Block;
- const BlockExpr *BlockExpression;
- CharUnits BlockSize;
- CharUnits BlockAlign;
- CharUnits CXXThisOffset;
-
- // Offset of the gap caused by block header having a smaller
- // alignment than the alignment of the block descriptor. This
- // is the gap offset before the first capturued field.
- CharUnits BlockHeaderForcedGapOffset;
- // Gap size caused by aligning first field after block header.
- // This could be zero if no forced alignment is required.
- CharUnits BlockHeaderForcedGapSize;
-
- /// An instruction which dominates the full-expression that the
- /// block is inside.
- llvm::Instruction *DominatingIP;
-
- /// The next block in the block-info chain. Invalid if this block
- /// info is not part of the CGF's block-info chain, which is true
- /// if it corresponds to a global block or a block whose expression
- /// has been encountered.
- CGBlockInfo *NextBlockInfo;
-
- const Capture &getCapture(const VarDecl *var) const {
- return const_cast<CGBlockInfo*>(this)->getCapture(var);
- }
- Capture &getCapture(const VarDecl *var) {
- llvm::DenseMap<const VarDecl*, Capture>::iterator
- it = Captures.find(var);
- assert(it != Captures.end() && "no entry for variable!");
- return it->second;
- }
-
- const BlockDecl *getBlockDecl() const { return Block; }
- const BlockExpr *getBlockExpr() const {
- assert(BlockExpression);
- assert(BlockExpression->getBlockDecl() == Block);
- return BlockExpression;
- }
-
- CGBlockInfo(const BlockDecl *blockDecl, StringRef Name);
-
- // Indicates whether the block needs a custom copy or dispose function.
- bool needsCopyDisposeHelpers() const {
- return NeedsCopyDispose && !Block->doesNotEscape();
- }
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGBuilder.h b/gnu/llvm/tools/clang/lib/CodeGen/CGBuilder.h
deleted file mode 100644
index 654ef72060b..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGBuilder.h
+++ /dev/null
@@ -1,306 +0,0 @@
-//===-- CGBuilder.h - Choose IRBuilder implementation ----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
-#define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
-
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/IRBuilder.h"
-#include "Address.h"
-#include "CodeGenTypeCache.h"
-
-namespace clang {
-namespace CodeGen {
-
-class CodeGenFunction;
-
-/// This is an IRBuilder insertion helper that forwards to
-/// CodeGenFunction::InsertHelper, which adds necessary metadata to
-/// instructions.
-class CGBuilderInserter : protected llvm::IRBuilderDefaultInserter {
-public:
- CGBuilderInserter() = default;
- explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {}
-
-protected:
- /// This forwards to CodeGenFunction::InsertHelper.
- void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
- llvm::BasicBlock *BB,
- llvm::BasicBlock::iterator InsertPt) const;
-private:
- CodeGenFunction *CGF = nullptr;
-};
-
-typedef CGBuilderInserter CGBuilderInserterTy;
-
-typedef llvm::IRBuilder<llvm::ConstantFolder, CGBuilderInserterTy>
- CGBuilderBaseTy;
-
-class CGBuilderTy : public CGBuilderBaseTy {
- /// Storing a reference to the type cache here makes it a lot easier
- /// to build natural-feeling, target-specific IR.
- const CodeGenTypeCache &TypeCache;
-public:
- CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::LLVMContext &C)
- : CGBuilderBaseTy(C), TypeCache(TypeCache) {}
- CGBuilderTy(const CodeGenTypeCache &TypeCache,
- llvm::LLVMContext &C, const llvm::ConstantFolder &F,
- const CGBuilderInserterTy &Inserter)
- : CGBuilderBaseTy(C, F, Inserter), TypeCache(TypeCache) {}
- CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::Instruction *I)
- : CGBuilderBaseTy(I), TypeCache(TypeCache) {}
- CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::BasicBlock *BB)
- : CGBuilderBaseTy(BB), TypeCache(TypeCache) {}
-
- llvm::ConstantInt *getSize(CharUnits N) {
- return llvm::ConstantInt::get(TypeCache.SizeTy, N.getQuantity());
- }
- llvm::ConstantInt *getSize(uint64_t N) {
- return llvm::ConstantInt::get(TypeCache.SizeTy, N);
- }
-
- // Note that we intentionally hide the CreateLoad APIs that don't
- // take an alignment.
- llvm::LoadInst *CreateLoad(Address Addr, const llvm::Twine &Name = "") {
- return CreateAlignedLoad(Addr.getPointer(),
- Addr.getAlignment().getQuantity(),
- Name);
- }
- llvm::LoadInst *CreateLoad(Address Addr, const char *Name) {
- // This overload is required to prevent string literals from
- // ending up in the IsVolatile overload.
- return CreateAlignedLoad(Addr.getPointer(),
- Addr.getAlignment().getQuantity(),
- Name);
- }
- llvm::LoadInst *CreateLoad(Address Addr, bool IsVolatile,
- const llvm::Twine &Name = "") {
- return CreateAlignedLoad(Addr.getPointer(),
- Addr.getAlignment().getQuantity(),
- IsVolatile,
- Name);
- }
-
- using CGBuilderBaseTy::CreateAlignedLoad;
- llvm::LoadInst *CreateAlignedLoad(llvm::Value *Addr, CharUnits Align,
- const llvm::Twine &Name = "") {
- return CreateAlignedLoad(Addr, Align.getQuantity(), Name);
- }
- llvm::LoadInst *CreateAlignedLoad(llvm::Value *Addr, CharUnits Align,
- const char *Name) {
- return CreateAlignedLoad(Addr, Align.getQuantity(), Name);
- }
- llvm::LoadInst *CreateAlignedLoad(llvm::Type *Ty, llvm::Value *Addr,
- CharUnits Align,
- const llvm::Twine &Name = "") {
- assert(Addr->getType()->getPointerElementType() == Ty);
- return CreateAlignedLoad(Addr, Align.getQuantity(), Name);
- }
-
- // Note that we intentionally hide the CreateStore APIs that don't
- // take an alignment.
- llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr,
- bool IsVolatile = false) {
- return CreateAlignedStore(Val, Addr.getPointer(),
- Addr.getAlignment().getQuantity(), IsVolatile);
- }
-
- using CGBuilderBaseTy::CreateAlignedStore;
- llvm::StoreInst *CreateAlignedStore(llvm::Value *Val, llvm::Value *Addr,
- CharUnits Align, bool IsVolatile = false) {
- return CreateAlignedStore(Val, Addr, Align.getQuantity(), IsVolatile);
- }
-
- // FIXME: these "default-aligned" APIs should be removed,
- // but I don't feel like fixing all the builtin code right now.
- llvm::StoreInst *CreateDefaultAlignedStore(llvm::Value *Val,
- llvm::Value *Addr,
- bool IsVolatile = false) {
- return CGBuilderBaseTy::CreateStore(Val, Addr, IsVolatile);
- }
-
- /// Emit a load from an i1 flag variable.
- llvm::LoadInst *CreateFlagLoad(llvm::Value *Addr,
- const llvm::Twine &Name = "") {
- assert(Addr->getType()->getPointerElementType() == getInt1Ty());
- return CreateAlignedLoad(getInt1Ty(), Addr, CharUnits::One(), Name);
- }
-
- /// Emit a store to an i1 flag variable.
- llvm::StoreInst *CreateFlagStore(bool Value, llvm::Value *Addr) {
- assert(Addr->getType()->getPointerElementType() == getInt1Ty());
- return CreateAlignedStore(getInt1(Value), Addr, CharUnits::One());
- }
-
- using CGBuilderBaseTy::CreateBitCast;
- Address CreateBitCast(Address Addr, llvm::Type *Ty,
- const llvm::Twine &Name = "") {
- return Address(CreateBitCast(Addr.getPointer(), Ty, Name),
- Addr.getAlignment());
- }
-
- using CGBuilderBaseTy::CreateAddrSpaceCast;
- Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty,
- const llvm::Twine &Name = "") {
- return Address(CreateAddrSpaceCast(Addr.getPointer(), Ty, Name),
- Addr.getAlignment());
- }
-
- /// Cast the element type of the given address to a different type,
- /// preserving information like the alignment and address space.
- Address CreateElementBitCast(Address Addr, llvm::Type *Ty,
- const llvm::Twine &Name = "") {
- auto PtrTy = Ty->getPointerTo(Addr.getAddressSpace());
- return CreateBitCast(Addr, PtrTy, Name);
- }
-
- using CGBuilderBaseTy::CreatePointerBitCastOrAddrSpaceCast;
- Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty,
- const llvm::Twine &Name = "") {
- llvm::Value *Ptr =
- CreatePointerBitCastOrAddrSpaceCast(Addr.getPointer(), Ty, Name);
- return Address(Ptr, Addr.getAlignment());
- }
-
- using CGBuilderBaseTy::CreateStructGEP;
- Address CreateStructGEP(Address Addr, unsigned Index, CharUnits Offset,
- const llvm::Twine &Name = "") {
- return Address(CreateStructGEP(Addr.getElementType(),
- Addr.getPointer(), Index, Name),
- Addr.getAlignment().alignmentAtOffset(Offset));
- }
- Address CreateStructGEP(Address Addr, unsigned Index,
- const llvm::StructLayout *Layout,
- const llvm::Twine &Name = "") {
- auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index));
- return CreateStructGEP(Addr, Index, Offset, Name);
- }
-
- /// Given
- /// %addr = [n x T]* ...
- /// produce
- /// %name = getelementptr inbounds %addr, i64 0, i64 index
- /// where i64 is actually the target word size.
- ///
- /// This API assumes that drilling into an array like this is always
- /// an inbounds operation.
- ///
- /// \param EltSize - the size of the type T in bytes
- Address CreateConstArrayGEP(Address Addr, uint64_t Index, CharUnits EltSize,
- const llvm::Twine &Name = "") {
- return Address(CreateInBoundsGEP(Addr.getPointer(),
- {getSize(CharUnits::Zero()),
- getSize(Index)},
- Name),
- Addr.getAlignment().alignmentAtOffset(Index * EltSize));
- }
-
- /// Given
- /// %addr = T* ...
- /// produce
- /// %name = getelementptr inbounds %addr, i64 index
- /// where i64 is actually the target word size.
- ///
- /// \param EltSize - the size of the type T in bytes
- Address CreateConstInBoundsGEP(Address Addr, uint64_t Index,
- CharUnits EltSize,
- const llvm::Twine &Name = "") {
- return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(),
- getSize(Index), Name),
- Addr.getAlignment().alignmentAtOffset(Index * EltSize));
- }
-
- /// Given
- /// %addr = T* ...
- /// produce
- /// %name = getelementptr inbounds %addr, i64 index
- /// where i64 is actually the target word size.
- ///
- /// \param EltSize - the size of the type T in bytes
- Address CreateConstGEP(Address Addr, uint64_t Index, CharUnits EltSize,
- const llvm::Twine &Name = "") {
- return Address(CreateGEP(Addr.getElementType(), Addr.getPointer(),
- getSize(Index), Name),
- Addr.getAlignment().alignmentAtOffset(Index * EltSize));
- }
-
- /// Given a pointer to i8, adjust it by a given constant offset.
- Address CreateConstInBoundsByteGEP(Address Addr, CharUnits Offset,
- const llvm::Twine &Name = "") {
- assert(Addr.getElementType() == TypeCache.Int8Ty);
- return Address(CreateInBoundsGEP(Addr.getPointer(), getSize(Offset), Name),
- Addr.getAlignment().alignmentAtOffset(Offset));
- }
- Address CreateConstByteGEP(Address Addr, CharUnits Offset,
- const llvm::Twine &Name = "") {
- assert(Addr.getElementType() == TypeCache.Int8Ty);
- return Address(CreateGEP(Addr.getPointer(), getSize(Offset), Name),
- Addr.getAlignment().alignmentAtOffset(Offset));
- }
-
- using CGBuilderBaseTy::CreateConstInBoundsGEP2_32;
- Address CreateConstInBoundsGEP2_32(Address Addr, unsigned Idx0,
- unsigned Idx1, const llvm::DataLayout &DL,
- const llvm::Twine &Name = "") {
- auto *GEP = cast<llvm::GetElementPtrInst>(CreateConstInBoundsGEP2_32(
- Addr.getElementType(), Addr.getPointer(), Idx0, Idx1, Name));
- llvm::APInt Offset(
- DL.getIndexSizeInBits(Addr.getType()->getPointerAddressSpace()), 0,
- /*IsSigned=*/true);
- if (!GEP->accumulateConstantOffset(DL, Offset))
- llvm_unreachable("offset of GEP with constants is always computable");
- return Address(GEP, Addr.getAlignment().alignmentAtOffset(
- CharUnits::fromQuantity(Offset.getSExtValue())));
- }
-
- llvm::Value *CreateConstInBoundsByteGEP(llvm::Value *Ptr, CharUnits Offset,
- const llvm::Twine &Name = "") {
- assert(Ptr->getType()->getPointerElementType() == TypeCache.Int8Ty);
- return CreateInBoundsGEP(Ptr, getSize(Offset), Name);
- }
- llvm::Value *CreateConstByteGEP(llvm::Value *Ptr, CharUnits Offset,
- const llvm::Twine &Name = "") {
- assert(Ptr->getType()->getPointerElementType() == TypeCache.Int8Ty);
- return CreateGEP(Ptr, getSize(Offset), Name);
- }
-
- using CGBuilderBaseTy::CreateMemCpy;
- llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size,
- bool IsVolatile = false) {
- return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(),
- Src.getPointer(), Src.getAlignment().getQuantity(),
- Size,IsVolatile);
- }
- llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size,
- bool IsVolatile = false) {
- return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(),
- Src.getPointer(), Src.getAlignment().getQuantity(),
- Size, IsVolatile);
- }
-
- using CGBuilderBaseTy::CreateMemMove;
- llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size,
- bool IsVolatile = false) {
- return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getQuantity(),
- Src.getPointer(), Src.getAlignment().getQuantity(),
- Size, IsVolatile);
- }
-
- using CGBuilderBaseTy::CreateMemSet;
- llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value,
- llvm::Value *Size, bool IsVolatile = false) {
- return CreateMemSet(Dest.getPointer(), Value, Size,
- Dest.getAlignment().getQuantity(), IsVolatile);
- }
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp
deleted file mode 100644
index ccc657493b2..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp
+++ /dev/null
@@ -1,13508 +0,0 @@
-//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Builtin calls as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
-#include "CGOpenCLRuntime.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "ConstantEmitter.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/OSLog.h"
-#include "clang/Basic/TargetBuiltins.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/TargetParser.h"
-#include <sstream>
-
-using namespace clang;
-using namespace CodeGen;
-using namespace llvm;
-
-static
-int64_t clamp(int64_t Value, int64_t Low, int64_t High) {
- return std::min(High, std::max(Low, Value));
-}
-
-/// getBuiltinLibFunction - Given a builtin id for a function like
-/// "__builtin_fabsf", return a Function* for "fabsf".
-llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
- unsigned BuiltinID) {
- assert(Context.BuiltinInfo.isLibFunction(BuiltinID));
-
- // Get the name, skip over the __builtin_ prefix (if necessary).
- StringRef Name;
- GlobalDecl D(FD);
-
- // If the builtin has been declared explicitly with an assembler label,
- // use the mangled name. This differs from the plain label on platforms
- // that prefix labels.
- if (FD->hasAttr<AsmLabelAttr>())
- Name = getMangledName(D);
- else
- Name = Context.BuiltinInfo.getName(BuiltinID) + 10;
-
- llvm::FunctionType *Ty =
- cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
-
- return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false);
-}
-
-/// Emit the conversions required to turn the given value into an
-/// integer of the given size.
-static Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V,
- QualType T, llvm::IntegerType *IntType) {
- V = CGF.EmitToMemory(V, T);
-
- if (V->getType()->isPointerTy())
- return CGF.Builder.CreatePtrToInt(V, IntType);
-
- assert(V->getType() == IntType);
- return V;
-}
-
-static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V,
- QualType T, llvm::Type *ResultType) {
- V = CGF.EmitFromMemory(V, T);
-
- if (ResultType->isPointerTy())
- return CGF.Builder.CreateIntToPtr(V, ResultType);
-
- assert(V->getType() == ResultType);
- return V;
-}
-
-/// Utility to insert an atomic instruction based on Intrinsic::ID
-/// and the expression node.
-static Value *MakeBinaryAtomicValue(
- CodeGenFunction &CGF, llvm::AtomicRMWInst::BinOp Kind, const CallExpr *E,
- AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent) {
- QualType T = E->getType();
- assert(E->getArg(0)->getType()->isPointerType());
- assert(CGF.getContext().hasSameUnqualifiedType(T,
- E->getArg(0)->getType()->getPointeeType()));
- assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
-
- llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
-
- llvm::IntegerType *IntType =
- llvm::IntegerType::get(CGF.getLLVMContext(),
- CGF.getContext().getTypeSize(T));
- llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
-
- llvm::Value *Args[2];
- Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType);
- Args[1] = CGF.EmitScalarExpr(E->getArg(1));
- llvm::Type *ValueType = Args[1]->getType();
- Args[1] = EmitToInt(CGF, Args[1], T, IntType);
-
- llvm::Value *Result = CGF.Builder.CreateAtomicRMW(
- Kind, Args[0], Args[1], Ordering);
- return EmitFromInt(CGF, Result, T, ValueType);
-}
-
-static Value *EmitNontemporalStore(CodeGenFunction &CGF, const CallExpr *E) {
- Value *Val = CGF.EmitScalarExpr(E->getArg(0));
- Value *Address = CGF.EmitScalarExpr(E->getArg(1));
-
- // Convert the type of the pointer to a pointer to the stored type.
- Val = CGF.EmitToMemory(Val, E->getArg(0)->getType());
- Value *BC = CGF.Builder.CreateBitCast(
- Address, llvm::PointerType::getUnqual(Val->getType()), "cast");
- LValue LV = CGF.MakeNaturalAlignAddrLValue(BC, E->getArg(0)->getType());
- LV.setNontemporal(true);
- CGF.EmitStoreOfScalar(Val, LV, false);
- return nullptr;
-}
-
-static Value *EmitNontemporalLoad(CodeGenFunction &CGF, const CallExpr *E) {
- Value *Address = CGF.EmitScalarExpr(E->getArg(0));
-
- LValue LV = CGF.MakeNaturalAlignAddrLValue(Address, E->getType());
- LV.setNontemporal(true);
- return CGF.EmitLoadOfScalar(LV, E->getExprLoc());
-}
-
-static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
- llvm::AtomicRMWInst::BinOp Kind,
- const CallExpr *E) {
- return RValue::get(MakeBinaryAtomicValue(CGF, Kind, E));
-}
-
-/// Utility to insert an atomic instruction based Intrinsic::ID and
-/// the expression node, where the return value is the result of the
-/// operation.
-static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
- llvm::AtomicRMWInst::BinOp Kind,
- const CallExpr *E,
- Instruction::BinaryOps Op,
- bool Invert = false) {
- QualType T = E->getType();
- assert(E->getArg(0)->getType()->isPointerType());
- assert(CGF.getContext().hasSameUnqualifiedType(T,
- E->getArg(0)->getType()->getPointeeType()));
- assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
-
- llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
-
- llvm::IntegerType *IntType =
- llvm::IntegerType::get(CGF.getLLVMContext(),
- CGF.getContext().getTypeSize(T));
- llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
-
- llvm::Value *Args[2];
- Args[1] = CGF.EmitScalarExpr(E->getArg(1));
- llvm::Type *ValueType = Args[1]->getType();
- Args[1] = EmitToInt(CGF, Args[1], T, IntType);
- Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType);
-
- llvm::Value *Result = CGF.Builder.CreateAtomicRMW(
- Kind, Args[0], Args[1], llvm::AtomicOrdering::SequentiallyConsistent);
- Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]);
- if (Invert)
- Result = CGF.Builder.CreateBinOp(llvm::Instruction::Xor, Result,
- llvm::ConstantInt::get(IntType, -1));
- Result = EmitFromInt(CGF, Result, T, ValueType);
- return RValue::get(Result);
-}
-
-/// Utility to insert an atomic cmpxchg instruction.
-///
-/// @param CGF The current codegen function.
-/// @param E Builtin call expression to convert to cmpxchg.
-/// arg0 - address to operate on
-/// arg1 - value to compare with
-/// arg2 - new value
-/// @param ReturnBool Specifies whether to return success flag of
-/// cmpxchg result or the old value.
-///
-/// @returns result of cmpxchg, according to ReturnBool
-///
-/// Note: In order to lower Microsoft's _InterlockedCompareExchange* intrinsics
-/// invoke the function EmitAtomicCmpXchgForMSIntrin.
-static Value *MakeAtomicCmpXchgValue(CodeGenFunction &CGF, const CallExpr *E,
- bool ReturnBool) {
- QualType T = ReturnBool ? E->getArg(1)->getType() : E->getType();
- llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
-
- llvm::IntegerType *IntType = llvm::IntegerType::get(
- CGF.getLLVMContext(), CGF.getContext().getTypeSize(T));
- llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
-
- Value *Args[3];
- Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType);
- Args[1] = CGF.EmitScalarExpr(E->getArg(1));
- llvm::Type *ValueType = Args[1]->getType();
- Args[1] = EmitToInt(CGF, Args[1], T, IntType);
- Args[2] = EmitToInt(CGF, CGF.EmitScalarExpr(E->getArg(2)), T, IntType);
-
- Value *Pair = CGF.Builder.CreateAtomicCmpXchg(
- Args[0], Args[1], Args[2], llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::AtomicOrdering::SequentiallyConsistent);
- if (ReturnBool)
- // Extract boolean success flag and zext it to int.
- return CGF.Builder.CreateZExt(CGF.Builder.CreateExtractValue(Pair, 1),
- CGF.ConvertType(E->getType()));
- else
- // Extract old value and emit it using the same type as compare value.
- return EmitFromInt(CGF, CGF.Builder.CreateExtractValue(Pair, 0), T,
- ValueType);
-}
-
-/// This function should be invoked to emit atomic cmpxchg for Microsoft's
-/// _InterlockedCompareExchange* intrinsics which have the following signature:
-/// T _InterlockedCompareExchange(T volatile *Destination,
-/// T Exchange,
-/// T Comparand);
-///
-/// Whereas the llvm 'cmpxchg' instruction has the following syntax:
-/// cmpxchg *Destination, Comparand, Exchange.
-/// So we need to swap Comparand and Exchange when invoking
-/// CreateAtomicCmpXchg. That is the reason we could not use the above utility
-/// function MakeAtomicCmpXchgValue since it expects the arguments to be
-/// already swapped.
-
-static
-Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,
- AtomicOrdering SuccessOrdering = AtomicOrdering::SequentiallyConsistent) {
- assert(E->getArg(0)->getType()->isPointerType());
- assert(CGF.getContext().hasSameUnqualifiedType(
- E->getType(), E->getArg(0)->getType()->getPointeeType()));
- assert(CGF.getContext().hasSameUnqualifiedType(E->getType(),
- E->getArg(1)->getType()));
- assert(CGF.getContext().hasSameUnqualifiedType(E->getType(),
- E->getArg(2)->getType()));
-
- auto *Destination = CGF.EmitScalarExpr(E->getArg(0));
- auto *Comparand = CGF.EmitScalarExpr(E->getArg(2));
- auto *Exchange = CGF.EmitScalarExpr(E->getArg(1));
-
- // For Release ordering, the failure ordering should be Monotonic.
- auto FailureOrdering = SuccessOrdering == AtomicOrdering::Release ?
- AtomicOrdering::Monotonic :
- SuccessOrdering;
-
- auto *Result = CGF.Builder.CreateAtomicCmpXchg(
- Destination, Comparand, Exchange,
- SuccessOrdering, FailureOrdering);
- Result->setVolatile(true);
- return CGF.Builder.CreateExtractValue(Result, 0);
-}
-
-static Value *EmitAtomicIncrementValue(CodeGenFunction &CGF, const CallExpr *E,
- AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent) {
- assert(E->getArg(0)->getType()->isPointerType());
-
- auto *IntTy = CGF.ConvertType(E->getType());
- auto *Result = CGF.Builder.CreateAtomicRMW(
- AtomicRMWInst::Add,
- CGF.EmitScalarExpr(E->getArg(0)),
- ConstantInt::get(IntTy, 1),
- Ordering);
- return CGF.Builder.CreateAdd(Result, ConstantInt::get(IntTy, 1));
-}
-
-static Value *EmitAtomicDecrementValue(CodeGenFunction &CGF, const CallExpr *E,
- AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent) {
- assert(E->getArg(0)->getType()->isPointerType());
-
- auto *IntTy = CGF.ConvertType(E->getType());
- auto *Result = CGF.Builder.CreateAtomicRMW(
- AtomicRMWInst::Sub,
- CGF.EmitScalarExpr(E->getArg(0)),
- ConstantInt::get(IntTy, 1),
- Ordering);
- return CGF.Builder.CreateSub(Result, ConstantInt::get(IntTy, 1));
-}
-
-// Emit a simple mangled intrinsic that has 1 argument and a return type
-// matching the argument type.
-static Value *emitUnaryBuiltin(CodeGenFunction &CGF,
- const CallExpr *E,
- unsigned IntrinsicID) {
- llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
-
- Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
- return CGF.Builder.CreateCall(F, Src0);
-}
-
-// Emit an intrinsic that has 2 operands of the same type as its result.
-static Value *emitBinaryBuiltin(CodeGenFunction &CGF,
- const CallExpr *E,
- unsigned IntrinsicID) {
- llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
- llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
-
- Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
- return CGF.Builder.CreateCall(F, { Src0, Src1 });
-}
-
-// Emit an intrinsic that has 3 operands of the same type as its result.
-static Value *emitTernaryBuiltin(CodeGenFunction &CGF,
- const CallExpr *E,
- unsigned IntrinsicID) {
- llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
- llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
- llvm::Value *Src2 = CGF.EmitScalarExpr(E->getArg(2));
-
- Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
- return CGF.Builder.CreateCall(F, { Src0, Src1, Src2 });
-}
-
-// Emit an intrinsic that has 1 float or double operand, and 1 integer.
-static Value *emitFPIntBuiltin(CodeGenFunction &CGF,
- const CallExpr *E,
- unsigned IntrinsicID) {
- llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
- llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
-
- Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
- return CGF.Builder.CreateCall(F, {Src0, Src1});
-}
-
-/// EmitFAbs - Emit a call to @llvm.fabs().
-static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) {
- Value *F = CGF.CGM.getIntrinsic(Intrinsic::fabs, V->getType());
- llvm::CallInst *Call = CGF.Builder.CreateCall(F, V);
- Call->setDoesNotAccessMemory();
- return Call;
-}
-
-/// Emit the computation of the sign bit for a floating point value. Returns
-/// the i1 sign bit value.
-static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) {
- LLVMContext &C = CGF.CGM.getLLVMContext();
-
- llvm::Type *Ty = V->getType();
- int Width = Ty->getPrimitiveSizeInBits();
- llvm::Type *IntTy = llvm::IntegerType::get(C, Width);
- V = CGF.Builder.CreateBitCast(V, IntTy);
- if (Ty->isPPC_FP128Ty()) {
- // We want the sign bit of the higher-order double. The bitcast we just
- // did works as if the double-double was stored to memory and then
- // read as an i128. The "store" will put the higher-order double in the
- // lower address in both little- and big-Endian modes, but the "load"
- // will treat those bits as a different part of the i128: the low bits in
- // little-Endian, the high bits in big-Endian. Therefore, on big-Endian
- // we need to shift the high bits down to the low before truncating.
- Width >>= 1;
- if (CGF.getTarget().isBigEndian()) {
- Value *ShiftCst = llvm::ConstantInt::get(IntTy, Width);
- V = CGF.Builder.CreateLShr(V, ShiftCst);
- }
- // We are truncating value in order to extract the higher-order
- // double, which we will be using to extract the sign from.
- IntTy = llvm::IntegerType::get(C, Width);
- V = CGF.Builder.CreateTrunc(V, IntTy);
- }
- Value *Zero = llvm::Constant::getNullValue(IntTy);
- return CGF.Builder.CreateICmpSLT(V, Zero);
-}
-
-static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
- const CallExpr *E, llvm::Constant *calleeValue) {
- CGCallee callee = CGCallee::forDirect(calleeValue, GlobalDecl(FD));
- return CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot());
-}
-
-/// Emit a call to llvm.{sadd,uadd,ssub,usub,smul,umul}.with.overflow.*
-/// depending on IntrinsicID.
-///
-/// \arg CGF The current codegen function.
-/// \arg IntrinsicID The ID for the Intrinsic we wish to generate.
-/// \arg X The first argument to the llvm.*.with.overflow.*.
-/// \arg Y The second argument to the llvm.*.with.overflow.*.
-/// \arg Carry The carry returned by the llvm.*.with.overflow.*.
-/// \returns The result (i.e. sum/product) returned by the intrinsic.
-static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF,
- const llvm::Intrinsic::ID IntrinsicID,
- llvm::Value *X, llvm::Value *Y,
- llvm::Value *&Carry) {
- // Make sure we have integers of the same width.
- assert(X->getType() == Y->getType() &&
- "Arguments must be the same type. (Did you forget to make sure both "
- "arguments have the same integer width?)");
-
- llvm::Value *Callee = CGF.CGM.getIntrinsic(IntrinsicID, X->getType());
- llvm::Value *Tmp = CGF.Builder.CreateCall(Callee, {X, Y});
- Carry = CGF.Builder.CreateExtractValue(Tmp, 1);
- return CGF.Builder.CreateExtractValue(Tmp, 0);
-}
-
-static Value *emitRangedBuiltin(CodeGenFunction &CGF,
- unsigned IntrinsicID,
- int low, int high) {
- llvm::MDBuilder MDHelper(CGF.getLLVMContext());
- llvm::MDNode *RNode = MDHelper.createRange(APInt(32, low), APInt(32, high));
- Value *F = CGF.CGM.getIntrinsic(IntrinsicID, {});
- llvm::Instruction *Call = CGF.Builder.CreateCall(F);
- Call->setMetadata(llvm::LLVMContext::MD_range, RNode);
- return Call;
-}
-
-namespace {
- struct WidthAndSignedness {
- unsigned Width;
- bool Signed;
- };
-}
-
-static WidthAndSignedness
-getIntegerWidthAndSignedness(const clang::ASTContext &context,
- const clang::QualType Type) {
- assert(Type->isIntegerType() && "Given type is not an integer.");
- unsigned Width = Type->isBooleanType() ? 1 : context.getTypeInfo(Type).Width;
- bool Signed = Type->isSignedIntegerType();
- return {Width, Signed};
-}
-
-// Given one or more integer types, this function produces an integer type that
-// encompasses them: any value in one of the given types could be expressed in
-// the encompassing type.
-static struct WidthAndSignedness
-EncompassingIntegerType(ArrayRef<struct WidthAndSignedness> Types) {
- assert(Types.size() > 0 && "Empty list of types.");
-
- // If any of the given types is signed, we must return a signed type.
- bool Signed = false;
- for (const auto &Type : Types) {
- Signed |= Type.Signed;
- }
-
- // The encompassing type must have a width greater than or equal to the width
- // of the specified types. Additionally, if the encompassing type is signed,
- // its width must be strictly greater than the width of any unsigned types
- // given.
- unsigned Width = 0;
- for (const auto &Type : Types) {
- unsigned MinWidth = Type.Width + (Signed && !Type.Signed);
- if (Width < MinWidth) {
- Width = MinWidth;
- }
- }
-
- return {Width, Signed};
-}
-
-Value *CodeGenFunction::EmitVAStartEnd(Value *ArgValue, bool IsStart) {
- llvm::Type *DestType = Int8PtrTy;
- if (ArgValue->getType() != DestType)
- ArgValue =
- Builder.CreateBitCast(ArgValue, DestType, ArgValue->getName().data());
-
- Intrinsic::ID inst = IsStart ? Intrinsic::vastart : Intrinsic::vaend;
- return Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue);
-}
-
-/// Checks if using the result of __builtin_object_size(p, @p From) in place of
-/// __builtin_object_size(p, @p To) is correct
-static bool areBOSTypesCompatible(int From, int To) {
- // Note: Our __builtin_object_size implementation currently treats Type=0 and
- // Type=2 identically. Encoding this implementation detail here may make
- // improving __builtin_object_size difficult in the future, so it's omitted.
- return From == To || (From == 0 && To == 1) || (From == 3 && To == 2);
-}
-
-static llvm::Value *
-getDefaultBuiltinObjectSizeResult(unsigned Type, llvm::IntegerType *ResType) {
- return ConstantInt::get(ResType, (Type & 2) ? 0 : -1, /*isSigned=*/true);
-}
-
-llvm::Value *
-CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType,
- llvm::Value *EmittedE) {
- uint64_t ObjectSize;
- if (!E->tryEvaluateObjectSize(ObjectSize, getContext(), Type))
- return emitBuiltinObjectSize(E, Type, ResType, EmittedE);
- return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
-}
-
-/// Returns a Value corresponding to the size of the given expression.
-/// This Value may be either of the following:
-/// - A llvm::Argument (if E is a param with the pass_object_size attribute on
-/// it)
-/// - A call to the @llvm.objectsize intrinsic
-///
-/// EmittedE is the result of emitting `E` as a scalar expr. If it's non-null
-/// and we wouldn't otherwise try to reference a pass_object_size parameter,
-/// we'll call @llvm.objectsize on EmittedE, rather than emitting E.
-llvm::Value *
-CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType,
- llvm::Value *EmittedE) {
- // We need to reference an argument if the pointer is a parameter with the
- // pass_object_size attribute.
- if (auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
- auto *Param = dyn_cast<ParmVarDecl>(D->getDecl());
- auto *PS = D->getDecl()->getAttr<PassObjectSizeAttr>();
- if (Param != nullptr && PS != nullptr &&
- areBOSTypesCompatible(PS->getType(), Type)) {
- auto Iter = SizeArguments.find(Param);
- assert(Iter != SizeArguments.end());
-
- const ImplicitParamDecl *D = Iter->second;
- auto DIter = LocalDeclMap.find(D);
- assert(DIter != LocalDeclMap.end());
-
- return EmitLoadOfScalar(DIter->second, /*volatile=*/false,
- getContext().getSizeType(), E->getBeginLoc());
- }
- }
-
- // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
- // evaluate E for side-effects. In either case, we shouldn't lower to
- // @llvm.objectsize.
- if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext())))
- return getDefaultBuiltinObjectSizeResult(Type, ResType);
-
- Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E);
- assert(Ptr->getType()->isPointerTy() &&
- "Non-pointer passed to __builtin_object_size?");
-
- Value *F = CGM.getIntrinsic(Intrinsic::objectsize, {ResType, Ptr->getType()});
-
- // LLVM only supports 0 and 2, make sure that we pass along that as a boolean.
- Value *Min = Builder.getInt1((Type & 2) != 0);
- // For GCC compatibility, __builtin_object_size treat NULL as unknown size.
- Value *NullIsUnknown = Builder.getTrue();
- return Builder.CreateCall(F, {Ptr, Min, NullIsUnknown});
-}
-
-namespace {
-/// A struct to generically describe a bit test intrinsic.
-struct BitTest {
- enum ActionKind : uint8_t { TestOnly, Complement, Reset, Set };
- enum InterlockingKind : uint8_t {
- Unlocked,
- Sequential,
- Acquire,
- Release,
- NoFence
- };
-
- ActionKind Action;
- InterlockingKind Interlocking;
- bool Is64Bit;
-
- static BitTest decodeBitTestBuiltin(unsigned BuiltinID);
-};
-} // namespace
-
-BitTest BitTest::decodeBitTestBuiltin(unsigned BuiltinID) {
- switch (BuiltinID) {
- // Main portable variants.
- case Builtin::BI_bittest:
- return {TestOnly, Unlocked, false};
- case Builtin::BI_bittestandcomplement:
- return {Complement, Unlocked, false};
- case Builtin::BI_bittestandreset:
- return {Reset, Unlocked, false};
- case Builtin::BI_bittestandset:
- return {Set, Unlocked, false};
- case Builtin::BI_interlockedbittestandreset:
- return {Reset, Sequential, false};
- case Builtin::BI_interlockedbittestandset:
- return {Set, Sequential, false};
-
- // X86-specific 64-bit variants.
- case Builtin::BI_bittest64:
- return {TestOnly, Unlocked, true};
- case Builtin::BI_bittestandcomplement64:
- return {Complement, Unlocked, true};
- case Builtin::BI_bittestandreset64:
- return {Reset, Unlocked, true};
- case Builtin::BI_bittestandset64:
- return {Set, Unlocked, true};
- case Builtin::BI_interlockedbittestandreset64:
- return {Reset, Sequential, true};
- case Builtin::BI_interlockedbittestandset64:
- return {Set, Sequential, true};
-
- // ARM/AArch64-specific ordering variants.
- case Builtin::BI_interlockedbittestandset_acq:
- return {Set, Acquire, false};
- case Builtin::BI_interlockedbittestandset_rel:
- return {Set, Release, false};
- case Builtin::BI_interlockedbittestandset_nf:
- return {Set, NoFence, false};
- case Builtin::BI_interlockedbittestandreset_acq:
- return {Reset, Acquire, false};
- case Builtin::BI_interlockedbittestandreset_rel:
- return {Reset, Release, false};
- case Builtin::BI_interlockedbittestandreset_nf:
- return {Reset, NoFence, false};
- }
- llvm_unreachable("expected only bittest intrinsics");
-}
-
-static char bitActionToX86BTCode(BitTest::ActionKind A) {
- switch (A) {
- case BitTest::TestOnly: return '\0';
- case BitTest::Complement: return 'c';
- case BitTest::Reset: return 'r';
- case BitTest::Set: return 's';
- }
- llvm_unreachable("invalid action");
-}
-
-static llvm::Value *EmitX86BitTestIntrinsic(CodeGenFunction &CGF,
- BitTest BT,
- const CallExpr *E, Value *BitBase,
- Value *BitPos) {
- char Action = bitActionToX86BTCode(BT.Action);
- char SizeSuffix = BT.Is64Bit ? 'q' : 'l';
-
- // Build the assembly.
- SmallString<64> Asm;
- raw_svector_ostream AsmOS(Asm);
- if (BT.Interlocking != BitTest::Unlocked)
- AsmOS << "lock ";
- AsmOS << "bt";
- if (Action)
- AsmOS << Action;
- AsmOS << SizeSuffix << " $2, ($1)\n\tsetc ${0:b}";
-
- // Build the constraints. FIXME: We should support immediates when possible.
- std::string Constraints = "=r,r,r,~{cc},~{flags},~{fpsr}";
- llvm::IntegerType *IntType = llvm::IntegerType::get(
- CGF.getLLVMContext(),
- CGF.getContext().getTypeSize(E->getArg(1)->getType()));
- llvm::Type *IntPtrType = IntType->getPointerTo();
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8Ty, {IntPtrType, IntType}, false);
-
- llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, Asm, Constraints, /*SideEffects=*/true);
- return CGF.Builder.CreateCall(IA, {BitBase, BitPos});
-}
-
-static llvm::AtomicOrdering
-getBitTestAtomicOrdering(BitTest::InterlockingKind I) {
- switch (I) {
- case BitTest::Unlocked: return llvm::AtomicOrdering::NotAtomic;
- case BitTest::Sequential: return llvm::AtomicOrdering::SequentiallyConsistent;
- case BitTest::Acquire: return llvm::AtomicOrdering::Acquire;
- case BitTest::Release: return llvm::AtomicOrdering::Release;
- case BitTest::NoFence: return llvm::AtomicOrdering::Monotonic;
- }
- llvm_unreachable("invalid interlocking");
-}
-
-/// Emit a _bittest* intrinsic. These intrinsics take a pointer to an array of
-/// bits and a bit position and read and optionally modify the bit at that
-/// position. The position index can be arbitrarily large, i.e. it can be larger
-/// than 31 or 63, so we need an indexed load in the general case.
-static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF,
- unsigned BuiltinID,
- const CallExpr *E) {
- Value *BitBase = CGF.EmitScalarExpr(E->getArg(0));
- Value *BitPos = CGF.EmitScalarExpr(E->getArg(1));
-
- BitTest BT = BitTest::decodeBitTestBuiltin(BuiltinID);
-
- // X86 has special BT, BTC, BTR, and BTS instructions that handle the array
- // indexing operation internally. Use them if possible.
- llvm::Triple::ArchType Arch = CGF.getTarget().getTriple().getArch();
- if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64)
- return EmitX86BitTestIntrinsic(CGF, BT, E, BitBase, BitPos);
-
- // Otherwise, use generic code to load one byte and test the bit. Use all but
- // the bottom three bits as the array index, and the bottom three bits to form
- // a mask.
- // Bit = BitBaseI8[BitPos >> 3] & (1 << (BitPos & 0x7)) != 0;
- Value *ByteIndex = CGF.Builder.CreateAShr(
- BitPos, llvm::ConstantInt::get(BitPos->getType(), 3), "bittest.byteidx");
- Value *BitBaseI8 = CGF.Builder.CreatePointerCast(BitBase, CGF.Int8PtrTy);
- Address ByteAddr(CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, BitBaseI8,
- ByteIndex, "bittest.byteaddr"),
- CharUnits::One());
- Value *PosLow =
- CGF.Builder.CreateAnd(CGF.Builder.CreateTrunc(BitPos, CGF.Int8Ty),
- llvm::ConstantInt::get(CGF.Int8Ty, 0x7));
-
- // The updating instructions will need a mask.
- Value *Mask = nullptr;
- if (BT.Action != BitTest::TestOnly) {
- Mask = CGF.Builder.CreateShl(llvm::ConstantInt::get(CGF.Int8Ty, 1), PosLow,
- "bittest.mask");
- }
-
- // Check the action and ordering of the interlocked intrinsics.
- llvm::AtomicOrdering Ordering = getBitTestAtomicOrdering(BT.Interlocking);
-
- Value *OldByte = nullptr;
- if (Ordering != llvm::AtomicOrdering::NotAtomic) {
- // Emit a combined atomicrmw load/store operation for the interlocked
- // intrinsics.
- llvm::AtomicRMWInst::BinOp RMWOp = llvm::AtomicRMWInst::Or;
- if (BT.Action == BitTest::Reset) {
- Mask = CGF.Builder.CreateNot(Mask);
- RMWOp = llvm::AtomicRMWInst::And;
- }
- OldByte = CGF.Builder.CreateAtomicRMW(RMWOp, ByteAddr.getPointer(), Mask,
- Ordering);
- } else {
- // Emit a plain load for the non-interlocked intrinsics.
- OldByte = CGF.Builder.CreateLoad(ByteAddr, "bittest.byte");
- Value *NewByte = nullptr;
- switch (BT.Action) {
- case BitTest::TestOnly:
- // Don't store anything.
- break;
- case BitTest::Complement:
- NewByte = CGF.Builder.CreateXor(OldByte, Mask);
- break;
- case BitTest::Reset:
- NewByte = CGF.Builder.CreateAnd(OldByte, CGF.Builder.CreateNot(Mask));
- break;
- case BitTest::Set:
- NewByte = CGF.Builder.CreateOr(OldByte, Mask);
- break;
- }
- if (NewByte)
- CGF.Builder.CreateStore(NewByte, ByteAddr);
- }
-
- // However we loaded the old byte, either by plain load or atomicrmw, shift
- // the bit into the low position and mask it to 0 or 1.
- Value *ShiftedByte = CGF.Builder.CreateLShr(OldByte, PosLow, "bittest.shr");
- return CGF.Builder.CreateAnd(
- ShiftedByte, llvm::ConstantInt::get(CGF.Int8Ty, 1), "bittest.res");
-}
-
-namespace {
-enum class MSVCSetJmpKind {
- _setjmpex,
- _setjmp3,
- _setjmp
-};
-}
-
-/// MSVC handles setjmp a bit differently on different platforms. On every
-/// architecture except 32-bit x86, the frame address is passed. On x86, extra
-/// parameters can be passed as variadic arguments, but we always pass none.
-static RValue EmitMSVCRTSetJmp(CodeGenFunction &CGF, MSVCSetJmpKind SJKind,
- const CallExpr *E) {
- llvm::Value *Arg1 = nullptr;
- llvm::Type *Arg1Ty = nullptr;
- StringRef Name;
- bool IsVarArg = false;
- if (SJKind == MSVCSetJmpKind::_setjmp3) {
- Name = "_setjmp3";
- Arg1Ty = CGF.Int32Ty;
- Arg1 = llvm::ConstantInt::get(CGF.IntTy, 0);
- IsVarArg = true;
- } else {
- Name = SJKind == MSVCSetJmpKind::_setjmp ? "_setjmp" : "_setjmpex";
- Arg1Ty = CGF.Int8PtrTy;
- if (CGF.getTarget().getTriple().getArch() == llvm::Triple::aarch64) {
- Arg1 = CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::sponentry));
- } else
- Arg1 = CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::frameaddress),
- llvm::ConstantInt::get(CGF.Int32Ty, 0));
- }
-
- // Mark the call site and declaration with ReturnsTwice.
- llvm::Type *ArgTypes[2] = {CGF.Int8PtrTy, Arg1Ty};
- llvm::AttributeList ReturnsTwiceAttr = llvm::AttributeList::get(
- CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex,
- llvm::Attribute::ReturnsTwice);
- llvm::Constant *SetJmpFn = CGF.CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGF.IntTy, ArgTypes, IsVarArg), Name,
- ReturnsTwiceAttr, /*Local=*/true);
-
- llvm::Value *Buf = CGF.Builder.CreateBitOrPointerCast(
- CGF.EmitScalarExpr(E->getArg(0)), CGF.Int8PtrTy);
- llvm::Value *Args[] = {Buf, Arg1};
- llvm::CallSite CS = CGF.EmitRuntimeCallOrInvoke(SetJmpFn, Args);
- CS.setAttributes(ReturnsTwiceAttr);
- return RValue::get(CS.getInstruction());
-}
-
-// Many of MSVC builtins are on x64, ARM and AArch64; to avoid repeating code,
-// we handle them here.
-enum class CodeGenFunction::MSVCIntrin {
- _BitScanForward,
- _BitScanReverse,
- _InterlockedAnd,
- _InterlockedDecrement,
- _InterlockedExchange,
- _InterlockedExchangeAdd,
- _InterlockedExchangeSub,
- _InterlockedIncrement,
- _InterlockedOr,
- _InterlockedXor,
- _InterlockedExchangeAdd_acq,
- _InterlockedExchangeAdd_rel,
- _InterlockedExchangeAdd_nf,
- _InterlockedExchange_acq,
- _InterlockedExchange_rel,
- _InterlockedExchange_nf,
- _InterlockedCompareExchange_acq,
- _InterlockedCompareExchange_rel,
- _InterlockedCompareExchange_nf,
- _InterlockedOr_acq,
- _InterlockedOr_rel,
- _InterlockedOr_nf,
- _InterlockedXor_acq,
- _InterlockedXor_rel,
- _InterlockedXor_nf,
- _InterlockedAnd_acq,
- _InterlockedAnd_rel,
- _InterlockedAnd_nf,
- _InterlockedIncrement_acq,
- _InterlockedIncrement_rel,
- _InterlockedIncrement_nf,
- _InterlockedDecrement_acq,
- _InterlockedDecrement_rel,
- _InterlockedDecrement_nf,
- __fastfail,
-};
-
-Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID,
- const CallExpr *E) {
- switch (BuiltinID) {
- case MSVCIntrin::_BitScanForward:
- case MSVCIntrin::_BitScanReverse: {
- Value *ArgValue = EmitScalarExpr(E->getArg(1));
-
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *IndexType =
- EmitScalarExpr(E->getArg(0))->getType()->getPointerElementType();
- llvm::Type *ResultType = ConvertType(E->getType());
-
- Value *ArgZero = llvm::Constant::getNullValue(ArgType);
- Value *ResZero = llvm::Constant::getNullValue(ResultType);
- Value *ResOne = llvm::ConstantInt::get(ResultType, 1);
-
- BasicBlock *Begin = Builder.GetInsertBlock();
- BasicBlock *End = createBasicBlock("bitscan_end", this->CurFn);
- Builder.SetInsertPoint(End);
- PHINode *Result = Builder.CreatePHI(ResultType, 2, "bitscan_result");
-
- Builder.SetInsertPoint(Begin);
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, ArgZero);
- BasicBlock *NotZero = createBasicBlock("bitscan_not_zero", this->CurFn);
- Builder.CreateCondBr(IsZero, End, NotZero);
- Result->addIncoming(ResZero, Begin);
-
- Builder.SetInsertPoint(NotZero);
- Address IndexAddress = EmitPointerWithAlignment(E->getArg(0));
-
- if (BuiltinID == MSVCIntrin::_BitScanForward) {
- Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Value *ZeroCount = Builder.CreateCall(F, {ArgValue, Builder.getTrue()});
- ZeroCount = Builder.CreateIntCast(ZeroCount, IndexType, false);
- Builder.CreateStore(ZeroCount, IndexAddress, false);
- } else {
- unsigned ArgWidth = cast<llvm::IntegerType>(ArgType)->getBitWidth();
- Value *ArgTypeLastIndex = llvm::ConstantInt::get(IndexType, ArgWidth - 1);
-
- Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *ZeroCount = Builder.CreateCall(F, {ArgValue, Builder.getTrue()});
- ZeroCount = Builder.CreateIntCast(ZeroCount, IndexType, false);
- Value *Index = Builder.CreateNSWSub(ArgTypeLastIndex, ZeroCount);
- Builder.CreateStore(Index, IndexAddress, false);
- }
- Builder.CreateBr(End);
- Result->addIncoming(ResOne, NotZero);
-
- Builder.SetInsertPoint(End);
- return Result;
- }
- case MSVCIntrin::_InterlockedAnd:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::And, E);
- case MSVCIntrin::_InterlockedExchange:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E);
- case MSVCIntrin::_InterlockedExchangeAdd:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Add, E);
- case MSVCIntrin::_InterlockedExchangeSub:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Sub, E);
- case MSVCIntrin::_InterlockedOr:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Or, E);
- case MSVCIntrin::_InterlockedXor:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xor, E);
- case MSVCIntrin::_InterlockedExchangeAdd_acq:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Add, E,
- AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedExchangeAdd_rel:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Add, E,
- AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedExchangeAdd_nf:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Add, E,
- AtomicOrdering::Monotonic);
- case MSVCIntrin::_InterlockedExchange_acq:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E,
- AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedExchange_rel:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E,
- AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedExchange_nf:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E,
- AtomicOrdering::Monotonic);
- case MSVCIntrin::_InterlockedCompareExchange_acq:
- return EmitAtomicCmpXchgForMSIntrin(*this, E, AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedCompareExchange_rel:
- return EmitAtomicCmpXchgForMSIntrin(*this, E, AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedCompareExchange_nf:
- return EmitAtomicCmpXchgForMSIntrin(*this, E, AtomicOrdering::Monotonic);
- case MSVCIntrin::_InterlockedOr_acq:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Or, E,
- AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedOr_rel:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Or, E,
- AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedOr_nf:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Or, E,
- AtomicOrdering::Monotonic);
- case MSVCIntrin::_InterlockedXor_acq:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xor, E,
- AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedXor_rel:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xor, E,
- AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedXor_nf:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xor, E,
- AtomicOrdering::Monotonic);
- case MSVCIntrin::_InterlockedAnd_acq:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::And, E,
- AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedAnd_rel:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::And, E,
- AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedAnd_nf:
- return MakeBinaryAtomicValue(*this, AtomicRMWInst::And, E,
- AtomicOrdering::Monotonic);
- case MSVCIntrin::_InterlockedIncrement_acq:
- return EmitAtomicIncrementValue(*this, E, AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedIncrement_rel:
- return EmitAtomicIncrementValue(*this, E, AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedIncrement_nf:
- return EmitAtomicIncrementValue(*this, E, AtomicOrdering::Monotonic);
- case MSVCIntrin::_InterlockedDecrement_acq:
- return EmitAtomicDecrementValue(*this, E, AtomicOrdering::Acquire);
- case MSVCIntrin::_InterlockedDecrement_rel:
- return EmitAtomicDecrementValue(*this, E, AtomicOrdering::Release);
- case MSVCIntrin::_InterlockedDecrement_nf:
- return EmitAtomicDecrementValue(*this, E, AtomicOrdering::Monotonic);
-
- case MSVCIntrin::_InterlockedDecrement:
- return EmitAtomicDecrementValue(*this, E);
- case MSVCIntrin::_InterlockedIncrement:
- return EmitAtomicIncrementValue(*this, E);
-
- case MSVCIntrin::__fastfail: {
- // Request immediate process termination from the kernel. The instruction
- // sequences to do this are documented on MSDN:
- // https://msdn.microsoft.com/en-us/library/dn774154.aspx
- llvm::Triple::ArchType ISA = getTarget().getTriple().getArch();
- StringRef Asm, Constraints;
- switch (ISA) {
- default:
- ErrorUnsupported(E, "__fastfail call for this architecture");
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- Asm = "int $$0x29";
- Constraints = "{cx}";
- break;
- case llvm::Triple::thumb:
- Asm = "udf #251";
- Constraints = "{r0}";
- break;
- }
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, {Int32Ty}, false);
- llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, Asm, Constraints, /*SideEffects=*/true);
- llvm::AttributeList NoReturnAttr = llvm::AttributeList::get(
- getLLVMContext(), llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoReturn);
- CallSite CS = Builder.CreateCall(IA, EmitScalarExpr(E->getArg(0)));
- CS.setAttributes(NoReturnAttr);
- return CS.getInstruction();
- }
- }
- llvm_unreachable("Incorrect MSVC intrinsic!");
-}
-
-namespace {
-// ARC cleanup for __builtin_os_log_format
-struct CallObjCArcUse final : EHScopeStack::Cleanup {
- CallObjCArcUse(llvm::Value *object) : object(object) {}
- llvm::Value *object;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitARCIntrinsicUse(object);
- }
-};
-}
-
-Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
- BuiltinCheckKind Kind) {
- assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero)
- && "Unsupported builtin check kind");
-
- Value *ArgValue = EmitScalarExpr(E);
- if (!SanOpts.has(SanitizerKind::Builtin) || !getTarget().isCLZForZeroUndef())
- return ArgValue;
-
- SanitizerScope SanScope(this);
- Value *Cond = Builder.CreateICmpNE(
- ArgValue, llvm::Constant::getNullValue(ArgValue->getType()));
- EmitCheck(std::make_pair(Cond, SanitizerKind::Builtin),
- SanitizerHandler::InvalidBuiltin,
- {EmitCheckSourceLocation(E->getExprLoc()),
- llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)},
- None);
- return ArgValue;
-}
-
-/// Get the argument type for arguments to os_log_helper.
-static CanQualType getOSLogArgType(ASTContext &C, int Size) {
- QualType UnsignedTy = C.getIntTypeForBitwidth(Size * 8, /*Signed=*/false);
- return C.getCanonicalType(UnsignedTy);
-}
-
-llvm::Function *CodeGenFunction::generateBuiltinOSLogHelperFunction(
- const analyze_os_log::OSLogBufferLayout &Layout,
- CharUnits BufferAlignment) {
- ASTContext &Ctx = getContext();
-
- llvm::SmallString<64> Name;
- {
- raw_svector_ostream OS(Name);
- OS << "__os_log_helper";
- OS << "_" << BufferAlignment.getQuantity();
- OS << "_" << int(Layout.getSummaryByte());
- OS << "_" << int(Layout.getNumArgsByte());
- for (const auto &Item : Layout.Items)
- OS << "_" << int(Item.getSizeByte()) << "_"
- << int(Item.getDescriptorByte());
- }
-
- if (llvm::Function *F = CGM.getModule().getFunction(Name))
- return F;
-
- llvm::SmallVector<QualType, 4> ArgTys;
- llvm::SmallVector<ImplicitParamDecl, 4> Params;
- Params.emplace_back(Ctx, nullptr, SourceLocation(), &Ctx.Idents.get("buffer"),
- Ctx.VoidPtrTy, ImplicitParamDecl::Other);
- ArgTys.emplace_back(Ctx.VoidPtrTy);
-
- for (unsigned int I = 0, E = Layout.Items.size(); I < E; ++I) {
- char Size = Layout.Items[I].getSizeByte();
- if (!Size)
- continue;
-
- QualType ArgTy = getOSLogArgType(Ctx, Size);
- Params.emplace_back(
- Ctx, nullptr, SourceLocation(),
- &Ctx.Idents.get(std::string("arg") + llvm::to_string(I)), ArgTy,
- ImplicitParamDecl::Other);
- ArgTys.emplace_back(ArgTy);
- }
-
- FunctionArgList Args;
- for (auto &P : Params)
- Args.push_back(&P);
-
- QualType ReturnTy = Ctx.VoidTy;
- QualType FuncionTy = Ctx.getFunctionType(ReturnTy, ArgTys, {});
-
- // The helper function has linkonce_odr linkage to enable the linker to merge
- // identical functions. To ensure the merging always happens, 'noinline' is
- // attached to the function when compiling with -Oz.
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, Args);
- llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *Fn = llvm::Function::Create(
- FuncTy, llvm::GlobalValue::LinkOnceODRLinkage, Name, &CGM.getModule());
- Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, Fn);
- CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Fn);
-
- // Attach 'noinline' at -Oz.
- if (CGM.getCodeGenOpts().OptimizeSize == 2)
- Fn->addFnAttr(llvm::Attribute::NoInline);
-
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
- IdentifierInfo *II = &Ctx.Idents.get(Name);
- FunctionDecl *FD = FunctionDecl::Create(
- Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
- FuncionTy, nullptr, SC_PrivateExtern, false, false);
-
- StartFunction(FD, ReturnTy, Fn, FI, Args);
-
- // Create a scope with an artificial location for the body of this function.
- auto AL = ApplyDebugLocation::CreateArtificial(*this);
-
- CharUnits Offset;
- Address BufAddr(Builder.CreateLoad(GetAddrOfLocalVar(&Params[0]), "buf"),
- BufferAlignment);
- Builder.CreateStore(Builder.getInt8(Layout.getSummaryByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "summary"));
- Builder.CreateStore(Builder.getInt8(Layout.getNumArgsByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "numArgs"));
-
- unsigned I = 1;
- for (const auto &Item : Layout.Items) {
- Builder.CreateStore(
- Builder.getInt8(Item.getDescriptorByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "argDescriptor"));
- Builder.CreateStore(
- Builder.getInt8(Item.getSizeByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "argSize"));
-
- CharUnits Size = Item.size();
- if (!Size.getQuantity())
- continue;
-
- Address Arg = GetAddrOfLocalVar(&Params[I]);
- Address Addr = Builder.CreateConstByteGEP(BufAddr, Offset, "argData");
- Addr = Builder.CreateBitCast(Addr, Arg.getPointer()->getType(),
- "argDataCast");
- Builder.CreateStore(Builder.CreateLoad(Arg), Addr);
- Offset += Size;
- ++I;
- }
-
- FinishFunction();
-
- return Fn;
-}
-
-RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) {
- assert(E.getNumArgs() >= 2 &&
- "__builtin_os_log_format takes at least 2 arguments");
- ASTContext &Ctx = getContext();
- analyze_os_log::OSLogBufferLayout Layout;
- analyze_os_log::computeOSLogBufferLayout(Ctx, &E, Layout);
- Address BufAddr = EmitPointerWithAlignment(E.getArg(0));
- llvm::SmallVector<llvm::Value *, 4> RetainableOperands;
-
- // Ignore argument 1, the format string. It is not currently used.
- CallArgList Args;
- Args.add(RValue::get(BufAddr.getPointer()), Ctx.VoidPtrTy);
-
- for (const auto &Item : Layout.Items) {
- int Size = Item.getSizeByte();
- if (!Size)
- continue;
-
- llvm::Value *ArgVal;
-
- if (Item.getKind() == analyze_os_log::OSLogBufferItem::MaskKind) {
- uint64_t Val = 0;
- for (unsigned I = 0, E = Item.getMaskType().size(); I < E; ++I)
- Val |= ((uint64_t)Item.getMaskType()[I]) << I * 8;
- ArgVal = llvm::Constant::getIntegerValue(Int64Ty, llvm::APInt(64, Val));
- } else if (const Expr *TheExpr = Item.getExpr()) {
- ArgVal = EmitScalarExpr(TheExpr, /*Ignore*/ false);
-
- // Check if this is a retainable type.
- if (TheExpr->getType()->isObjCRetainableType()) {
- assert(getEvaluationKind(TheExpr->getType()) == TEK_Scalar &&
- "Only scalar can be a ObjC retainable type");
- // Check if the object is constant, if not, save it in
- // RetainableOperands.
- if (!isa<Constant>(ArgVal))
- RetainableOperands.push_back(ArgVal);
- }
- } else {
- ArgVal = Builder.getInt32(Item.getConstValue().getQuantity());
- }
-
- unsigned ArgValSize =
- CGM.getDataLayout().getTypeSizeInBits(ArgVal->getType());
- llvm::IntegerType *IntTy = llvm::Type::getIntNTy(getLLVMContext(),
- ArgValSize);
- ArgVal = Builder.CreateBitOrPointerCast(ArgVal, IntTy);
- CanQualType ArgTy = getOSLogArgType(Ctx, Size);
- // If ArgVal has type x86_fp80, zero-extend ArgVal.
- ArgVal = Builder.CreateZExtOrBitCast(ArgVal, ConvertType(ArgTy));
- Args.add(RValue::get(ArgVal), ArgTy);
- }
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionCall(Ctx.VoidTy, Args);
- llvm::Function *F = CodeGenFunction(CGM).generateBuiltinOSLogHelperFunction(
- Layout, BufAddr.getAlignment());
- EmitCall(FI, CGCallee::forDirect(F), ReturnValueSlot(), Args);
-
- // Push a clang.arc.use cleanup for each object in RetainableOperands. The
- // cleanup will cause the use to appear after the final log call, keeping
- // the object valid while it’s held in the log buffer. Note that if there’s
- // a release cleanup on the object, it will already be active; since
- // cleanups are emitted in reverse order, the use will occur before the
- // object is released.
- if (!RetainableOperands.empty() && getLangOpts().ObjCAutoRefCount &&
- CGM.getCodeGenOpts().OptimizationLevel != 0)
- for (llvm::Value *Object : RetainableOperands)
- pushFullExprCleanup<CallObjCArcUse>(getARCCleanupKind(), Object);
-
- return RValue::get(BufAddr.getPointer());
-}
-
-/// Determine if a binop is a checked mixed-sign multiply we can specialize.
-static bool isSpecialMixedSignMultiply(unsigned BuiltinID,
- WidthAndSignedness Op1Info,
- WidthAndSignedness Op2Info,
- WidthAndSignedness ResultInfo) {
- return BuiltinID == Builtin::BI__builtin_mul_overflow &&
- std::max(Op1Info.Width, Op2Info.Width) >= ResultInfo.Width &&
- Op1Info.Signed != Op2Info.Signed;
-}
-
-/// Emit a checked mixed-sign multiply. This is a cheaper specialization of
-/// the generic checked-binop irgen.
-static RValue
-EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
- WidthAndSignedness Op1Info, const clang::Expr *Op2,
- WidthAndSignedness Op2Info,
- const clang::Expr *ResultArg, QualType ResultQTy,
- WidthAndSignedness ResultInfo) {
- assert(isSpecialMixedSignMultiply(Builtin::BI__builtin_mul_overflow, Op1Info,
- Op2Info, ResultInfo) &&
- "Not a mixed-sign multipliction we can specialize");
-
- // Emit the signed and unsigned operands.
- const clang::Expr *SignedOp = Op1Info.Signed ? Op1 : Op2;
- const clang::Expr *UnsignedOp = Op1Info.Signed ? Op2 : Op1;
- llvm::Value *Signed = CGF.EmitScalarExpr(SignedOp);
- llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp);
- unsigned SignedOpWidth = Op1Info.Signed ? Op1Info.Width : Op2Info.Width;
- unsigned UnsignedOpWidth = Op1Info.Signed ? Op2Info.Width : Op1Info.Width;
-
- // One of the operands may be smaller than the other. If so, [s|z]ext it.
- if (SignedOpWidth < UnsignedOpWidth)
- Signed = CGF.Builder.CreateSExt(Signed, Unsigned->getType(), "op.sext");
- if (UnsignedOpWidth < SignedOpWidth)
- Unsigned = CGF.Builder.CreateZExt(Unsigned, Signed->getType(), "op.zext");
-
- llvm::Type *OpTy = Signed->getType();
- llvm::Value *Zero = llvm::Constant::getNullValue(OpTy);
- Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg);
- llvm::Type *ResTy = ResultPtr.getElementType();
- unsigned OpWidth = std::max(Op1Info.Width, Op2Info.Width);
-
- // Take the absolute value of the signed operand.
- llvm::Value *IsNegative = CGF.Builder.CreateICmpSLT(Signed, Zero);
- llvm::Value *AbsOfNegative = CGF.Builder.CreateSub(Zero, Signed);
- llvm::Value *AbsSigned =
- CGF.Builder.CreateSelect(IsNegative, AbsOfNegative, Signed);
-
- // Perform a checked unsigned multiplication.
- llvm::Value *UnsignedOverflow;
- llvm::Value *UnsignedResult =
- EmitOverflowIntrinsic(CGF, llvm::Intrinsic::umul_with_overflow, AbsSigned,
- Unsigned, UnsignedOverflow);
-
- llvm::Value *Overflow, *Result;
- if (ResultInfo.Signed) {
- // Signed overflow occurs if the result is greater than INT_MAX or lesser
- // than INT_MIN, i.e when |Result| > (INT_MAX + IsNegative).
- auto IntMax =
- llvm::APInt::getSignedMaxValue(ResultInfo.Width).zextOrSelf(OpWidth);
- llvm::Value *MaxResult =
- CGF.Builder.CreateAdd(llvm::ConstantInt::get(OpTy, IntMax),
- CGF.Builder.CreateZExt(IsNegative, OpTy));
- llvm::Value *SignedOverflow =
- CGF.Builder.CreateICmpUGT(UnsignedResult, MaxResult);
- Overflow = CGF.Builder.CreateOr(UnsignedOverflow, SignedOverflow);
-
- // Prepare the signed result (possibly by negating it).
- llvm::Value *NegativeResult = CGF.Builder.CreateNeg(UnsignedResult);
- llvm::Value *SignedResult =
- CGF.Builder.CreateSelect(IsNegative, NegativeResult, UnsignedResult);
- Result = CGF.Builder.CreateTrunc(SignedResult, ResTy);
- } else {
- // Unsigned overflow occurs if the result is < 0 or greater than UINT_MAX.
- llvm::Value *Underflow = CGF.Builder.CreateAnd(
- IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult));
- Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow);
- if (ResultInfo.Width < OpWidth) {
- auto IntMax =
- llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth);
- llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT(
- UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax));
- Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow);
- }
-
- // Negate the product if it would be negative in infinite precision.
- Result = CGF.Builder.CreateSelect(
- IsNegative, CGF.Builder.CreateNeg(UnsignedResult), UnsignedResult);
-
- Result = CGF.Builder.CreateTrunc(Result, ResTy);
- }
- assert(Overflow && Result && "Missing overflow or result");
-
- bool isVolatile =
- ResultArg->getType()->getPointeeType().isVolatileQualified();
- CGF.Builder.CreateStore(CGF.EmitToMemory(Result, ResultQTy), ResultPtr,
- isVolatile);
- return RValue::get(Overflow);
-}
-
-static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
- Value *&RecordPtr, CharUnits Align, Value *Func,
- int Lvl) {
- const auto *RT = RType->getAs<RecordType>();
- ASTContext &Context = CGF.getContext();
- RecordDecl *RD = RT->getDecl()->getDefinition();
- ASTContext &Ctx = RD->getASTContext();
- const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD);
- std::string Pad = std::string(Lvl * 4, ' ');
-
- Value *GString =
- CGF.Builder.CreateGlobalStringPtr(RType.getAsString() + " {\n");
- Value *Res = CGF.Builder.CreateCall(Func, {GString});
-
- static llvm::DenseMap<QualType, const char *> Types;
- if (Types.empty()) {
- Types[Context.CharTy] = "%c";
- Types[Context.BoolTy] = "%d";
- Types[Context.SignedCharTy] = "%hhd";
- Types[Context.UnsignedCharTy] = "%hhu";
- Types[Context.IntTy] = "%d";
- Types[Context.UnsignedIntTy] = "%u";
- Types[Context.LongTy] = "%ld";
- Types[Context.UnsignedLongTy] = "%lu";
- Types[Context.LongLongTy] = "%lld";
- Types[Context.UnsignedLongLongTy] = "%llu";
- Types[Context.ShortTy] = "%hd";
- Types[Context.UnsignedShortTy] = "%hu";
- Types[Context.VoidPtrTy] = "%p";
- Types[Context.FloatTy] = "%f";
- Types[Context.DoubleTy] = "%f";
- Types[Context.LongDoubleTy] = "%Lf";
- Types[Context.getPointerType(Context.CharTy)] = "%s";
- Types[Context.getPointerType(Context.getConstType(Context.CharTy))] = "%s";
- }
-
- for (const auto *FD : RD->fields()) {
- uint64_t Off = RL.getFieldOffset(FD->getFieldIndex());
- Off = Ctx.toCharUnitsFromBits(Off).getQuantity();
-
- Value *FieldPtr = RecordPtr;
- if (RD->isUnion())
- FieldPtr = CGF.Builder.CreatePointerCast(
- FieldPtr, CGF.ConvertType(Context.getPointerType(FD->getType())));
- else
- FieldPtr = CGF.Builder.CreateStructGEP(CGF.ConvertType(RType), FieldPtr,
- FD->getFieldIndex());
-
- GString = CGF.Builder.CreateGlobalStringPtr(
- llvm::Twine(Pad)
- .concat(FD->getType().getAsString())
- .concat(llvm::Twine(' '))
- .concat(FD->getNameAsString())
- .concat(" : ")
- .str());
- Value *TmpRes = CGF.Builder.CreateCall(Func, {GString});
- Res = CGF.Builder.CreateAdd(Res, TmpRes);
-
- QualType CanonicalType =
- FD->getType().getUnqualifiedType().getCanonicalType();
-
- // We check whether we are in a recursive type
- if (CanonicalType->isRecordType()) {
- Value *TmpRes =
- dumpRecord(CGF, CanonicalType, FieldPtr, Align, Func, Lvl + 1);
- Res = CGF.Builder.CreateAdd(TmpRes, Res);
- continue;
- }
-
- // We try to determine the best format to print the current field
- llvm::Twine Format = Types.find(CanonicalType) == Types.end()
- ? Types[Context.VoidPtrTy]
- : Types[CanonicalType];
-
- Address FieldAddress = Address(FieldPtr, Align);
- FieldPtr = CGF.Builder.CreateLoad(FieldAddress);
-
- // FIXME Need to handle bitfield here
- GString = CGF.Builder.CreateGlobalStringPtr(
- Format.concat(llvm::Twine('\n')).str());
- TmpRes = CGF.Builder.CreateCall(Func, {GString, FieldPtr});
- Res = CGF.Builder.CreateAdd(Res, TmpRes);
- }
-
- GString = CGF.Builder.CreateGlobalStringPtr(Pad + "}\n");
- Value *TmpRes = CGF.Builder.CreateCall(Func, {GString});
- Res = CGF.Builder.CreateAdd(Res, TmpRes);
- return Res;
-}
-
-static bool
-TypeRequiresBuiltinLaunderImp(const ASTContext &Ctx, QualType Ty,
- llvm::SmallPtrSetImpl<const Decl *> &Seen) {
- if (const auto *Arr = Ctx.getAsArrayType(Ty))
- Ty = Ctx.getBaseElementType(Arr);
-
- const auto *Record = Ty->getAsCXXRecordDecl();
- if (!Record)
- return false;
-
- // We've already checked this type, or are in the process of checking it.
- if (!Seen.insert(Record).second)
- return false;
-
- assert(Record->hasDefinition() &&
- "Incomplete types should already be diagnosed");
-
- if (Record->isDynamicClass())
- return true;
-
- for (FieldDecl *F : Record->fields()) {
- if (TypeRequiresBuiltinLaunderImp(Ctx, F->getType(), Seen))
- return true;
- }
- return false;
-}
-
-/// Determine if the specified type requires laundering by checking if it is a
-/// dynamic class type or contains a subobject which is a dynamic class type.
-static bool TypeRequiresBuiltinLaunder(CodeGenModule &CGM, QualType Ty) {
- if (!CGM.getCodeGenOpts().StrictVTablePointers)
- return false;
- llvm::SmallPtrSet<const Decl *, 16> Seen;
- return TypeRequiresBuiltinLaunderImp(CGM.getContext(), Ty, Seen);
-}
-
-RValue CodeGenFunction::emitRotate(const CallExpr *E, bool IsRotateRight) {
- llvm::Value *Src = EmitScalarExpr(E->getArg(0));
- llvm::Value *ShiftAmt = EmitScalarExpr(E->getArg(1));
-
- // The builtin's shift arg may have a different type than the source arg and
- // result, but the LLVM intrinsic uses the same type for all values.
- llvm::Type *Ty = Src->getType();
- ShiftAmt = Builder.CreateIntCast(ShiftAmt, Ty, false);
-
- // Rotate is a special case of LLVM funnel shift - 1st 2 args are the same.
- unsigned IID = IsRotateRight ? Intrinsic::fshr : Intrinsic::fshl;
- Value *F = CGM.getIntrinsic(IID, Ty);
- return RValue::get(Builder.CreateCall(F, { Src, Src, ShiftAmt }));
-}
-
-RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
- const CallExpr *E,
- ReturnValueSlot ReturnValue) {
- const FunctionDecl *FD = GD.getDecl()->getAsFunction();
- // See if we can constant fold this builtin. If so, don't emit it at all.
- Expr::EvalResult Result;
- if (E->EvaluateAsRValue(Result, CGM.getContext()) &&
- !Result.hasSideEffects()) {
- if (Result.Val.isInt())
- return RValue::get(llvm::ConstantInt::get(getLLVMContext(),
- Result.Val.getInt()));
- if (Result.Val.isFloat())
- return RValue::get(llvm::ConstantFP::get(getLLVMContext(),
- Result.Val.getFloat()));
- }
-
- // There are LLVM math intrinsics/instructions corresponding to math library
- // functions except the LLVM op will never set errno while the math library
- // might. Also, math builtins have the same semantics as their math library
- // twins. Thus, we can transform math library and builtin calls to their
- // LLVM counterparts if the call is marked 'const' (known to never set errno).
- if (FD->hasAttr<ConstAttr>()) {
- switch (BuiltinID) {
- case Builtin::BIceil:
- case Builtin::BIceilf:
- case Builtin::BIceill:
- case Builtin::BI__builtin_ceil:
- case Builtin::BI__builtin_ceilf:
- case Builtin::BI__builtin_ceill:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::ceil));
-
- case Builtin::BIcopysign:
- case Builtin::BIcopysignf:
- case Builtin::BIcopysignl:
- case Builtin::BI__builtin_copysign:
- case Builtin::BI__builtin_copysignf:
- case Builtin::BI__builtin_copysignl:
- case Builtin::BI__builtin_copysignf128:
- return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::copysign));
-
- case Builtin::BIcos:
- case Builtin::BIcosf:
- case Builtin::BIcosl:
- case Builtin::BI__builtin_cos:
- case Builtin::BI__builtin_cosf:
- case Builtin::BI__builtin_cosl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::cos));
-
- case Builtin::BIexp:
- case Builtin::BIexpf:
- case Builtin::BIexpl:
- case Builtin::BI__builtin_exp:
- case Builtin::BI__builtin_expf:
- case Builtin::BI__builtin_expl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp));
-
- case Builtin::BIexp2:
- case Builtin::BIexp2f:
- case Builtin::BIexp2l:
- case Builtin::BI__builtin_exp2:
- case Builtin::BI__builtin_exp2f:
- case Builtin::BI__builtin_exp2l:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp2));
-
- case Builtin::BIfabs:
- case Builtin::BIfabsf:
- case Builtin::BIfabsl:
- case Builtin::BI__builtin_fabs:
- case Builtin::BI__builtin_fabsf:
- case Builtin::BI__builtin_fabsl:
- case Builtin::BI__builtin_fabsf128:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::fabs));
-
- case Builtin::BIfloor:
- case Builtin::BIfloorf:
- case Builtin::BIfloorl:
- case Builtin::BI__builtin_floor:
- case Builtin::BI__builtin_floorf:
- case Builtin::BI__builtin_floorl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::floor));
-
- case Builtin::BIfma:
- case Builtin::BIfmaf:
- case Builtin::BIfmal:
- case Builtin::BI__builtin_fma:
- case Builtin::BI__builtin_fmaf:
- case Builtin::BI__builtin_fmal:
- return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma));
-
- case Builtin::BIfmax:
- case Builtin::BIfmaxf:
- case Builtin::BIfmaxl:
- case Builtin::BI__builtin_fmax:
- case Builtin::BI__builtin_fmaxf:
- case Builtin::BI__builtin_fmaxl:
- return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::maxnum));
-
- case Builtin::BIfmin:
- case Builtin::BIfminf:
- case Builtin::BIfminl:
- case Builtin::BI__builtin_fmin:
- case Builtin::BI__builtin_fminf:
- case Builtin::BI__builtin_fminl:
- return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::minnum));
-
- // fmod() is a special-case. It maps to the frem instruction rather than an
- // LLVM intrinsic.
- case Builtin::BIfmod:
- case Builtin::BIfmodf:
- case Builtin::BIfmodl:
- case Builtin::BI__builtin_fmod:
- case Builtin::BI__builtin_fmodf:
- case Builtin::BI__builtin_fmodl: {
- Value *Arg1 = EmitScalarExpr(E->getArg(0));
- Value *Arg2 = EmitScalarExpr(E->getArg(1));
- return RValue::get(Builder.CreateFRem(Arg1, Arg2, "fmod"));
- }
-
- case Builtin::BIlog:
- case Builtin::BIlogf:
- case Builtin::BIlogl:
- case Builtin::BI__builtin_log:
- case Builtin::BI__builtin_logf:
- case Builtin::BI__builtin_logl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log));
-
- case Builtin::BIlog10:
- case Builtin::BIlog10f:
- case Builtin::BIlog10l:
- case Builtin::BI__builtin_log10:
- case Builtin::BI__builtin_log10f:
- case Builtin::BI__builtin_log10l:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log10));
-
- case Builtin::BIlog2:
- case Builtin::BIlog2f:
- case Builtin::BIlog2l:
- case Builtin::BI__builtin_log2:
- case Builtin::BI__builtin_log2f:
- case Builtin::BI__builtin_log2l:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log2));
-
- case Builtin::BInearbyint:
- case Builtin::BInearbyintf:
- case Builtin::BInearbyintl:
- case Builtin::BI__builtin_nearbyint:
- case Builtin::BI__builtin_nearbyintf:
- case Builtin::BI__builtin_nearbyintl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::nearbyint));
-
- case Builtin::BIpow:
- case Builtin::BIpowf:
- case Builtin::BIpowl:
- case Builtin::BI__builtin_pow:
- case Builtin::BI__builtin_powf:
- case Builtin::BI__builtin_powl:
- return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::pow));
-
- case Builtin::BIrint:
- case Builtin::BIrintf:
- case Builtin::BIrintl:
- case Builtin::BI__builtin_rint:
- case Builtin::BI__builtin_rintf:
- case Builtin::BI__builtin_rintl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint));
-
- case Builtin::BIround:
- case Builtin::BIroundf:
- case Builtin::BIroundl:
- case Builtin::BI__builtin_round:
- case Builtin::BI__builtin_roundf:
- case Builtin::BI__builtin_roundl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::round));
-
- case Builtin::BIsin:
- case Builtin::BIsinf:
- case Builtin::BIsinl:
- case Builtin::BI__builtin_sin:
- case Builtin::BI__builtin_sinf:
- case Builtin::BI__builtin_sinl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sin));
-
- case Builtin::BIsqrt:
- case Builtin::BIsqrtf:
- case Builtin::BIsqrtl:
- case Builtin::BI__builtin_sqrt:
- case Builtin::BI__builtin_sqrtf:
- case Builtin::BI__builtin_sqrtl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt));
-
- case Builtin::BItrunc:
- case Builtin::BItruncf:
- case Builtin::BItruncl:
- case Builtin::BI__builtin_trunc:
- case Builtin::BI__builtin_truncf:
- case Builtin::BI__builtin_truncl:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::trunc));
-
- default:
- break;
- }
- }
-
- switch (BuiltinID) {
- default: break;
- case Builtin::BI__builtin___CFStringMakeConstantString:
- case Builtin::BI__builtin___NSStringMakeConstantString:
- return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
- case Builtin::BI__builtin_stdarg_start:
- case Builtin::BI__builtin_va_start:
- case Builtin::BI__va_start:
- case Builtin::BI__builtin_va_end:
- return RValue::get(
- EmitVAStartEnd(BuiltinID == Builtin::BI__va_start
- ? EmitScalarExpr(E->getArg(0))
- : EmitVAListRef(E->getArg(0)).getPointer(),
- BuiltinID != Builtin::BI__builtin_va_end));
- case Builtin::BI__builtin_va_copy: {
- Value *DstPtr = EmitVAListRef(E->getArg(0)).getPointer();
- Value *SrcPtr = EmitVAListRef(E->getArg(1)).getPointer();
-
- llvm::Type *Type = Int8PtrTy;
-
- DstPtr = Builder.CreateBitCast(DstPtr, Type);
- SrcPtr = Builder.CreateBitCast(SrcPtr, Type);
- return RValue::get(Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy),
- {DstPtr, SrcPtr}));
- }
- case Builtin::BI__builtin_abs:
- case Builtin::BI__builtin_labs:
- case Builtin::BI__builtin_llabs: {
- // X < 0 ? -X : X
- // The negation has 'nsw' because abs of INT_MIN is undefined.
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- Value *NegOp = Builder.CreateNSWNeg(ArgValue, "neg");
- Constant *Zero = llvm::Constant::getNullValue(ArgValue->getType());
- Value *CmpResult = Builder.CreateICmpSLT(ArgValue, Zero, "abscond");
- Value *Result = Builder.CreateSelect(CmpResult, NegOp, ArgValue, "abs");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_conj:
- case Builtin::BI__builtin_conjf:
- case Builtin::BI__builtin_conjl: {
- ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
- Value *Real = ComplexVal.first;
- Value *Imag = ComplexVal.second;
- Value *Zero =
- Imag->getType()->isFPOrFPVectorTy()
- ? llvm::ConstantFP::getZeroValueForNegation(Imag->getType())
- : llvm::Constant::getNullValue(Imag->getType());
-
- Imag = Builder.CreateFSub(Zero, Imag, "sub");
- return RValue::getComplex(std::make_pair(Real, Imag));
- }
- case Builtin::BI__builtin_creal:
- case Builtin::BI__builtin_crealf:
- case Builtin::BI__builtin_creall:
- case Builtin::BIcreal:
- case Builtin::BIcrealf:
- case Builtin::BIcreall: {
- ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
- return RValue::get(ComplexVal.first);
- }
-
- case Builtin::BI__builtin_dump_struct: {
- Value *Func = EmitScalarExpr(E->getArg(1)->IgnoreImpCasts());
- CharUnits Arg0Align = EmitPointerWithAlignment(E->getArg(0)).getAlignment();
-
- const Expr *Arg0 = E->getArg(0)->IgnoreImpCasts();
- QualType Arg0Type = Arg0->getType()->getPointeeType();
-
- Value *RecordPtr = EmitScalarExpr(Arg0);
- Value *Res = dumpRecord(*this, Arg0Type, RecordPtr, Arg0Align, Func, 0);
- return RValue::get(Res);
- }
-
- case Builtin::BI__builtin_cimag:
- case Builtin::BI__builtin_cimagf:
- case Builtin::BI__builtin_cimagl:
- case Builtin::BIcimag:
- case Builtin::BIcimagf:
- case Builtin::BIcimagl: {
- ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
- return RValue::get(ComplexVal.second);
- }
-
- case Builtin::BI__builtin_clrsb:
- case Builtin::BI__builtin_clrsbl:
- case Builtin::BI__builtin_clrsbll: {
- // clrsb(x) -> clz(x < 0 ? ~x : x) - 1 or
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
-
- llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Zero = llvm::Constant::getNullValue(ArgType);
- Value *IsNeg = Builder.CreateICmpSLT(ArgValue, Zero, "isneg");
- Value *Inverse = Builder.CreateNot(ArgValue, "not");
- Value *Tmp = Builder.CreateSelect(IsNeg, Inverse, ArgValue);
- Value *Ctlz = Builder.CreateCall(F, {Tmp, Builder.getFalse()});
- Value *Result = Builder.CreateSub(Ctlz, llvm::ConstantInt::get(ArgType, 1));
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_ctzs:
- case Builtin::BI__builtin_ctz:
- case Builtin::BI__builtin_ctzl:
- case Builtin::BI__builtin_ctzll: {
- Value *ArgValue = EmitCheckedArgForBuiltin(E->getArg(0), BCK_CTZPassedZero);
-
- llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef());
- Value *Result = Builder.CreateCall(F, {ArgValue, ZeroUndef});
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_clzs:
- case Builtin::BI__builtin_clz:
- case Builtin::BI__builtin_clzl:
- case Builtin::BI__builtin_clzll: {
- Value *ArgValue = EmitCheckedArgForBuiltin(E->getArg(0), BCK_CLZPassedZero);
-
- llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef());
- Value *Result = Builder.CreateCall(F, {ArgValue, ZeroUndef});
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_ffs:
- case Builtin::BI__builtin_ffsl:
- case Builtin::BI__builtin_ffsll: {
- // ffs(x) -> x ? cttz(x) + 1 : 0
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
-
- llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Tmp =
- Builder.CreateAdd(Builder.CreateCall(F, {ArgValue, Builder.getTrue()}),
- llvm::ConstantInt::get(ArgType, 1));
- Value *Zero = llvm::Constant::getNullValue(ArgType);
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
- Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs");
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_parity:
- case Builtin::BI__builtin_parityl:
- case Builtin::BI__builtin_parityll: {
- // parity(x) -> ctpop(x) & 1
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
-
- llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Tmp = Builder.CreateCall(F, ArgValue);
- Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1));
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
- return RValue::get(Result);
- }
- case Builtin::BI__lzcnt16:
- case Builtin::BI__lzcnt:
- case Builtin::BI__lzcnt64: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
-
- llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
- return RValue::get(Result);
- }
- case Builtin::BI__popcnt16:
- case Builtin::BI__popcnt:
- case Builtin::BI__popcnt64:
- case Builtin::BI__builtin_popcount:
- case Builtin::BI__builtin_popcountl:
- case Builtin::BI__builtin_popcountll: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
-
- llvm::Type *ArgType = ArgValue->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall(F, ArgValue);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
- "cast");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_unpredictable: {
- // Always return the argument of __builtin_unpredictable. LLVM does not
- // handle this builtin. Metadata for this builtin should be added directly
- // to instructions such as branches or switches that use it.
- return RValue::get(EmitScalarExpr(E->getArg(0)));
- }
- case Builtin::BI__builtin_expect: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
-
- Value *ExpectedValue = EmitScalarExpr(E->getArg(1));
- // Don't generate llvm.expect on -O0 as the backend won't use it for
- // anything.
- // Note, we still IRGen ExpectedValue because it could have side-effects.
- if (CGM.getCodeGenOpts().OptimizationLevel == 0)
- return RValue::get(ArgValue);
-
- Value *FnExpect = CGM.getIntrinsic(Intrinsic::expect, ArgType);
- Value *Result =
- Builder.CreateCall(FnExpect, {ArgValue, ExpectedValue}, "expval");
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_assume_aligned: {
- const Expr *Ptr = E->getArg(0);
- Value *PtrValue = EmitScalarExpr(Ptr);
- Value *OffsetValue =
- (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : nullptr;
-
- Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
- ConstantInt *AlignmentCI = cast<ConstantInt>(AlignmentValue);
- unsigned Alignment = (unsigned)AlignmentCI->getZExtValue();
-
- EmitAlignmentAssumption(PtrValue, Ptr, /*The expr loc is sufficient.*/ SourceLocation(),
- Alignment, OffsetValue);
- return RValue::get(PtrValue);
- }
- case Builtin::BI__assume:
- case Builtin::BI__builtin_assume: {
- if (E->getArg(0)->HasSideEffects(getContext()))
- return RValue::get(nullptr);
-
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- Value *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
- return RValue::get(Builder.CreateCall(FnAssume, ArgValue));
- }
- case Builtin::BI__builtin_bswap16:
- case Builtin::BI__builtin_bswap32:
- case Builtin::BI__builtin_bswap64: {
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::bswap));
- }
- case Builtin::BI__builtin_bitreverse8:
- case Builtin::BI__builtin_bitreverse16:
- case Builtin::BI__builtin_bitreverse32:
- case Builtin::BI__builtin_bitreverse64: {
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::bitreverse));
- }
- case Builtin::BI__builtin_rotateleft8:
- case Builtin::BI__builtin_rotateleft16:
- case Builtin::BI__builtin_rotateleft32:
- case Builtin::BI__builtin_rotateleft64:
- case Builtin::BI_rotl8: // Microsoft variants of rotate left
- case Builtin::BI_rotl16:
- case Builtin::BI_rotl:
- case Builtin::BI_lrotl:
- case Builtin::BI_rotl64:
- return emitRotate(E, false);
-
- case Builtin::BI__builtin_rotateright8:
- case Builtin::BI__builtin_rotateright16:
- case Builtin::BI__builtin_rotateright32:
- case Builtin::BI__builtin_rotateright64:
- case Builtin::BI_rotr8: // Microsoft variants of rotate right
- case Builtin::BI_rotr16:
- case Builtin::BI_rotr:
- case Builtin::BI_lrotr:
- case Builtin::BI_rotr64:
- return emitRotate(E, true);
-
- case Builtin::BI__builtin_constant_p: {
- llvm::Type *ResultType = ConvertType(E->getType());
- if (CGM.getCodeGenOpts().OptimizationLevel == 0)
- // At -O0, we don't perform inlining, so we don't need to delay the
- // processing.
- return RValue::get(ConstantInt::get(ResultType, 0));
-
- const Expr *Arg = E->getArg(0);
- QualType ArgType = Arg->getType();
- if (!hasScalarEvaluationKind(ArgType) || ArgType->isFunctionType())
- // We can only reason about scalar types.
- return RValue::get(ConstantInt::get(ResultType, 0));
-
- Value *ArgValue = EmitScalarExpr(Arg);
- Value *F = CGM.getIntrinsic(Intrinsic::is_constant, ConvertType(ArgType));
- Value *Result = Builder.CreateCall(F, ArgValue);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/false);
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_object_size: {
- unsigned Type =
- E->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue();
- auto *ResType = cast<llvm::IntegerType>(ConvertType(E->getType()));
-
- // We pass this builtin onto the optimizer so that it can figure out the
- // object size in more complex cases.
- return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
- /*EmittedE=*/nullptr));
- }
- case Builtin::BI__builtin_prefetch: {
- Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
- // FIXME: Technically these constants should of type 'int', yes?
- RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) :
- llvm::ConstantInt::get(Int32Ty, 0);
- Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) :
- llvm::ConstantInt::get(Int32Ty, 3);
- Value *Data = llvm::ConstantInt::get(Int32Ty, 1);
- Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
- return RValue::get(Builder.CreateCall(F, {Address, RW, Locality, Data}));
- }
- case Builtin::BI__builtin_readcyclecounter: {
- Value *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
- return RValue::get(Builder.CreateCall(F));
- }
- case Builtin::BI__builtin___clear_cache: {
- Value *Begin = EmitScalarExpr(E->getArg(0));
- Value *End = EmitScalarExpr(E->getArg(1));
- Value *F = CGM.getIntrinsic(Intrinsic::clear_cache);
- return RValue::get(Builder.CreateCall(F, {Begin, End}));
- }
- case Builtin::BI__builtin_trap:
- return RValue::get(EmitTrapCall(Intrinsic::trap));
- case Builtin::BI__debugbreak:
- return RValue::get(EmitTrapCall(Intrinsic::debugtrap));
- case Builtin::BI__builtin_unreachable: {
- EmitUnreachable(E->getExprLoc());
-
- // We do need to preserve an insertion point.
- EmitBlock(createBasicBlock("unreachable.cont"));
-
- return RValue::get(nullptr);
- }
-
- case Builtin::BI__builtin_powi:
- case Builtin::BI__builtin_powif:
- case Builtin::BI__builtin_powil: {
- Value *Base = EmitScalarExpr(E->getArg(0));
- Value *Exponent = EmitScalarExpr(E->getArg(1));
- llvm::Type *ArgType = Base->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::powi, ArgType);
- return RValue::get(Builder.CreateCall(F, {Base, Exponent}));
- }
-
- case Builtin::BI__builtin_isgreater:
- case Builtin::BI__builtin_isgreaterequal:
- case Builtin::BI__builtin_isless:
- case Builtin::BI__builtin_islessequal:
- case Builtin::BI__builtin_islessgreater:
- case Builtin::BI__builtin_isunordered: {
- // Ordered comparisons: we know the arguments to these are matching scalar
- // floating point values.
- Value *LHS = EmitScalarExpr(E->getArg(0));
- Value *RHS = EmitScalarExpr(E->getArg(1));
-
- switch (BuiltinID) {
- default: llvm_unreachable("Unknown ordered comparison");
- case Builtin::BI__builtin_isgreater:
- LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp");
- break;
- case Builtin::BI__builtin_isgreaterequal:
- LHS = Builder.CreateFCmpOGE(LHS, RHS, "cmp");
- break;
- case Builtin::BI__builtin_isless:
- LHS = Builder.CreateFCmpOLT(LHS, RHS, "cmp");
- break;
- case Builtin::BI__builtin_islessequal:
- LHS = Builder.CreateFCmpOLE(LHS, RHS, "cmp");
- break;
- case Builtin::BI__builtin_islessgreater:
- LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp");
- break;
- case Builtin::BI__builtin_isunordered:
- LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp");
- break;
- }
- // ZExt bool to int type.
- return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType())));
- }
- case Builtin::BI__builtin_isnan: {
- Value *V = EmitScalarExpr(E->getArg(0));
- V = Builder.CreateFCmpUNO(V, V, "cmp");
- return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
- }
-
- case Builtin::BIfinite:
- case Builtin::BI__finite:
- case Builtin::BIfinitef:
- case Builtin::BI__finitef:
- case Builtin::BIfinitel:
- case Builtin::BI__finitel:
- case Builtin::BI__builtin_isinf:
- case Builtin::BI__builtin_isfinite: {
- // isinf(x) --> fabs(x) == infinity
- // isfinite(x) --> fabs(x) != infinity
- // x != NaN via the ordered compare in either case.
- Value *V = EmitScalarExpr(E->getArg(0));
- Value *Fabs = EmitFAbs(*this, V);
- Constant *Infinity = ConstantFP::getInfinity(V->getType());
- CmpInst::Predicate Pred = (BuiltinID == Builtin::BI__builtin_isinf)
- ? CmpInst::FCMP_OEQ
- : CmpInst::FCMP_ONE;
- Value *FCmp = Builder.CreateFCmp(Pred, Fabs, Infinity, "cmpinf");
- return RValue::get(Builder.CreateZExt(FCmp, ConvertType(E->getType())));
- }
-
- case Builtin::BI__builtin_isinf_sign: {
- // isinf_sign(x) -> fabs(x) == infinity ? (signbit(x) ? -1 : 1) : 0
- Value *Arg = EmitScalarExpr(E->getArg(0));
- Value *AbsArg = EmitFAbs(*this, Arg);
- Value *IsInf = Builder.CreateFCmpOEQ(
- AbsArg, ConstantFP::getInfinity(Arg->getType()), "isinf");
- Value *IsNeg = EmitSignBit(*this, Arg);
-
- llvm::Type *IntTy = ConvertType(E->getType());
- Value *Zero = Constant::getNullValue(IntTy);
- Value *One = ConstantInt::get(IntTy, 1);
- Value *NegativeOne = ConstantInt::get(IntTy, -1);
- Value *SignResult = Builder.CreateSelect(IsNeg, NegativeOne, One);
- Value *Result = Builder.CreateSelect(IsInf, SignResult, Zero);
- return RValue::get(Result);
- }
-
- case Builtin::BI__builtin_isnormal: {
- // isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min
- Value *V = EmitScalarExpr(E->getArg(0));
- Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
-
- Value *Abs = EmitFAbs(*this, V);
- Value *IsLessThanInf =
- Builder.CreateFCmpULT(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
- APFloat Smallest = APFloat::getSmallestNormalized(
- getContext().getFloatTypeSemantics(E->getArg(0)->getType()));
- Value *IsNormal =
- Builder.CreateFCmpUGE(Abs, ConstantFP::get(V->getContext(), Smallest),
- "isnormal");
- V = Builder.CreateAnd(Eq, IsLessThanInf, "and");
- V = Builder.CreateAnd(V, IsNormal, "and");
- return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
- }
-
- case Builtin::BI__builtin_fpclassify: {
- Value *V = EmitScalarExpr(E->getArg(5));
- llvm::Type *Ty = ConvertType(E->getArg(5)->getType());
-
- // Create Result
- BasicBlock *Begin = Builder.GetInsertBlock();
- BasicBlock *End = createBasicBlock("fpclassify_end", this->CurFn);
- Builder.SetInsertPoint(End);
- PHINode *Result =
- Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 4,
- "fpclassify_result");
-
- // if (V==0) return FP_ZERO
- Builder.SetInsertPoint(Begin);
- Value *IsZero = Builder.CreateFCmpOEQ(V, Constant::getNullValue(Ty),
- "iszero");
- Value *ZeroLiteral = EmitScalarExpr(E->getArg(4));
- BasicBlock *NotZero = createBasicBlock("fpclassify_not_zero", this->CurFn);
- Builder.CreateCondBr(IsZero, End, NotZero);
- Result->addIncoming(ZeroLiteral, Begin);
-
- // if (V != V) return FP_NAN
- Builder.SetInsertPoint(NotZero);
- Value *IsNan = Builder.CreateFCmpUNO(V, V, "cmp");
- Value *NanLiteral = EmitScalarExpr(E->getArg(0));
- BasicBlock *NotNan = createBasicBlock("fpclassify_not_nan", this->CurFn);
- Builder.CreateCondBr(IsNan, End, NotNan);
- Result->addIncoming(NanLiteral, NotZero);
-
- // if (fabs(V) == infinity) return FP_INFINITY
- Builder.SetInsertPoint(NotNan);
- Value *VAbs = EmitFAbs(*this, V);
- Value *IsInf =
- Builder.CreateFCmpOEQ(VAbs, ConstantFP::getInfinity(V->getType()),
- "isinf");
- Value *InfLiteral = EmitScalarExpr(E->getArg(1));
- BasicBlock *NotInf = createBasicBlock("fpclassify_not_inf", this->CurFn);
- Builder.CreateCondBr(IsInf, End, NotInf);
- Result->addIncoming(InfLiteral, NotNan);
-
- // if (fabs(V) >= MIN_NORMAL) return FP_NORMAL else FP_SUBNORMAL
- Builder.SetInsertPoint(NotInf);
- APFloat Smallest = APFloat::getSmallestNormalized(
- getContext().getFloatTypeSemantics(E->getArg(5)->getType()));
- Value *IsNormal =
- Builder.CreateFCmpUGE(VAbs, ConstantFP::get(V->getContext(), Smallest),
- "isnormal");
- Value *NormalResult =
- Builder.CreateSelect(IsNormal, EmitScalarExpr(E->getArg(2)),
- EmitScalarExpr(E->getArg(3)));
- Builder.CreateBr(End);
- Result->addIncoming(NormalResult, NotInf);
-
- // return Result
- Builder.SetInsertPoint(End);
- return RValue::get(Result);
- }
-
- case Builtin::BIalloca:
- case Builtin::BI_alloca:
- case Builtin::BI__builtin_alloca: {
- Value *Size = EmitScalarExpr(E->getArg(0));
- const TargetInfo &TI = getContext().getTargetInfo();
- // The alignment of the alloca should correspond to __BIGGEST_ALIGNMENT__.
- unsigned SuitableAlignmentInBytes =
- CGM.getContext()
- .toCharUnitsFromBits(TI.getSuitableAlign())
- .getQuantity();
- AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
- AI->setAlignment(SuitableAlignmentInBytes);
- return RValue::get(AI);
- }
-
- case Builtin::BI__builtin_alloca_with_align: {
- Value *Size = EmitScalarExpr(E->getArg(0));
- Value *AlignmentInBitsValue = EmitScalarExpr(E->getArg(1));
- auto *AlignmentInBitsCI = cast<ConstantInt>(AlignmentInBitsValue);
- unsigned AlignmentInBits = AlignmentInBitsCI->getZExtValue();
- unsigned AlignmentInBytes =
- CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getQuantity();
- AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
- AI->setAlignment(AlignmentInBytes);
- return RValue::get(AI);
- }
-
- case Builtin::BIbzero:
- case Builtin::BI__builtin_bzero: {
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Value *SizeVal = EmitScalarExpr(E->getArg(1));
- EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(),
- E->getArg(0)->getExprLoc(), FD, 0);
- Builder.CreateMemSet(Dest, Builder.getInt8(0), SizeVal, false);
- return RValue::get(nullptr);
- }
- case Builtin::BImemcpy:
- case Builtin::BI__builtin_memcpy: {
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Address Src = EmitPointerWithAlignment(E->getArg(1));
- Value *SizeVal = EmitScalarExpr(E->getArg(2));
- EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(),
- E->getArg(0)->getExprLoc(), FD, 0);
- EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(),
- E->getArg(1)->getExprLoc(), FD, 1);
- Builder.CreateMemCpy(Dest, Src, SizeVal, false);
- return RValue::get(Dest.getPointer());
- }
-
- case Builtin::BI__builtin_char_memchr:
- BuiltinID = Builtin::BI__builtin_memchr;
- break;
-
- case Builtin::BI__builtin___memcpy_chk: {
- // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memcpy iff cst1<=cst2.
- Expr::EvalResult SizeResult, DstSizeResult;
- if (!E->getArg(2)->EvaluateAsInt(SizeResult, CGM.getContext()) ||
- !E->getArg(3)->EvaluateAsInt(DstSizeResult, CGM.getContext()))
- break;
- llvm::APSInt Size = SizeResult.Val.getInt();
- llvm::APSInt DstSize = DstSizeResult.Val.getInt();
- if (Size.ugt(DstSize))
- break;
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Address Src = EmitPointerWithAlignment(E->getArg(1));
- Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- Builder.CreateMemCpy(Dest, Src, SizeVal, false);
- return RValue::get(Dest.getPointer());
- }
-
- case Builtin::BI__builtin_objc_memmove_collectable: {
- Address DestAddr = EmitPointerWithAlignment(E->getArg(0));
- Address SrcAddr = EmitPointerWithAlignment(E->getArg(1));
- Value *SizeVal = EmitScalarExpr(E->getArg(2));
- CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this,
- DestAddr, SrcAddr, SizeVal);
- return RValue::get(DestAddr.getPointer());
- }
-
- case Builtin::BI__builtin___memmove_chk: {
- // fold __builtin_memmove_chk(x, y, cst1, cst2) to memmove iff cst1<=cst2.
- Expr::EvalResult SizeResult, DstSizeResult;
- if (!E->getArg(2)->EvaluateAsInt(SizeResult, CGM.getContext()) ||
- !E->getArg(3)->EvaluateAsInt(DstSizeResult, CGM.getContext()))
- break;
- llvm::APSInt Size = SizeResult.Val.getInt();
- llvm::APSInt DstSize = DstSizeResult.Val.getInt();
- if (Size.ugt(DstSize))
- break;
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Address Src = EmitPointerWithAlignment(E->getArg(1));
- Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- Builder.CreateMemMove(Dest, Src, SizeVal, false);
- return RValue::get(Dest.getPointer());
- }
-
- case Builtin::BImemmove:
- case Builtin::BI__builtin_memmove: {
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Address Src = EmitPointerWithAlignment(E->getArg(1));
- Value *SizeVal = EmitScalarExpr(E->getArg(2));
- EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(),
- E->getArg(0)->getExprLoc(), FD, 0);
- EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(),
- E->getArg(1)->getExprLoc(), FD, 1);
- Builder.CreateMemMove(Dest, Src, SizeVal, false);
- return RValue::get(Dest.getPointer());
- }
- case Builtin::BImemset:
- case Builtin::BI__builtin_memset: {
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
- Builder.getInt8Ty());
- Value *SizeVal = EmitScalarExpr(E->getArg(2));
- EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(),
- E->getArg(0)->getExprLoc(), FD, 0);
- Builder.CreateMemSet(Dest, ByteVal, SizeVal, false);
- return RValue::get(Dest.getPointer());
- }
- case Builtin::BI__builtin___memset_chk: {
- // fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
- Expr::EvalResult SizeResult, DstSizeResult;
- if (!E->getArg(2)->EvaluateAsInt(SizeResult, CGM.getContext()) ||
- !E->getArg(3)->EvaluateAsInt(DstSizeResult, CGM.getContext()))
- break;
- llvm::APSInt Size = SizeResult.Val.getInt();
- llvm::APSInt DstSize = DstSizeResult.Val.getInt();
- if (Size.ugt(DstSize))
- break;
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
- Builder.getInt8Ty());
- Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- Builder.CreateMemSet(Dest, ByteVal, SizeVal, false);
- return RValue::get(Dest.getPointer());
- }
- case Builtin::BI__builtin_wmemcmp: {
- // The MSVC runtime library does not provide a definition of wmemcmp, so we
- // need an inline implementation.
- if (!getTarget().getTriple().isOSMSVCRT())
- break;
-
- llvm::Type *WCharTy = ConvertType(getContext().WCharTy);
-
- Value *Dst = EmitScalarExpr(E->getArg(0));
- Value *Src = EmitScalarExpr(E->getArg(1));
- Value *Size = EmitScalarExpr(E->getArg(2));
-
- BasicBlock *Entry = Builder.GetInsertBlock();
- BasicBlock *CmpGT = createBasicBlock("wmemcmp.gt");
- BasicBlock *CmpLT = createBasicBlock("wmemcmp.lt");
- BasicBlock *Next = createBasicBlock("wmemcmp.next");
- BasicBlock *Exit = createBasicBlock("wmemcmp.exit");
- Value *SizeEq0 = Builder.CreateICmpEQ(Size, ConstantInt::get(SizeTy, 0));
- Builder.CreateCondBr(SizeEq0, Exit, CmpGT);
-
- EmitBlock(CmpGT);
- PHINode *DstPhi = Builder.CreatePHI(Dst->getType(), 2);
- DstPhi->addIncoming(Dst, Entry);
- PHINode *SrcPhi = Builder.CreatePHI(Src->getType(), 2);
- SrcPhi->addIncoming(Src, Entry);
- PHINode *SizePhi = Builder.CreatePHI(SizeTy, 2);
- SizePhi->addIncoming(Size, Entry);
- CharUnits WCharAlign =
- getContext().getTypeAlignInChars(getContext().WCharTy);
- Value *DstCh = Builder.CreateAlignedLoad(WCharTy, DstPhi, WCharAlign);
- Value *SrcCh = Builder.CreateAlignedLoad(WCharTy, SrcPhi, WCharAlign);
- Value *DstGtSrc = Builder.CreateICmpUGT(DstCh, SrcCh);
- Builder.CreateCondBr(DstGtSrc, Exit, CmpLT);
-
- EmitBlock(CmpLT);
- Value *DstLtSrc = Builder.CreateICmpULT(DstCh, SrcCh);
- Builder.CreateCondBr(DstLtSrc, Exit, Next);
-
- EmitBlock(Next);
- Value *NextDst = Builder.CreateConstInBoundsGEP1_32(WCharTy, DstPhi, 1);
- Value *NextSrc = Builder.CreateConstInBoundsGEP1_32(WCharTy, SrcPhi, 1);
- Value *NextSize = Builder.CreateSub(SizePhi, ConstantInt::get(SizeTy, 1));
- Value *NextSizeEq0 =
- Builder.CreateICmpEQ(NextSize, ConstantInt::get(SizeTy, 0));
- Builder.CreateCondBr(NextSizeEq0, Exit, CmpGT);
- DstPhi->addIncoming(NextDst, Next);
- SrcPhi->addIncoming(NextSrc, Next);
- SizePhi->addIncoming(NextSize, Next);
-
- EmitBlock(Exit);
- PHINode *Ret = Builder.CreatePHI(IntTy, 4);
- Ret->addIncoming(ConstantInt::get(IntTy, 0), Entry);
- Ret->addIncoming(ConstantInt::get(IntTy, 1), CmpGT);
- Ret->addIncoming(ConstantInt::get(IntTy, -1), CmpLT);
- Ret->addIncoming(ConstantInt::get(IntTy, 0), Next);
- return RValue::get(Ret);
- }
- case Builtin::BI__builtin_dwarf_cfa: {
- // The offset in bytes from the first argument to the CFA.
- //
- // Why on earth is this in the frontend? Is there any reason at
- // all that the backend can't reasonably determine this while
- // lowering llvm.eh.dwarf.cfa()?
- //
- // TODO: If there's a satisfactory reason, add a target hook for
- // this instead of hard-coding 0, which is correct for most targets.
- int32_t Offset = 0;
-
- Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa);
- return RValue::get(Builder.CreateCall(F,
- llvm::ConstantInt::get(Int32Ty, Offset)));
- }
- case Builtin::BI__builtin_return_address: {
- Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0),
- getContext().UnsignedIntTy);
- Value *F = CGM.getIntrinsic(Intrinsic::returnaddress);
- return RValue::get(Builder.CreateCall(F, Depth));
- }
- case Builtin::BI_ReturnAddress: {
- Value *F = CGM.getIntrinsic(Intrinsic::returnaddress);
- return RValue::get(Builder.CreateCall(F, Builder.getInt32(0)));
- }
- case Builtin::BI__builtin_frame_address: {
- Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0),
- getContext().UnsignedIntTy);
- Value *F = CGM.getIntrinsic(Intrinsic::frameaddress);
- return RValue::get(Builder.CreateCall(F, Depth));
- }
- case Builtin::BI__builtin_extract_return_addr: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *Result = getTargetHooks().decodeReturnAddress(*this, Address);
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_frob_return_addr: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *Result = getTargetHooks().encodeReturnAddress(*this, Address);
- return RValue::get(Result);
- }
- case Builtin::BI__builtin_dwarf_sp_column: {
- llvm::IntegerType *Ty
- = cast<llvm::IntegerType>(ConvertType(E->getType()));
- int Column = getTargetHooks().getDwarfEHStackPointer(CGM);
- if (Column == -1) {
- CGM.ErrorUnsupported(E, "__builtin_dwarf_sp_column");
- return RValue::get(llvm::UndefValue::get(Ty));
- }
- return RValue::get(llvm::ConstantInt::get(Ty, Column, true));
- }
- case Builtin::BI__builtin_init_dwarf_reg_size_table: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- if (getTargetHooks().initDwarfEHRegSizeTable(*this, Address))
- CGM.ErrorUnsupported(E, "__builtin_init_dwarf_reg_size_table");
- return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
- }
- case Builtin::BI__builtin_eh_return: {
- Value *Int = EmitScalarExpr(E->getArg(0));
- Value *Ptr = EmitScalarExpr(E->getArg(1));
-
- llvm::IntegerType *IntTy = cast<llvm::IntegerType>(Int->getType());
- assert((IntTy->getBitWidth() == 32 || IntTy->getBitWidth() == 64) &&
- "LLVM's __builtin_eh_return only supports 32- and 64-bit variants");
- Value *F = CGM.getIntrinsic(IntTy->getBitWidth() == 32
- ? Intrinsic::eh_return_i32
- : Intrinsic::eh_return_i64);
- Builder.CreateCall(F, {Int, Ptr});
- Builder.CreateUnreachable();
-
- // We do need to preserve an insertion point.
- EmitBlock(createBasicBlock("builtin_eh_return.cont"));
-
- return RValue::get(nullptr);
- }
- case Builtin::BI__builtin_unwind_init: {
- Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init);
- return RValue::get(Builder.CreateCall(F));
- }
- case Builtin::BI__builtin_extend_pointer: {
- // Extends a pointer to the size of an _Unwind_Word, which is
- // uint64_t on all platforms. Generally this gets poked into a
- // register and eventually used as an address, so if the
- // addressing registers are wider than pointers and the platform
- // doesn't implicitly ignore high-order bits when doing
- // addressing, we need to make sure we zext / sext based on
- // the platform's expectations.
- //
- // See: http://gcc.gnu.org/ml/gcc-bugs/2002-02/msg00237.html
-
- // Cast the pointer to intptr_t.
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- Value *Result = Builder.CreatePtrToInt(Ptr, IntPtrTy, "extend.cast");
-
- // If that's 64 bits, we're done.
- if (IntPtrTy->getBitWidth() == 64)
- return RValue::get(Result);
-
- // Otherwise, ask the codegen data what to do.
- if (getTargetHooks().extendPointerWithSExt())
- return RValue::get(Builder.CreateSExt(Result, Int64Ty, "extend.sext"));
- else
- return RValue::get(Builder.CreateZExt(Result, Int64Ty, "extend.zext"));
- }
- case Builtin::BI__builtin_setjmp: {
- // Buffer is a void**.
- Address Buf = EmitPointerWithAlignment(E->getArg(0));
-
- // Store the frame pointer to the setjmp buffer.
- Value *FrameAddr =
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::frameaddress),
- ConstantInt::get(Int32Ty, 0));
- Builder.CreateStore(FrameAddr, Buf);
-
- // Store the stack pointer to the setjmp buffer.
- Value *StackAddr =
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::stacksave));
- Address StackSaveSlot =
- Builder.CreateConstInBoundsGEP(Buf, 2, getPointerSize());
- Builder.CreateStore(StackAddr, StackSaveSlot);
-
- // Call LLVM's EH setjmp, which is lightweight.
- Value *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
- Buf = Builder.CreateBitCast(Buf, Int8PtrTy);
- return RValue::get(Builder.CreateCall(F, Buf.getPointer()));
- }
- case Builtin::BI__builtin_longjmp: {
- Value *Buf = EmitScalarExpr(E->getArg(0));
- Buf = Builder.CreateBitCast(Buf, Int8PtrTy);
-
- // Call LLVM's EH longjmp, which is lightweight.
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::eh_sjlj_longjmp), Buf);
-
- // longjmp doesn't return; mark this as unreachable.
- Builder.CreateUnreachable();
-
- // We do need to preserve an insertion point.
- EmitBlock(createBasicBlock("longjmp.cont"));
-
- return RValue::get(nullptr);
- }
- case Builtin::BI__builtin_launder: {
- const Expr *Arg = E->getArg(0);
- QualType ArgTy = Arg->getType()->getPointeeType();
- Value *Ptr = EmitScalarExpr(Arg);
- if (TypeRequiresBuiltinLaunder(CGM, ArgTy))
- Ptr = Builder.CreateLaunderInvariantGroup(Ptr);
-
- return RValue::get(Ptr);
- }
- case Builtin::BI__sync_fetch_and_add:
- case Builtin::BI__sync_fetch_and_sub:
- case Builtin::BI__sync_fetch_and_or:
- case Builtin::BI__sync_fetch_and_and:
- case Builtin::BI__sync_fetch_and_xor:
- case Builtin::BI__sync_fetch_and_nand:
- case Builtin::BI__sync_add_and_fetch:
- case Builtin::BI__sync_sub_and_fetch:
- case Builtin::BI__sync_and_and_fetch:
- case Builtin::BI__sync_or_and_fetch:
- case Builtin::BI__sync_xor_and_fetch:
- case Builtin::BI__sync_nand_and_fetch:
- case Builtin::BI__sync_val_compare_and_swap:
- case Builtin::BI__sync_bool_compare_and_swap:
- case Builtin::BI__sync_lock_test_and_set:
- case Builtin::BI__sync_lock_release:
- case Builtin::BI__sync_swap:
- llvm_unreachable("Shouldn't make it through sema");
- case Builtin::BI__sync_fetch_and_add_1:
- case Builtin::BI__sync_fetch_and_add_2:
- case Builtin::BI__sync_fetch_and_add_4:
- case Builtin::BI__sync_fetch_and_add_8:
- case Builtin::BI__sync_fetch_and_add_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Add, E);
- case Builtin::BI__sync_fetch_and_sub_1:
- case Builtin::BI__sync_fetch_and_sub_2:
- case Builtin::BI__sync_fetch_and_sub_4:
- case Builtin::BI__sync_fetch_and_sub_8:
- case Builtin::BI__sync_fetch_and_sub_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Sub, E);
- case Builtin::BI__sync_fetch_and_or_1:
- case Builtin::BI__sync_fetch_and_or_2:
- case Builtin::BI__sync_fetch_and_or_4:
- case Builtin::BI__sync_fetch_and_or_8:
- case Builtin::BI__sync_fetch_and_or_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Or, E);
- case Builtin::BI__sync_fetch_and_and_1:
- case Builtin::BI__sync_fetch_and_and_2:
- case Builtin::BI__sync_fetch_and_and_4:
- case Builtin::BI__sync_fetch_and_and_8:
- case Builtin::BI__sync_fetch_and_and_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::And, E);
- case Builtin::BI__sync_fetch_and_xor_1:
- case Builtin::BI__sync_fetch_and_xor_2:
- case Builtin::BI__sync_fetch_and_xor_4:
- case Builtin::BI__sync_fetch_and_xor_8:
- case Builtin::BI__sync_fetch_and_xor_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xor, E);
- case Builtin::BI__sync_fetch_and_nand_1:
- case Builtin::BI__sync_fetch_and_nand_2:
- case Builtin::BI__sync_fetch_and_nand_4:
- case Builtin::BI__sync_fetch_and_nand_8:
- case Builtin::BI__sync_fetch_and_nand_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Nand, E);
-
- // Clang extensions: not overloaded yet.
- case Builtin::BI__sync_fetch_and_min:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Min, E);
- case Builtin::BI__sync_fetch_and_max:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Max, E);
- case Builtin::BI__sync_fetch_and_umin:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::UMin, E);
- case Builtin::BI__sync_fetch_and_umax:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::UMax, E);
-
- case Builtin::BI__sync_add_and_fetch_1:
- case Builtin::BI__sync_add_and_fetch_2:
- case Builtin::BI__sync_add_and_fetch_4:
- case Builtin::BI__sync_add_and_fetch_8:
- case Builtin::BI__sync_add_and_fetch_16:
- return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Add, E,
- llvm::Instruction::Add);
- case Builtin::BI__sync_sub_and_fetch_1:
- case Builtin::BI__sync_sub_and_fetch_2:
- case Builtin::BI__sync_sub_and_fetch_4:
- case Builtin::BI__sync_sub_and_fetch_8:
- case Builtin::BI__sync_sub_and_fetch_16:
- return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Sub, E,
- llvm::Instruction::Sub);
- case Builtin::BI__sync_and_and_fetch_1:
- case Builtin::BI__sync_and_and_fetch_2:
- case Builtin::BI__sync_and_and_fetch_4:
- case Builtin::BI__sync_and_and_fetch_8:
- case Builtin::BI__sync_and_and_fetch_16:
- return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::And, E,
- llvm::Instruction::And);
- case Builtin::BI__sync_or_and_fetch_1:
- case Builtin::BI__sync_or_and_fetch_2:
- case Builtin::BI__sync_or_and_fetch_4:
- case Builtin::BI__sync_or_and_fetch_8:
- case Builtin::BI__sync_or_and_fetch_16:
- return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Or, E,
- llvm::Instruction::Or);
- case Builtin::BI__sync_xor_and_fetch_1:
- case Builtin::BI__sync_xor_and_fetch_2:
- case Builtin::BI__sync_xor_and_fetch_4:
- case Builtin::BI__sync_xor_and_fetch_8:
- case Builtin::BI__sync_xor_and_fetch_16:
- return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Xor, E,
- llvm::Instruction::Xor);
- case Builtin::BI__sync_nand_and_fetch_1:
- case Builtin::BI__sync_nand_and_fetch_2:
- case Builtin::BI__sync_nand_and_fetch_4:
- case Builtin::BI__sync_nand_and_fetch_8:
- case Builtin::BI__sync_nand_and_fetch_16:
- return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Nand, E,
- llvm::Instruction::And, true);
-
- case Builtin::BI__sync_val_compare_and_swap_1:
- case Builtin::BI__sync_val_compare_and_swap_2:
- case Builtin::BI__sync_val_compare_and_swap_4:
- case Builtin::BI__sync_val_compare_and_swap_8:
- case Builtin::BI__sync_val_compare_and_swap_16:
- return RValue::get(MakeAtomicCmpXchgValue(*this, E, false));
-
- case Builtin::BI__sync_bool_compare_and_swap_1:
- case Builtin::BI__sync_bool_compare_and_swap_2:
- case Builtin::BI__sync_bool_compare_and_swap_4:
- case Builtin::BI__sync_bool_compare_and_swap_8:
- case Builtin::BI__sync_bool_compare_and_swap_16:
- return RValue::get(MakeAtomicCmpXchgValue(*this, E, true));
-
- case Builtin::BI__sync_swap_1:
- case Builtin::BI__sync_swap_2:
- case Builtin::BI__sync_swap_4:
- case Builtin::BI__sync_swap_8:
- case Builtin::BI__sync_swap_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E);
-
- case Builtin::BI__sync_lock_test_and_set_1:
- case Builtin::BI__sync_lock_test_and_set_2:
- case Builtin::BI__sync_lock_test_and_set_4:
- case Builtin::BI__sync_lock_test_and_set_8:
- case Builtin::BI__sync_lock_test_and_set_16:
- return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E);
-
- case Builtin::BI__sync_lock_release_1:
- case Builtin::BI__sync_lock_release_2:
- case Builtin::BI__sync_lock_release_4:
- case Builtin::BI__sync_lock_release_8:
- case Builtin::BI__sync_lock_release_16: {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- QualType ElTy = E->getArg(0)->getType()->getPointeeType();
- CharUnits StoreSize = getContext().getTypeSizeInChars(ElTy);
- llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(),
- StoreSize.getQuantity() * 8);
- Ptr = Builder.CreateBitCast(Ptr, ITy->getPointerTo());
- llvm::StoreInst *Store =
- Builder.CreateAlignedStore(llvm::Constant::getNullValue(ITy), Ptr,
- StoreSize);
- Store->setAtomic(llvm::AtomicOrdering::Release);
- return RValue::get(nullptr);
- }
-
- case Builtin::BI__sync_synchronize: {
- // We assume this is supposed to correspond to a C++0x-style
- // sequentially-consistent fence (i.e. this is only usable for
- // synchronization, not device I/O or anything like that). This intrinsic
- // is really badly designed in the sense that in theory, there isn't
- // any way to safely use it... but in practice, it mostly works
- // to use it with non-atomic loads and stores to get acquire/release
- // semantics.
- Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent);
- return RValue::get(nullptr);
- }
-
- case Builtin::BI__builtin_nontemporal_load:
- return RValue::get(EmitNontemporalLoad(*this, E));
- case Builtin::BI__builtin_nontemporal_store:
- return RValue::get(EmitNontemporalStore(*this, E));
- case Builtin::BI__c11_atomic_is_lock_free:
- case Builtin::BI__atomic_is_lock_free: {
- // Call "bool __atomic_is_lock_free(size_t size, void *ptr)". For the
- // __c11 builtin, ptr is 0 (indicating a properly-aligned object), since
- // _Atomic(T) is always properly-aligned.
- const char *LibCallName = "__atomic_is_lock_free";
- CallArgList Args;
- Args.add(RValue::get(EmitScalarExpr(E->getArg(0))),
- getContext().getSizeType());
- if (BuiltinID == Builtin::BI__atomic_is_lock_free)
- Args.add(RValue::get(EmitScalarExpr(E->getArg(1))),
- getContext().VoidPtrTy);
- else
- Args.add(RValue::get(llvm::Constant::getNullValue(VoidPtrTy)),
- getContext().VoidPtrTy);
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeBuiltinFunctionCall(E->getType(), Args);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
- return EmitCall(FuncInfo, CGCallee::forDirect(Func),
- ReturnValueSlot(), Args);
- }
-
- case Builtin::BI__atomic_test_and_set: {
- // Look at the argument type to determine whether this is a volatile
- // operation. The parameter type is always volatile.
- QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType();
- bool Volatile =
- PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
-
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace();
- Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
- Value *NewVal = Builder.getInt8(1);
- Value *Order = EmitScalarExpr(E->getArg(1));
- if (isa<llvm::ConstantInt>(Order)) {
- int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- AtomicRMWInst *Result = nullptr;
- switch (ord) {
- case 0: // memory_order_relaxed
- default: // invalid order
- Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal,
- llvm::AtomicOrdering::Monotonic);
- break;
- case 1: // memory_order_consume
- case 2: // memory_order_acquire
- Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal,
- llvm::AtomicOrdering::Acquire);
- break;
- case 3: // memory_order_release
- Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal,
- llvm::AtomicOrdering::Release);
- break;
- case 4: // memory_order_acq_rel
-
- Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal,
- llvm::AtomicOrdering::AcquireRelease);
- break;
- case 5: // memory_order_seq_cst
- Result = Builder.CreateAtomicRMW(
- llvm::AtomicRMWInst::Xchg, Ptr, NewVal,
- llvm::AtomicOrdering::SequentiallyConsistent);
- break;
- }
- Result->setVolatile(Volatile);
- return RValue::get(Builder.CreateIsNotNull(Result, "tobool"));
- }
-
- llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
-
- llvm::BasicBlock *BBs[5] = {
- createBasicBlock("monotonic", CurFn),
- createBasicBlock("acquire", CurFn),
- createBasicBlock("release", CurFn),
- createBasicBlock("acqrel", CurFn),
- createBasicBlock("seqcst", CurFn)
- };
- llvm::AtomicOrdering Orders[5] = {
- llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Acquire,
- llvm::AtomicOrdering::Release, llvm::AtomicOrdering::AcquireRelease,
- llvm::AtomicOrdering::SequentiallyConsistent};
-
- Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
- llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]);
-
- Builder.SetInsertPoint(ContBB);
- PHINode *Result = Builder.CreatePHI(Int8Ty, 5, "was_set");
-
- for (unsigned i = 0; i < 5; ++i) {
- Builder.SetInsertPoint(BBs[i]);
- AtomicRMWInst *RMW = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
- Ptr, NewVal, Orders[i]);
- RMW->setVolatile(Volatile);
- Result->addIncoming(RMW, BBs[i]);
- Builder.CreateBr(ContBB);
- }
-
- SI->addCase(Builder.getInt32(0), BBs[0]);
- SI->addCase(Builder.getInt32(1), BBs[1]);
- SI->addCase(Builder.getInt32(2), BBs[1]);
- SI->addCase(Builder.getInt32(3), BBs[2]);
- SI->addCase(Builder.getInt32(4), BBs[3]);
- SI->addCase(Builder.getInt32(5), BBs[4]);
-
- Builder.SetInsertPoint(ContBB);
- return RValue::get(Builder.CreateIsNotNull(Result, "tobool"));
- }
-
- case Builtin::BI__atomic_clear: {
- QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType();
- bool Volatile =
- PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
-
- Address Ptr = EmitPointerWithAlignment(E->getArg(0));
- unsigned AddrSpace = Ptr.getPointer()->getType()->getPointerAddressSpace();
- Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
- Value *NewVal = Builder.getInt8(0);
- Value *Order = EmitScalarExpr(E->getArg(1));
- if (isa<llvm::ConstantInt>(Order)) {
- int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- StoreInst *Store = Builder.CreateStore(NewVal, Ptr, Volatile);
- switch (ord) {
- case 0: // memory_order_relaxed
- default: // invalid order
- Store->setOrdering(llvm::AtomicOrdering::Monotonic);
- break;
- case 3: // memory_order_release
- Store->setOrdering(llvm::AtomicOrdering::Release);
- break;
- case 5: // memory_order_seq_cst
- Store->setOrdering(llvm::AtomicOrdering::SequentiallyConsistent);
- break;
- }
- return RValue::get(nullptr);
- }
-
- llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
-
- llvm::BasicBlock *BBs[3] = {
- createBasicBlock("monotonic", CurFn),
- createBasicBlock("release", CurFn),
- createBasicBlock("seqcst", CurFn)
- };
- llvm::AtomicOrdering Orders[3] = {
- llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Release,
- llvm::AtomicOrdering::SequentiallyConsistent};
-
- Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
- llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]);
-
- for (unsigned i = 0; i < 3; ++i) {
- Builder.SetInsertPoint(BBs[i]);
- StoreInst *Store = Builder.CreateStore(NewVal, Ptr, Volatile);
- Store->setOrdering(Orders[i]);
- Builder.CreateBr(ContBB);
- }
-
- SI->addCase(Builder.getInt32(0), BBs[0]);
- SI->addCase(Builder.getInt32(3), BBs[1]);
- SI->addCase(Builder.getInt32(5), BBs[2]);
-
- Builder.SetInsertPoint(ContBB);
- return RValue::get(nullptr);
- }
-
- case Builtin::BI__atomic_thread_fence:
- case Builtin::BI__atomic_signal_fence:
- case Builtin::BI__c11_atomic_thread_fence:
- case Builtin::BI__c11_atomic_signal_fence: {
- llvm::SyncScope::ID SSID;
- if (BuiltinID == Builtin::BI__atomic_signal_fence ||
- BuiltinID == Builtin::BI__c11_atomic_signal_fence)
- SSID = llvm::SyncScope::SingleThread;
- else
- SSID = llvm::SyncScope::System;
- Value *Order = EmitScalarExpr(E->getArg(0));
- if (isa<llvm::ConstantInt>(Order)) {
- int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- switch (ord) {
- case 0: // memory_order_relaxed
- default: // invalid order
- break;
- case 1: // memory_order_consume
- case 2: // memory_order_acquire
- Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID);
- break;
- case 3: // memory_order_release
- Builder.CreateFence(llvm::AtomicOrdering::Release, SSID);
- break;
- case 4: // memory_order_acq_rel
- Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID);
- break;
- case 5: // memory_order_seq_cst
- Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID);
- break;
- }
- return RValue::get(nullptr);
- }
-
- llvm::BasicBlock *AcquireBB, *ReleaseBB, *AcqRelBB, *SeqCstBB;
- AcquireBB = createBasicBlock("acquire", CurFn);
- ReleaseBB = createBasicBlock("release", CurFn);
- AcqRelBB = createBasicBlock("acqrel", CurFn);
- SeqCstBB = createBasicBlock("seqcst", CurFn);
- llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
-
- Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
- llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB);
-
- Builder.SetInsertPoint(AcquireBB);
- Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(1), AcquireBB);
- SI->addCase(Builder.getInt32(2), AcquireBB);
-
- Builder.SetInsertPoint(ReleaseBB);
- Builder.CreateFence(llvm::AtomicOrdering::Release, SSID);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(3), ReleaseBB);
-
- Builder.SetInsertPoint(AcqRelBB);
- Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(4), AcqRelBB);
-
- Builder.SetInsertPoint(SeqCstBB);
- Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(5), SeqCstBB);
-
- Builder.SetInsertPoint(ContBB);
- return RValue::get(nullptr);
- }
-
- case Builtin::BI__builtin_signbit:
- case Builtin::BI__builtin_signbitf:
- case Builtin::BI__builtin_signbitl: {
- return RValue::get(
- Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))),
- ConvertType(E->getType())));
- }
- case Builtin::BI__annotation: {
- // Re-encode each wide string to UTF8 and make an MDString.
- SmallVector<Metadata *, 1> Strings;
- for (const Expr *Arg : E->arguments()) {
- const auto *Str = cast<StringLiteral>(Arg->IgnoreParenCasts());
- assert(Str->getCharByteWidth() == 2);
- StringRef WideBytes = Str->getBytes();
- std::string StrUtf8;
- if (!convertUTF16ToUTF8String(
- makeArrayRef(WideBytes.data(), WideBytes.size()), StrUtf8)) {
- CGM.ErrorUnsupported(E, "non-UTF16 __annotation argument");
- continue;
- }
- Strings.push_back(llvm::MDString::get(getLLVMContext(), StrUtf8));
- }
-
- // Build and MDTuple of MDStrings and emit the intrinsic call.
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::codeview_annotation, {});
- MDTuple *StrTuple = MDTuple::get(getLLVMContext(), Strings);
- Builder.CreateCall(F, MetadataAsValue::get(getLLVMContext(), StrTuple));
- return RValue::getIgnored();
- }
- case Builtin::BI__builtin_annotation: {
- llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0));
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::annotation,
- AnnVal->getType());
-
- // Get the annotation string, go through casts. Sema requires this to be a
- // non-wide string literal, potentially casted, so the cast<> is safe.
- const Expr *AnnotationStrExpr = E->getArg(1)->IgnoreParenCasts();
- StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
- return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
- }
- case Builtin::BI__builtin_addcb:
- case Builtin::BI__builtin_addcs:
- case Builtin::BI__builtin_addc:
- case Builtin::BI__builtin_addcl:
- case Builtin::BI__builtin_addcll:
- case Builtin::BI__builtin_subcb:
- case Builtin::BI__builtin_subcs:
- case Builtin::BI__builtin_subc:
- case Builtin::BI__builtin_subcl:
- case Builtin::BI__builtin_subcll: {
-
- // We translate all of these builtins from expressions of the form:
- // int x = ..., y = ..., carryin = ..., carryout, result;
- // result = __builtin_addc(x, y, carryin, &carryout);
- //
- // to LLVM IR of the form:
- //
- // %tmp1 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
- // %tmpsum1 = extractvalue {i32, i1} %tmp1, 0
- // %carry1 = extractvalue {i32, i1} %tmp1, 1
- // %tmp2 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %tmpsum1,
- // i32 %carryin)
- // %result = extractvalue {i32, i1} %tmp2, 0
- // %carry2 = extractvalue {i32, i1} %tmp2, 1
- // %tmp3 = or i1 %carry1, %carry2
- // %tmp4 = zext i1 %tmp3 to i32
- // store i32 %tmp4, i32* %carryout
-
- // Scalarize our inputs.
- llvm::Value *X = EmitScalarExpr(E->getArg(0));
- llvm::Value *Y = EmitScalarExpr(E->getArg(1));
- llvm::Value *Carryin = EmitScalarExpr(E->getArg(2));
- Address CarryOutPtr = EmitPointerWithAlignment(E->getArg(3));
-
- // Decide if we are lowering to a uadd.with.overflow or usub.with.overflow.
- llvm::Intrinsic::ID IntrinsicId;
- switch (BuiltinID) {
- default: llvm_unreachable("Unknown multiprecision builtin id.");
- case Builtin::BI__builtin_addcb:
- case Builtin::BI__builtin_addcs:
- case Builtin::BI__builtin_addc:
- case Builtin::BI__builtin_addcl:
- case Builtin::BI__builtin_addcll:
- IntrinsicId = llvm::Intrinsic::uadd_with_overflow;
- break;
- case Builtin::BI__builtin_subcb:
- case Builtin::BI__builtin_subcs:
- case Builtin::BI__builtin_subc:
- case Builtin::BI__builtin_subcl:
- case Builtin::BI__builtin_subcll:
- IntrinsicId = llvm::Intrinsic::usub_with_overflow;
- break;
- }
-
- // Construct our resulting LLVM IR expression.
- llvm::Value *Carry1;
- llvm::Value *Sum1 = EmitOverflowIntrinsic(*this, IntrinsicId,
- X, Y, Carry1);
- llvm::Value *Carry2;
- llvm::Value *Sum2 = EmitOverflowIntrinsic(*this, IntrinsicId,
- Sum1, Carryin, Carry2);
- llvm::Value *CarryOut = Builder.CreateZExt(Builder.CreateOr(Carry1, Carry2),
- X->getType());
- Builder.CreateStore(CarryOut, CarryOutPtr);
- return RValue::get(Sum2);
- }
-
- case Builtin::BI__builtin_add_overflow:
- case Builtin::BI__builtin_sub_overflow:
- case Builtin::BI__builtin_mul_overflow: {
- const clang::Expr *LeftArg = E->getArg(0);
- const clang::Expr *RightArg = E->getArg(1);
- const clang::Expr *ResultArg = E->getArg(2);
-
- clang::QualType ResultQTy =
- ResultArg->getType()->castAs<PointerType>()->getPointeeType();
-
- WidthAndSignedness LeftInfo =
- getIntegerWidthAndSignedness(CGM.getContext(), LeftArg->getType());
- WidthAndSignedness RightInfo =
- getIntegerWidthAndSignedness(CGM.getContext(), RightArg->getType());
- WidthAndSignedness ResultInfo =
- getIntegerWidthAndSignedness(CGM.getContext(), ResultQTy);
-
- // Handle mixed-sign multiplication as a special case, because adding
- // runtime or backend support for our generic irgen would be too expensive.
- if (isSpecialMixedSignMultiply(BuiltinID, LeftInfo, RightInfo, ResultInfo))
- return EmitCheckedMixedSignMultiply(*this, LeftArg, LeftInfo, RightArg,
- RightInfo, ResultArg, ResultQTy,
- ResultInfo);
-
- WidthAndSignedness EncompassingInfo =
- EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo});
-
- llvm::Type *EncompassingLLVMTy =
- llvm::IntegerType::get(CGM.getLLVMContext(), EncompassingInfo.Width);
-
- llvm::Type *ResultLLVMTy = CGM.getTypes().ConvertType(ResultQTy);
-
- llvm::Intrinsic::ID IntrinsicId;
- switch (BuiltinID) {
- default:
- llvm_unreachable("Unknown overflow builtin id.");
- case Builtin::BI__builtin_add_overflow:
- IntrinsicId = EncompassingInfo.Signed
- ? llvm::Intrinsic::sadd_with_overflow
- : llvm::Intrinsic::uadd_with_overflow;
- break;
- case Builtin::BI__builtin_sub_overflow:
- IntrinsicId = EncompassingInfo.Signed
- ? llvm::Intrinsic::ssub_with_overflow
- : llvm::Intrinsic::usub_with_overflow;
- break;
- case Builtin::BI__builtin_mul_overflow:
- IntrinsicId = EncompassingInfo.Signed
- ? llvm::Intrinsic::smul_with_overflow
- : llvm::Intrinsic::umul_with_overflow;
- break;
- }
-
- llvm::Value *Left = EmitScalarExpr(LeftArg);
- llvm::Value *Right = EmitScalarExpr(RightArg);
- Address ResultPtr = EmitPointerWithAlignment(ResultArg);
-
- // Extend each operand to the encompassing type.
- Left = Builder.CreateIntCast(Left, EncompassingLLVMTy, LeftInfo.Signed);
- Right = Builder.CreateIntCast(Right, EncompassingLLVMTy, RightInfo.Signed);
-
- // Perform the operation on the extended values.
- llvm::Value *Overflow, *Result;
- Result = EmitOverflowIntrinsic(*this, IntrinsicId, Left, Right, Overflow);
-
- if (EncompassingInfo.Width > ResultInfo.Width) {
- // The encompassing type is wider than the result type, so we need to
- // truncate it.
- llvm::Value *ResultTrunc = Builder.CreateTrunc(Result, ResultLLVMTy);
-
- // To see if the truncation caused an overflow, we will extend
- // the result and then compare it to the original result.
- llvm::Value *ResultTruncExt = Builder.CreateIntCast(
- ResultTrunc, EncompassingLLVMTy, ResultInfo.Signed);
- llvm::Value *TruncationOverflow =
- Builder.CreateICmpNE(Result, ResultTruncExt);
-
- Overflow = Builder.CreateOr(Overflow, TruncationOverflow);
- Result = ResultTrunc;
- }
-
- // Finally, store the result using the pointer.
- bool isVolatile =
- ResultArg->getType()->getPointeeType().isVolatileQualified();
- Builder.CreateStore(EmitToMemory(Result, ResultQTy), ResultPtr, isVolatile);
-
- return RValue::get(Overflow);
- }
-
- case Builtin::BI__builtin_uadd_overflow:
- case Builtin::BI__builtin_uaddl_overflow:
- case Builtin::BI__builtin_uaddll_overflow:
- case Builtin::BI__builtin_usub_overflow:
- case Builtin::BI__builtin_usubl_overflow:
- case Builtin::BI__builtin_usubll_overflow:
- case Builtin::BI__builtin_umul_overflow:
- case Builtin::BI__builtin_umull_overflow:
- case Builtin::BI__builtin_umulll_overflow:
- case Builtin::BI__builtin_sadd_overflow:
- case Builtin::BI__builtin_saddl_overflow:
- case Builtin::BI__builtin_saddll_overflow:
- case Builtin::BI__builtin_ssub_overflow:
- case Builtin::BI__builtin_ssubl_overflow:
- case Builtin::BI__builtin_ssubll_overflow:
- case Builtin::BI__builtin_smul_overflow:
- case Builtin::BI__builtin_smull_overflow:
- case Builtin::BI__builtin_smulll_overflow: {
-
- // We translate all of these builtins directly to the relevant llvm IR node.
-
- // Scalarize our inputs.
- llvm::Value *X = EmitScalarExpr(E->getArg(0));
- llvm::Value *Y = EmitScalarExpr(E->getArg(1));
- Address SumOutPtr = EmitPointerWithAlignment(E->getArg(2));
-
- // Decide which of the overflow intrinsics we are lowering to:
- llvm::Intrinsic::ID IntrinsicId;
- switch (BuiltinID) {
- default: llvm_unreachable("Unknown overflow builtin id.");
- case Builtin::BI__builtin_uadd_overflow:
- case Builtin::BI__builtin_uaddl_overflow:
- case Builtin::BI__builtin_uaddll_overflow:
- IntrinsicId = llvm::Intrinsic::uadd_with_overflow;
- break;
- case Builtin::BI__builtin_usub_overflow:
- case Builtin::BI__builtin_usubl_overflow:
- case Builtin::BI__builtin_usubll_overflow:
- IntrinsicId = llvm::Intrinsic::usub_with_overflow;
- break;
- case Builtin::BI__builtin_umul_overflow:
- case Builtin::BI__builtin_umull_overflow:
- case Builtin::BI__builtin_umulll_overflow:
- IntrinsicId = llvm::Intrinsic::umul_with_overflow;
- break;
- case Builtin::BI__builtin_sadd_overflow:
- case Builtin::BI__builtin_saddl_overflow:
- case Builtin::BI__builtin_saddll_overflow:
- IntrinsicId = llvm::Intrinsic::sadd_with_overflow;
- break;
- case Builtin::BI__builtin_ssub_overflow:
- case Builtin::BI__builtin_ssubl_overflow:
- case Builtin::BI__builtin_ssubll_overflow:
- IntrinsicId = llvm::Intrinsic::ssub_with_overflow;
- break;
- case Builtin::BI__builtin_smul_overflow:
- case Builtin::BI__builtin_smull_overflow:
- case Builtin::BI__builtin_smulll_overflow:
- IntrinsicId = llvm::Intrinsic::smul_with_overflow;
- break;
- }
-
-
- llvm::Value *Carry;
- llvm::Value *Sum = EmitOverflowIntrinsic(*this, IntrinsicId, X, Y, Carry);
- Builder.CreateStore(Sum, SumOutPtr);
-
- return RValue::get(Carry);
- }
- case Builtin::BI__builtin_addressof:
- return RValue::get(EmitLValue(E->getArg(0)).getPointer());
- case Builtin::BI__builtin_operator_new:
- return EmitBuiltinNewDeleteCall(
- E->getCallee()->getType()->castAs<FunctionProtoType>(), E, false);
- case Builtin::BI__builtin_operator_delete:
- return EmitBuiltinNewDeleteCall(
- E->getCallee()->getType()->castAs<FunctionProtoType>(), E, true);
-
- case Builtin::BI__noop:
- // __noop always evaluates to an integer literal zero.
- return RValue::get(ConstantInt::get(IntTy, 0));
- case Builtin::BI__builtin_call_with_static_chain: {
- const CallExpr *Call = cast<CallExpr>(E->getArg(0));
- const Expr *Chain = E->getArg(1);
- return EmitCall(Call->getCallee()->getType(),
- EmitCallee(Call->getCallee()), Call, ReturnValue,
- EmitScalarExpr(Chain));
- }
- case Builtin::BI_InterlockedExchange8:
- case Builtin::BI_InterlockedExchange16:
- case Builtin::BI_InterlockedExchange:
- case Builtin::BI_InterlockedExchangePointer:
- return RValue::get(
- EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E));
- case Builtin::BI_InterlockedCompareExchangePointer:
- case Builtin::BI_InterlockedCompareExchangePointer_nf: {
- llvm::Type *RTy;
- llvm::IntegerType *IntType =
- IntegerType::get(getLLVMContext(),
- getContext().getTypeSize(E->getType()));
- llvm::Type *IntPtrType = IntType->getPointerTo();
-
- llvm::Value *Destination =
- Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), IntPtrType);
-
- llvm::Value *Exchange = EmitScalarExpr(E->getArg(1));
- RTy = Exchange->getType();
- Exchange = Builder.CreatePtrToInt(Exchange, IntType);
-
- llvm::Value *Comparand =
- Builder.CreatePtrToInt(EmitScalarExpr(E->getArg(2)), IntType);
-
- auto Ordering =
- BuiltinID == Builtin::BI_InterlockedCompareExchangePointer_nf ?
- AtomicOrdering::Monotonic : AtomicOrdering::SequentiallyConsistent;
-
- auto Result = Builder.CreateAtomicCmpXchg(Destination, Comparand, Exchange,
- Ordering, Ordering);
- Result->setVolatile(true);
-
- return RValue::get(Builder.CreateIntToPtr(Builder.CreateExtractValue(Result,
- 0),
- RTy));
- }
- case Builtin::BI_InterlockedCompareExchange8:
- case Builtin::BI_InterlockedCompareExchange16:
- case Builtin::BI_InterlockedCompareExchange:
- case Builtin::BI_InterlockedCompareExchange64:
- return RValue::get(EmitAtomicCmpXchgForMSIntrin(*this, E));
- case Builtin::BI_InterlockedIncrement16:
- case Builtin::BI_InterlockedIncrement:
- return RValue::get(
- EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E));
- case Builtin::BI_InterlockedDecrement16:
- case Builtin::BI_InterlockedDecrement:
- return RValue::get(
- EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E));
- case Builtin::BI_InterlockedAnd8:
- case Builtin::BI_InterlockedAnd16:
- case Builtin::BI_InterlockedAnd:
- return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E));
- case Builtin::BI_InterlockedExchangeAdd8:
- case Builtin::BI_InterlockedExchangeAdd16:
- case Builtin::BI_InterlockedExchangeAdd:
- return RValue::get(
- EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E));
- case Builtin::BI_InterlockedExchangeSub8:
- case Builtin::BI_InterlockedExchangeSub16:
- case Builtin::BI_InterlockedExchangeSub:
- return RValue::get(
- EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E));
- case Builtin::BI_InterlockedOr8:
- case Builtin::BI_InterlockedOr16:
- case Builtin::BI_InterlockedOr:
- return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E));
- case Builtin::BI_InterlockedXor8:
- case Builtin::BI_InterlockedXor16:
- case Builtin::BI_InterlockedXor:
- return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E));
-
- case Builtin::BI_bittest64:
- case Builtin::BI_bittest:
- case Builtin::BI_bittestandcomplement64:
- case Builtin::BI_bittestandcomplement:
- case Builtin::BI_bittestandreset64:
- case Builtin::BI_bittestandreset:
- case Builtin::BI_bittestandset64:
- case Builtin::BI_bittestandset:
- case Builtin::BI_interlockedbittestandreset:
- case Builtin::BI_interlockedbittestandreset64:
- case Builtin::BI_interlockedbittestandset64:
- case Builtin::BI_interlockedbittestandset:
- case Builtin::BI_interlockedbittestandset_acq:
- case Builtin::BI_interlockedbittestandset_rel:
- case Builtin::BI_interlockedbittestandset_nf:
- case Builtin::BI_interlockedbittestandreset_acq:
- case Builtin::BI_interlockedbittestandreset_rel:
- case Builtin::BI_interlockedbittestandreset_nf:
- return RValue::get(EmitBitTestIntrinsic(*this, BuiltinID, E));
-
- case Builtin::BI__exception_code:
- case Builtin::BI_exception_code:
- return RValue::get(EmitSEHExceptionCode());
- case Builtin::BI__exception_info:
- case Builtin::BI_exception_info:
- return RValue::get(EmitSEHExceptionInfo());
- case Builtin::BI__abnormal_termination:
- case Builtin::BI_abnormal_termination:
- return RValue::get(EmitSEHAbnormalTermination());
- case Builtin::BI_setjmpex:
- if (getTarget().getTriple().isOSMSVCRT())
- return EmitMSVCRTSetJmp(*this, MSVCSetJmpKind::_setjmpex, E);
- break;
- case Builtin::BI_setjmp:
- if (getTarget().getTriple().isOSMSVCRT()) {
- if (getTarget().getTriple().getArch() == llvm::Triple::x86)
- return EmitMSVCRTSetJmp(*this, MSVCSetJmpKind::_setjmp3, E);
- else if (getTarget().getTriple().getArch() == llvm::Triple::aarch64)
- return EmitMSVCRTSetJmp(*this, MSVCSetJmpKind::_setjmpex, E);
- return EmitMSVCRTSetJmp(*this, MSVCSetJmpKind::_setjmp, E);
- }
- break;
-
- case Builtin::BI__GetExceptionInfo: {
- if (llvm::GlobalVariable *GV =
- CGM.getCXXABI().getThrowInfo(FD->getParamDecl(0)->getType()))
- return RValue::get(llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy));
- break;
- }
-
- case Builtin::BI__fastfail:
- return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::__fastfail, E));
-
- case Builtin::BI__builtin_coro_size: {
- auto & Context = getContext();
- auto SizeTy = Context.getSizeType();
- auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
- Value *F = CGM.getIntrinsic(Intrinsic::coro_size, T);
- return RValue::get(Builder.CreateCall(F));
- }
-
- case Builtin::BI__builtin_coro_id:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_id);
- case Builtin::BI__builtin_coro_promise:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_promise);
- case Builtin::BI__builtin_coro_resume:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_resume);
- case Builtin::BI__builtin_coro_frame:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_frame);
- case Builtin::BI__builtin_coro_noop:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_noop);
- case Builtin::BI__builtin_coro_free:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_free);
- case Builtin::BI__builtin_coro_destroy:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_destroy);
- case Builtin::BI__builtin_coro_done:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_done);
- case Builtin::BI__builtin_coro_alloc:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_alloc);
- case Builtin::BI__builtin_coro_begin:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_begin);
- case Builtin::BI__builtin_coro_end:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_end);
- case Builtin::BI__builtin_coro_suspend:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_suspend);
- case Builtin::BI__builtin_coro_param:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_param);
-
- // OpenCL v2.0 s6.13.16.2, Built-in pipe read and write functions
- case Builtin::BIread_pipe:
- case Builtin::BIwrite_pipe: {
- Value *Arg0 = EmitScalarExpr(E->getArg(0)),
- *Arg1 = EmitScalarExpr(E->getArg(1));
- CGOpenCLRuntime OpenCLRT(CGM);
- Value *PacketSize = OpenCLRT.getPipeElemSize(E->getArg(0));
- Value *PacketAlign = OpenCLRT.getPipeElemAlign(E->getArg(0));
-
- // Type of the generic packet parameter.
- unsigned GenericAS =
- getContext().getTargetAddressSpace(LangAS::opencl_generic);
- llvm::Type *I8PTy = llvm::PointerType::get(
- llvm::Type::getInt8Ty(getLLVMContext()), GenericAS);
-
- // Testing which overloaded version we should generate the call for.
- if (2U == E->getNumArgs()) {
- const char *Name = (BuiltinID == Builtin::BIread_pipe) ? "__read_pipe_2"
- : "__write_pipe_2";
- // Creating a generic function type to be able to call with any builtin or
- // user defined type.
- llvm::Type *ArgTys[] = {Arg0->getType(), I8PTy, Int32Ty, Int32Ty};
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
- Value *BCast = Builder.CreatePointerCast(Arg1, I8PTy);
- return RValue::get(
- Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- {Arg0, BCast, PacketSize, PacketAlign}));
- } else {
- assert(4 == E->getNumArgs() &&
- "Illegal number of parameters to pipe function");
- const char *Name = (BuiltinID == Builtin::BIread_pipe) ? "__read_pipe_4"
- : "__write_pipe_4";
-
- llvm::Type *ArgTys[] = {Arg0->getType(), Arg1->getType(), Int32Ty, I8PTy,
- Int32Ty, Int32Ty};
- Value *Arg2 = EmitScalarExpr(E->getArg(2)),
- *Arg3 = EmitScalarExpr(E->getArg(3));
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
- Value *BCast = Builder.CreatePointerCast(Arg3, I8PTy);
- // We know the third argument is an integer type, but we may need to cast
- // it to i32.
- if (Arg2->getType() != Int32Ty)
- Arg2 = Builder.CreateZExtOrTrunc(Arg2, Int32Ty);
- return RValue::get(Builder.CreateCall(
- CGM.CreateRuntimeFunction(FTy, Name),
- {Arg0, Arg1, Arg2, BCast, PacketSize, PacketAlign}));
- }
- }
- // OpenCL v2.0 s6.13.16 ,s9.17.3.5 - Built-in pipe reserve read and write
- // functions
- case Builtin::BIreserve_read_pipe:
- case Builtin::BIreserve_write_pipe:
- case Builtin::BIwork_group_reserve_read_pipe:
- case Builtin::BIwork_group_reserve_write_pipe:
- case Builtin::BIsub_group_reserve_read_pipe:
- case Builtin::BIsub_group_reserve_write_pipe: {
- // Composing the mangled name for the function.
- const char *Name;
- if (BuiltinID == Builtin::BIreserve_read_pipe)
- Name = "__reserve_read_pipe";
- else if (BuiltinID == Builtin::BIreserve_write_pipe)
- Name = "__reserve_write_pipe";
- else if (BuiltinID == Builtin::BIwork_group_reserve_read_pipe)
- Name = "__work_group_reserve_read_pipe";
- else if (BuiltinID == Builtin::BIwork_group_reserve_write_pipe)
- Name = "__work_group_reserve_write_pipe";
- else if (BuiltinID == Builtin::BIsub_group_reserve_read_pipe)
- Name = "__sub_group_reserve_read_pipe";
- else
- Name = "__sub_group_reserve_write_pipe";
-
- Value *Arg0 = EmitScalarExpr(E->getArg(0)),
- *Arg1 = EmitScalarExpr(E->getArg(1));
- llvm::Type *ReservedIDTy = ConvertType(getContext().OCLReserveIDTy);
- CGOpenCLRuntime OpenCLRT(CGM);
- Value *PacketSize = OpenCLRT.getPipeElemSize(E->getArg(0));
- Value *PacketAlign = OpenCLRT.getPipeElemAlign(E->getArg(0));
-
- // Building the generic function prototype.
- llvm::Type *ArgTys[] = {Arg0->getType(), Int32Ty, Int32Ty, Int32Ty};
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- ReservedIDTy, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
- // We know the second argument is an integer type, but we may need to cast
- // it to i32.
- if (Arg1->getType() != Int32Ty)
- Arg1 = Builder.CreateZExtOrTrunc(Arg1, Int32Ty);
- return RValue::get(
- Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- {Arg0, Arg1, PacketSize, PacketAlign}));
- }
- // OpenCL v2.0 s6.13.16, s9.17.3.5 - Built-in pipe commit read and write
- // functions
- case Builtin::BIcommit_read_pipe:
- case Builtin::BIcommit_write_pipe:
- case Builtin::BIwork_group_commit_read_pipe:
- case Builtin::BIwork_group_commit_write_pipe:
- case Builtin::BIsub_group_commit_read_pipe:
- case Builtin::BIsub_group_commit_write_pipe: {
- const char *Name;
- if (BuiltinID == Builtin::BIcommit_read_pipe)
- Name = "__commit_read_pipe";
- else if (BuiltinID == Builtin::BIcommit_write_pipe)
- Name = "__commit_write_pipe";
- else if (BuiltinID == Builtin::BIwork_group_commit_read_pipe)
- Name = "__work_group_commit_read_pipe";
- else if (BuiltinID == Builtin::BIwork_group_commit_write_pipe)
- Name = "__work_group_commit_write_pipe";
- else if (BuiltinID == Builtin::BIsub_group_commit_read_pipe)
- Name = "__sub_group_commit_read_pipe";
- else
- Name = "__sub_group_commit_write_pipe";
-
- Value *Arg0 = EmitScalarExpr(E->getArg(0)),
- *Arg1 = EmitScalarExpr(E->getArg(1));
- CGOpenCLRuntime OpenCLRT(CGM);
- Value *PacketSize = OpenCLRT.getPipeElemSize(E->getArg(0));
- Value *PacketAlign = OpenCLRT.getPipeElemAlign(E->getArg(0));
-
- // Building the generic function prototype.
- llvm::Type *ArgTys[] = {Arg0->getType(), Arg1->getType(), Int32Ty, Int32Ty};
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- llvm::ArrayRef<llvm::Type *>(ArgTys), false);
-
- return RValue::get(
- Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- {Arg0, Arg1, PacketSize, PacketAlign}));
- }
- // OpenCL v2.0 s6.13.16.4 Built-in pipe query functions
- case Builtin::BIget_pipe_num_packets:
- case Builtin::BIget_pipe_max_packets: {
- const char *BaseName;
- const PipeType *PipeTy = E->getArg(0)->getType()->getAs<PipeType>();
- if (BuiltinID == Builtin::BIget_pipe_num_packets)
- BaseName = "__get_pipe_num_packets";
- else
- BaseName = "__get_pipe_max_packets";
- auto Name = std::string(BaseName) +
- std::string(PipeTy->isReadOnly() ? "_ro" : "_wo");
-
- // Building the generic function prototype.
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- CGOpenCLRuntime OpenCLRT(CGM);
- Value *PacketSize = OpenCLRT.getPipeElemSize(E->getArg(0));
- Value *PacketAlign = OpenCLRT.getPipeElemAlign(E->getArg(0));
- llvm::Type *ArgTys[] = {Arg0->getType(), Int32Ty, Int32Ty};
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
-
- return RValue::get(Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- {Arg0, PacketSize, PacketAlign}));
- }
-
- // OpenCL v2.0 s6.13.9 - Address space qualifier functions.
- case Builtin::BIto_global:
- case Builtin::BIto_local:
- case Builtin::BIto_private: {
- auto Arg0 = EmitScalarExpr(E->getArg(0));
- auto NewArgT = llvm::PointerType::get(Int8Ty,
- CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
- auto NewRetT = llvm::PointerType::get(Int8Ty,
- CGM.getContext().getTargetAddressSpace(
- E->getType()->getPointeeType().getAddressSpace()));
- auto FTy = llvm::FunctionType::get(NewRetT, {NewArgT}, false);
- llvm::Value *NewArg;
- if (Arg0->getType()->getPointerAddressSpace() !=
- NewArgT->getPointerAddressSpace())
- NewArg = Builder.CreateAddrSpaceCast(Arg0, NewArgT);
- else
- NewArg = Builder.CreateBitOrPointerCast(Arg0, NewArgT);
- auto NewName = std::string("__") + E->getDirectCallee()->getName().str();
- auto NewCall =
- Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, NewName), {NewArg});
- return RValue::get(Builder.CreateBitOrPointerCast(NewCall,
- ConvertType(E->getType())));
- }
-
- // OpenCL v2.0, s6.13.17 - Enqueue kernel function.
- // It contains four different overload formats specified in Table 6.13.17.1.
- case Builtin::BIenqueue_kernel: {
- StringRef Name; // Generated function call name
- unsigned NumArgs = E->getNumArgs();
-
- llvm::Type *QueueTy = ConvertType(getContext().OCLQueueTy);
- llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
- getContext().getTargetAddressSpace(LangAS::opencl_generic));
-
- llvm::Value *Queue = EmitScalarExpr(E->getArg(0));
- llvm::Value *Flags = EmitScalarExpr(E->getArg(1));
- LValue NDRangeL = EmitAggExprToLValue(E->getArg(2));
- llvm::Value *Range = NDRangeL.getAddress().getPointer();
- llvm::Type *RangeTy = NDRangeL.getAddress().getType();
-
- if (NumArgs == 4) {
- // The most basic form of the call with parameters:
- // queue_t, kernel_enqueue_flags_t, ndrange_t, block(void)
- Name = "__enqueue_kernel_basic";
- llvm::Type *ArgTys[] = {QueueTy, Int32Ty, RangeTy, GenericVoidPtrTy,
- GenericVoidPtrTy};
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
-
- auto Info =
- CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(3));
- llvm::Value *Kernel =
- Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
- llvm::Value *Block =
- Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
-
- AttrBuilder B;
- B.addAttribute(Attribute::ByVal);
- llvm::AttributeList ByValAttrSet =
- llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B);
-
- auto RTCall =
- Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name, ByValAttrSet),
- {Queue, Flags, Range, Kernel, Block});
- RTCall->setAttributes(ByValAttrSet);
- return RValue::get(RTCall);
- }
- assert(NumArgs >= 5 && "Invalid enqueue_kernel signature");
-
- // Create a temporary array to hold the sizes of local pointer arguments
- // for the block. \p First is the position of the first size argument.
- auto CreateArrayForSizeVar = [=](unsigned First)
- -> std::tuple<llvm::Value *, llvm::Value *, llvm::Value *> {
- llvm::APInt ArraySize(32, NumArgs - First);
- QualType SizeArrayTy = getContext().getConstantArrayType(
- getContext().getSizeType(), ArraySize, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- auto Tmp = CreateMemTemp(SizeArrayTy, "block_sizes");
- llvm::Value *TmpPtr = Tmp.getPointer();
- llvm::Value *TmpSize = EmitLifetimeStart(
- CGM.getDataLayout().getTypeAllocSize(Tmp.getElementType()), TmpPtr);
- llvm::Value *ElemPtr;
- // Each of the following arguments specifies the size of the corresponding
- // argument passed to the enqueued block.
- auto *Zero = llvm::ConstantInt::get(IntTy, 0);
- for (unsigned I = First; I < NumArgs; ++I) {
- auto *Index = llvm::ConstantInt::get(IntTy, I - First);
- auto *GEP = Builder.CreateGEP(TmpPtr, {Zero, Index});
- if (I == First)
- ElemPtr = GEP;
- auto *V =
- Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(I)), SizeTy);
- Builder.CreateAlignedStore(
- V, GEP, CGM.getDataLayout().getPrefTypeAlignment(SizeTy));
- }
- return std::tie(ElemPtr, TmpSize, TmpPtr);
- };
-
- // Could have events and/or varargs.
- if (E->getArg(3)->getType()->isBlockPointerType()) {
- // No events passed, but has variadic arguments.
- Name = "__enqueue_kernel_varargs";
- auto Info =
- CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(3));
- llvm::Value *Kernel =
- Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
- auto *Block = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
- llvm::Value *ElemPtr, *TmpSize, *TmpPtr;
- std::tie(ElemPtr, TmpSize, TmpPtr) = CreateArrayForSizeVar(4);
-
- // Create a vector of the arguments, as well as a constant value to
- // express to the runtime the number of variadic arguments.
- std::vector<llvm::Value *> Args = {
- Queue, Flags, Range,
- Kernel, Block, ConstantInt::get(IntTy, NumArgs - 4),
- ElemPtr};
- std::vector<llvm::Type *> ArgTys = {
- QueueTy, IntTy, RangeTy, GenericVoidPtrTy,
- GenericVoidPtrTy, IntTy, ElemPtr->getType()};
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
- auto Call =
- RValue::get(Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- llvm::ArrayRef<llvm::Value *>(Args)));
- if (TmpSize)
- EmitLifetimeEnd(TmpSize, TmpPtr);
- return Call;
- }
- // Any calls now have event arguments passed.
- if (NumArgs >= 7) {
- llvm::Type *EventTy = ConvertType(getContext().OCLClkEventTy);
- llvm::Type *EventPtrTy = EventTy->getPointerTo(
- CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
-
- llvm::Value *NumEvents =
- Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(3)), Int32Ty);
- llvm::Value *EventList =
- E->getArg(4)->getType()->isArrayType()
- ? EmitArrayToPointerDecay(E->getArg(4)).getPointer()
- : EmitScalarExpr(E->getArg(4));
- llvm::Value *ClkEvent = EmitScalarExpr(E->getArg(5));
- // Convert to generic address space.
- EventList = Builder.CreatePointerCast(EventList, EventPtrTy);
- ClkEvent = ClkEvent->getType()->isIntegerTy()
- ? Builder.CreateBitOrPointerCast(ClkEvent, EventPtrTy)
- : Builder.CreatePointerCast(ClkEvent, EventPtrTy);
- auto Info =
- CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(6));
- llvm::Value *Kernel =
- Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
- llvm::Value *Block =
- Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
-
- std::vector<llvm::Type *> ArgTys = {
- QueueTy, Int32Ty, RangeTy, Int32Ty,
- EventPtrTy, EventPtrTy, GenericVoidPtrTy, GenericVoidPtrTy};
-
- std::vector<llvm::Value *> Args = {Queue, Flags, Range, NumEvents,
- EventList, ClkEvent, Kernel, Block};
-
- if (NumArgs == 7) {
- // Has events but no variadics.
- Name = "__enqueue_kernel_basic_events";
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
- return RValue::get(
- Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- llvm::ArrayRef<llvm::Value *>(Args)));
- }
- // Has event info and variadics
- // Pass the number of variadics to the runtime function too.
- Args.push_back(ConstantInt::get(Int32Ty, NumArgs - 7));
- ArgTys.push_back(Int32Ty);
- Name = "__enqueue_kernel_events_varargs";
-
- llvm::Value *ElemPtr, *TmpSize, *TmpPtr;
- std::tie(ElemPtr, TmpSize, TmpPtr) = CreateArrayForSizeVar(7);
- Args.push_back(ElemPtr);
- ArgTys.push_back(ElemPtr->getType());
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
- auto Call =
- RValue::get(Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
- llvm::ArrayRef<llvm::Value *>(Args)));
- if (TmpSize)
- EmitLifetimeEnd(TmpSize, TmpPtr);
- return Call;
- }
- LLVM_FALLTHROUGH;
- }
- // OpenCL v2.0 s6.13.17.6 - Kernel query functions need bitcast of block
- // parameter.
- case Builtin::BIget_kernel_work_group_size: {
- llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
- getContext().getTargetAddressSpace(LangAS::opencl_generic));
- auto Info =
- CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(0));
- Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
- Value *Arg = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
- return RValue::get(Builder.CreateCall(
- CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, {GenericVoidPtrTy, GenericVoidPtrTy},
- false),
- "__get_kernel_work_group_size_impl"),
- {Kernel, Arg}));
- }
- case Builtin::BIget_kernel_preferred_work_group_size_multiple: {
- llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
- getContext().getTargetAddressSpace(LangAS::opencl_generic));
- auto Info =
- CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(0));
- Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
- Value *Arg = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
- return RValue::get(Builder.CreateCall(
- CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, {GenericVoidPtrTy, GenericVoidPtrTy},
- false),
- "__get_kernel_preferred_work_group_size_multiple_impl"),
- {Kernel, Arg}));
- }
- case Builtin::BIget_kernel_max_sub_group_size_for_ndrange:
- case Builtin::BIget_kernel_sub_group_count_for_ndrange: {
- llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
- getContext().getTargetAddressSpace(LangAS::opencl_generic));
- LValue NDRangeL = EmitAggExprToLValue(E->getArg(0));
- llvm::Value *NDRange = NDRangeL.getAddress().getPointer();
- auto Info =
- CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(1));
- Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
- Value *Block = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
- const char *Name =
- BuiltinID == Builtin::BIget_kernel_max_sub_group_size_for_ndrange
- ? "__get_kernel_max_sub_group_size_for_ndrange_impl"
- : "__get_kernel_sub_group_count_for_ndrange_impl";
- return RValue::get(Builder.CreateCall(
- CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(
- IntTy, {NDRange->getType(), GenericVoidPtrTy, GenericVoidPtrTy},
- false),
- Name),
- {NDRange, Kernel, Block}));
- }
-
- case Builtin::BI__builtin_store_half:
- case Builtin::BI__builtin_store_halff: {
- Value *Val = EmitScalarExpr(E->getArg(0));
- Address Address = EmitPointerWithAlignment(E->getArg(1));
- Value *HalfVal = Builder.CreateFPTrunc(Val, Builder.getHalfTy());
- return RValue::get(Builder.CreateStore(HalfVal, Address));
- }
- case Builtin::BI__builtin_load_half: {
- Address Address = EmitPointerWithAlignment(E->getArg(0));
- Value *HalfVal = Builder.CreateLoad(Address);
- return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getDoubleTy()));
- }
- case Builtin::BI__builtin_load_halff: {
- Address Address = EmitPointerWithAlignment(E->getArg(0));
- Value *HalfVal = Builder.CreateLoad(Address);
- return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getFloatTy()));
- }
- case Builtin::BIprintf:
- if (getTarget().getTriple().isNVPTX())
- return EmitNVPTXDevicePrintfCallExpr(E, ReturnValue);
- break;
- case Builtin::BI__builtin_canonicalize:
- case Builtin::BI__builtin_canonicalizef:
- case Builtin::BI__builtin_canonicalizel:
- return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::canonicalize));
-
- case Builtin::BI__builtin_thread_pointer: {
- if (!getContext().getTargetInfo().isTLSSupported())
- CGM.ErrorUnsupported(E, "__builtin_thread_pointer");
- // Fall through - it's already mapped to the intrinsic by GCCBuiltin.
- break;
- }
- case Builtin::BI__builtin_os_log_format:
- return emitBuiltinOSLogFormat(*E);
-
- case Builtin::BI__xray_customevent: {
- if (!ShouldXRayInstrumentFunction())
- return RValue::getIgnored();
-
- if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
- XRayInstrKind::Custom))
- return RValue::getIgnored();
-
- if (const auto *XRayAttr = CurFuncDecl->getAttr<XRayInstrumentAttr>())
- if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents())
- return RValue::getIgnored();
-
- Function *F = CGM.getIntrinsic(Intrinsic::xray_customevent);
- auto FTy = F->getFunctionType();
- auto Arg0 = E->getArg(0);
- auto Arg0Val = EmitScalarExpr(Arg0);
- auto Arg0Ty = Arg0->getType();
- auto PTy0 = FTy->getParamType(0);
- if (PTy0 != Arg0Val->getType()) {
- if (Arg0Ty->isArrayType())
- Arg0Val = EmitArrayToPointerDecay(Arg0).getPointer();
- else
- Arg0Val = Builder.CreatePointerCast(Arg0Val, PTy0);
- }
- auto Arg1 = EmitScalarExpr(E->getArg(1));
- auto PTy1 = FTy->getParamType(1);
- if (PTy1 != Arg1->getType())
- Arg1 = Builder.CreateTruncOrBitCast(Arg1, PTy1);
- return RValue::get(Builder.CreateCall(F, {Arg0Val, Arg1}));
- }
-
- case Builtin::BI__xray_typedevent: {
- // TODO: There should be a way to always emit events even if the current
- // function is not instrumented. Losing events in a stream can cripple
- // a trace.
- if (!ShouldXRayInstrumentFunction())
- return RValue::getIgnored();
-
- if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
- XRayInstrKind::Typed))
- return RValue::getIgnored();
-
- if (const auto *XRayAttr = CurFuncDecl->getAttr<XRayInstrumentAttr>())
- if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayTypedEvents())
- return RValue::getIgnored();
-
- Function *F = CGM.getIntrinsic(Intrinsic::xray_typedevent);
- auto FTy = F->getFunctionType();
- auto Arg0 = EmitScalarExpr(E->getArg(0));
- auto PTy0 = FTy->getParamType(0);
- if (PTy0 != Arg0->getType())
- Arg0 = Builder.CreateTruncOrBitCast(Arg0, PTy0);
- auto Arg1 = E->getArg(1);
- auto Arg1Val = EmitScalarExpr(Arg1);
- auto Arg1Ty = Arg1->getType();
- auto PTy1 = FTy->getParamType(1);
- if (PTy1 != Arg1Val->getType()) {
- if (Arg1Ty->isArrayType())
- Arg1Val = EmitArrayToPointerDecay(Arg1).getPointer();
- else
- Arg1Val = Builder.CreatePointerCast(Arg1Val, PTy1);
- }
- auto Arg2 = EmitScalarExpr(E->getArg(2));
- auto PTy2 = FTy->getParamType(2);
- if (PTy2 != Arg2->getType())
- Arg2 = Builder.CreateTruncOrBitCast(Arg2, PTy2);
- return RValue::get(Builder.CreateCall(F, {Arg0, Arg1Val, Arg2}));
- }
-
- case Builtin::BI__builtin_ms_va_start:
- case Builtin::BI__builtin_ms_va_end:
- return RValue::get(
- EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(),
- BuiltinID == Builtin::BI__builtin_ms_va_start));
-
- case Builtin::BI__builtin_ms_va_copy: {
- // Lower this manually. We can't reliably determine whether or not any
- // given va_copy() is for a Win64 va_list from the calling convention
- // alone, because it's legal to do this from a System V ABI function.
- // With opaque pointer types, we won't have enough information in LLVM
- // IR to determine this from the argument types, either. Best to do it
- // now, while we have enough information.
- Address DestAddr = EmitMSVAListRef(E->getArg(0));
- Address SrcAddr = EmitMSVAListRef(E->getArg(1));
-
- llvm::Type *BPP = Int8PtrPtrTy;
-
- DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), BPP, "cp"),
- DestAddr.getAlignment());
- SrcAddr = Address(Builder.CreateBitCast(SrcAddr.getPointer(), BPP, "ap"),
- SrcAddr.getAlignment());
-
- Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val");
- return RValue::get(Builder.CreateStore(ArgPtr, DestAddr));
- }
- }
-
- // If this is an alias for a lib function (e.g. __builtin_sin), emit
- // the call using the normal call path, but using the unmangled
- // version of the function name.
- if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
- return emitLibraryCall(*this, FD, E,
- CGM.getBuiltinLibFunction(FD, BuiltinID));
-
- // If this is a predefined lib function (e.g. malloc), emit the call
- // using exactly the normal call path.
- if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return emitLibraryCall(*this, FD, E,
- cast<llvm::Constant>(EmitScalarExpr(E->getCallee())));
-
- // Check that a call to a target specific builtin has the correct target
- // features.
- // This is down here to avoid non-target specific builtins, however, if
- // generic builtins start to require generic target features then we
- // can move this up to the beginning of the function.
- checkTargetFeatures(E, FD);
-
- if (unsigned VectorWidth = getContext().BuiltinInfo.getRequiredVectorWidth(BuiltinID))
- LargestVectorWidth = std::max(LargestVectorWidth, VectorWidth);
-
- // See if we have a target specific intrinsic.
- const char *Name = getContext().BuiltinInfo.getName(BuiltinID);
- Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic;
- StringRef Prefix =
- llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch());
- if (!Prefix.empty()) {
- IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix.data(), Name);
- // NOTE we don't need to perform a compatibility flag check here since the
- // intrinsics are declared in Builtins*.def via LANGBUILTIN which filter the
- // MS builtins via ALL_MS_LANGUAGES and are filtered earlier.
- if (IntrinsicID == Intrinsic::not_intrinsic)
- IntrinsicID = Intrinsic::getIntrinsicForMSBuiltin(Prefix.data(), Name);
- }
-
- if (IntrinsicID != Intrinsic::not_intrinsic) {
- SmallVector<Value*, 16> Args;
-
- // Find out if any arguments are required to be integer constant
- // expressions.
- unsigned ICEArguments = 0;
- ASTContext::GetBuiltinTypeError Error;
- getContext().GetBuiltinType(BuiltinID, Error, &ICEArguments);
- assert(Error == ASTContext::GE_None && "Should not codegen an error");
-
- Function *F = CGM.getIntrinsic(IntrinsicID);
- llvm::FunctionType *FTy = F->getFunctionType();
-
- for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
- Value *ArgValue;
- // If this is a normal argument, just emit it as a scalar.
- if ((ICEArguments & (1 << i)) == 0) {
- ArgValue = EmitScalarExpr(E->getArg(i));
- } else {
- // If this is required to be a constant, constant fold it so that we
- // know that the generated intrinsic gets a ConstantInt.
- llvm::APSInt Result;
- bool IsConst = E->getArg(i)->isIntegerConstantExpr(Result,getContext());
- assert(IsConst && "Constant arg isn't actually constant?");
- (void)IsConst;
- ArgValue = llvm::ConstantInt::get(getLLVMContext(), Result);
- }
-
- // If the intrinsic arg type is different from the builtin arg type
- // we need to do a bit cast.
- llvm::Type *PTy = FTy->getParamType(i);
- if (PTy != ArgValue->getType()) {
- // XXX - vector of pointers?
- if (auto *PtrTy = dyn_cast<llvm::PointerType>(PTy)) {
- if (PtrTy->getAddressSpace() !=
- ArgValue->getType()->getPointerAddressSpace()) {
- ArgValue = Builder.CreateAddrSpaceCast(
- ArgValue,
- ArgValue->getType()->getPointerTo(PtrTy->getAddressSpace()));
- }
- }
-
- assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) &&
- "Must be able to losslessly bit cast to param");
- ArgValue = Builder.CreateBitCast(ArgValue, PTy);
- }
-
- Args.push_back(ArgValue);
- }
-
- Value *V = Builder.CreateCall(F, Args);
- QualType BuiltinRetType = E->getType();
-
- llvm::Type *RetTy = VoidTy;
- if (!BuiltinRetType->isVoidType())
- RetTy = ConvertType(BuiltinRetType);
-
- if (RetTy != V->getType()) {
- // XXX - vector of pointers?
- if (auto *PtrTy = dyn_cast<llvm::PointerType>(RetTy)) {
- if (PtrTy->getAddressSpace() != V->getType()->getPointerAddressSpace()) {
- V = Builder.CreateAddrSpaceCast(
- V, V->getType()->getPointerTo(PtrTy->getAddressSpace()));
- }
- }
-
- assert(V->getType()->canLosslesslyBitCastTo(RetTy) &&
- "Must be able to losslessly bit cast result type");
- V = Builder.CreateBitCast(V, RetTy);
- }
-
- return RValue::get(V);
- }
-
- // See if we have a target specific builtin that needs to be lowered.
- if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E))
- return RValue::get(V);
-
- ErrorUnsupported(E, "builtin function");
-
- // Unknown builtin, for now just dump it out and return undef.
- return GetUndefRValue(E->getType());
-}
-
-static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
- unsigned BuiltinID, const CallExpr *E,
- llvm::Triple::ArchType Arch) {
- switch (Arch) {
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- return CGF->EmitARMBuiltinExpr(BuiltinID, E, Arch);
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- return CGF->EmitAArch64BuiltinExpr(BuiltinID, E, Arch);
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return CGF->EmitX86BuiltinExpr(BuiltinID, E);
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- return CGF->EmitPPCBuiltinExpr(BuiltinID, E);
- case llvm::Triple::r600:
- case llvm::Triple::amdgcn:
- return CGF->EmitAMDGPUBuiltinExpr(BuiltinID, E);
- case llvm::Triple::systemz:
- return CGF->EmitSystemZBuiltinExpr(BuiltinID, E);
- case llvm::Triple::nvptx:
- case llvm::Triple::nvptx64:
- return CGF->EmitNVPTXBuiltinExpr(BuiltinID, E);
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- return CGF->EmitWebAssemblyBuiltinExpr(BuiltinID, E);
- case llvm::Triple::hexagon:
- return CGF->EmitHexagonBuiltinExpr(BuiltinID, E);
- default:
- return nullptr;
- }
-}
-
-Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- if (getContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) {
- assert(getContext().getAuxTargetInfo() && "Missing aux target info");
- return EmitTargetArchBuiltinExpr(
- this, getContext().BuiltinInfo.getAuxBuiltinID(BuiltinID), E,
- getContext().getAuxTargetInfo()->getTriple().getArch());
- }
-
- return EmitTargetArchBuiltinExpr(this, BuiltinID, E,
- getTarget().getTriple().getArch());
-}
-
-static llvm::VectorType *GetNeonType(CodeGenFunction *CGF,
- NeonTypeFlags TypeFlags,
- bool HasLegalHalfType=true,
- bool V1Ty=false) {
- int IsQuad = TypeFlags.isQuad();
- switch (TypeFlags.getEltType()) {
- case NeonTypeFlags::Int8:
- case NeonTypeFlags::Poly8:
- return llvm::VectorType::get(CGF->Int8Ty, V1Ty ? 1 : (8 << IsQuad));
- case NeonTypeFlags::Int16:
- case NeonTypeFlags::Poly16:
- return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad));
- case NeonTypeFlags::Float16:
- if (HasLegalHalfType)
- return llvm::VectorType::get(CGF->HalfTy, V1Ty ? 1 : (4 << IsQuad));
- else
- return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad));
- case NeonTypeFlags::Int32:
- return llvm::VectorType::get(CGF->Int32Ty, V1Ty ? 1 : (2 << IsQuad));
- case NeonTypeFlags::Int64:
- case NeonTypeFlags::Poly64:
- return llvm::VectorType::get(CGF->Int64Ty, V1Ty ? 1 : (1 << IsQuad));
- case NeonTypeFlags::Poly128:
- // FIXME: i128 and f128 doesn't get fully support in Clang and llvm.
- // There is a lot of i128 and f128 API missing.
- // so we use v16i8 to represent poly128 and get pattern matched.
- return llvm::VectorType::get(CGF->Int8Ty, 16);
- case NeonTypeFlags::Float32:
- return llvm::VectorType::get(CGF->FloatTy, V1Ty ? 1 : (2 << IsQuad));
- case NeonTypeFlags::Float64:
- return llvm::VectorType::get(CGF->DoubleTy, V1Ty ? 1 : (1 << IsQuad));
- }
- llvm_unreachable("Unknown vector element type!");
-}
-
-static llvm::VectorType *GetFloatNeonType(CodeGenFunction *CGF,
- NeonTypeFlags IntTypeFlags) {
- int IsQuad = IntTypeFlags.isQuad();
- switch (IntTypeFlags.getEltType()) {
- case NeonTypeFlags::Int16:
- return llvm::VectorType::get(CGF->HalfTy, (4 << IsQuad));
- case NeonTypeFlags::Int32:
- return llvm::VectorType::get(CGF->FloatTy, (2 << IsQuad));
- case NeonTypeFlags::Int64:
- return llvm::VectorType::get(CGF->DoubleTy, (1 << IsQuad));
- default:
- llvm_unreachable("Type can't be converted to floating-point!");
- }
-}
-
-Value *CodeGenFunction::EmitNeonSplat(Value *V, Constant *C) {
- unsigned nElts = V->getType()->getVectorNumElements();
- Value* SV = llvm::ConstantVector::getSplat(nElts, C);
- return Builder.CreateShuffleVector(V, V, SV, "lane");
-}
-
-Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops,
- const char *name,
- unsigned shift, bool rightshift) {
- unsigned j = 0;
- for (Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end();
- ai != ae; ++ai, ++j)
- if (shift > 0 && shift == j)
- Ops[j] = EmitNeonShiftVector(Ops[j], ai->getType(), rightshift);
- else
- Ops[j] = Builder.CreateBitCast(Ops[j], ai->getType(), name);
-
- return Builder.CreateCall(F, Ops, name);
-}
-
-Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
- bool neg) {
- int SV = cast<ConstantInt>(V)->getSExtValue();
- return ConstantInt::get(Ty, neg ? -SV : SV);
-}
-
-// Right-shift a vector by a constant.
-Value *CodeGenFunction::EmitNeonRShiftImm(Value *Vec, Value *Shift,
- llvm::Type *Ty, bool usgn,
- const char *name) {
- llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
-
- int ShiftAmt = cast<ConstantInt>(Shift)->getSExtValue();
- int EltSize = VTy->getScalarSizeInBits();
-
- Vec = Builder.CreateBitCast(Vec, Ty);
-
- // lshr/ashr are undefined when the shift amount is equal to the vector
- // element size.
- if (ShiftAmt == EltSize) {
- if (usgn) {
- // Right-shifting an unsigned value by its size yields 0.
- return llvm::ConstantAggregateZero::get(VTy);
- } else {
- // Right-shifting a signed value by its size is equivalent
- // to a shift of size-1.
- --ShiftAmt;
- Shift = ConstantInt::get(VTy->getElementType(), ShiftAmt);
- }
- }
-
- Shift = EmitNeonShiftVector(Shift, Ty, false);
- if (usgn)
- return Builder.CreateLShr(Vec, Shift, name);
- else
- return Builder.CreateAShr(Vec, Shift, name);
-}
-
-enum {
- AddRetType = (1 << 0),
- Add1ArgType = (1 << 1),
- Add2ArgTypes = (1 << 2),
-
- VectorizeRetType = (1 << 3),
- VectorizeArgTypes = (1 << 4),
-
- InventFloatType = (1 << 5),
- UnsignedAlts = (1 << 6),
-
- Use64BitVectors = (1 << 7),
- Use128BitVectors = (1 << 8),
-
- Vectorize1ArgType = Add1ArgType | VectorizeArgTypes,
- VectorRet = AddRetType | VectorizeRetType,
- VectorRetGetArgs01 =
- AddRetType | Add2ArgTypes | VectorizeRetType | VectorizeArgTypes,
- FpCmpzModifiers =
- AddRetType | VectorizeRetType | Add1ArgType | InventFloatType
-};
-
-namespace {
-struct NeonIntrinsicInfo {
- const char *NameHint;
- unsigned BuiltinID;
- unsigned LLVMIntrinsic;
- unsigned AltLLVMIntrinsic;
- unsigned TypeModifier;
-
- bool operator<(unsigned RHSBuiltinID) const {
- return BuiltinID < RHSBuiltinID;
- }
- bool operator<(const NeonIntrinsicInfo &TE) const {
- return BuiltinID < TE.BuiltinID;
- }
-};
-} // end anonymous namespace
-
-#define NEONMAP0(NameBase) \
- { #NameBase, NEON::BI__builtin_neon_ ## NameBase, 0, 0, 0 }
-
-#define NEONMAP1(NameBase, LLVMIntrinsic, TypeModifier) \
- { #NameBase, NEON:: BI__builtin_neon_ ## NameBase, \
- Intrinsic::LLVMIntrinsic, 0, TypeModifier }
-
-#define NEONMAP2(NameBase, LLVMIntrinsic, AltLLVMIntrinsic, TypeModifier) \
- { #NameBase, NEON:: BI__builtin_neon_ ## NameBase, \
- Intrinsic::LLVMIntrinsic, Intrinsic::AltLLVMIntrinsic, \
- TypeModifier }
-
-static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
- NEONMAP2(vabd_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vabdq_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
- NEONMAP1(vabs_v, arm_neon_vabs, 0),
- NEONMAP1(vabsq_v, arm_neon_vabs, 0),
- NEONMAP0(vaddhn_v),
- NEONMAP1(vaesdq_v, arm_neon_aesd, 0),
- NEONMAP1(vaeseq_v, arm_neon_aese, 0),
- NEONMAP1(vaesimcq_v, arm_neon_aesimc, 0),
- NEONMAP1(vaesmcq_v, arm_neon_aesmc, 0),
- NEONMAP1(vbsl_v, arm_neon_vbsl, AddRetType),
- NEONMAP1(vbslq_v, arm_neon_vbsl, AddRetType),
- NEONMAP1(vcage_v, arm_neon_vacge, 0),
- NEONMAP1(vcageq_v, arm_neon_vacge, 0),
- NEONMAP1(vcagt_v, arm_neon_vacgt, 0),
- NEONMAP1(vcagtq_v, arm_neon_vacgt, 0),
- NEONMAP1(vcale_v, arm_neon_vacge, 0),
- NEONMAP1(vcaleq_v, arm_neon_vacge, 0),
- NEONMAP1(vcalt_v, arm_neon_vacgt, 0),
- NEONMAP1(vcaltq_v, arm_neon_vacgt, 0),
- NEONMAP0(vceqz_v),
- NEONMAP0(vceqzq_v),
- NEONMAP0(vcgez_v),
- NEONMAP0(vcgezq_v),
- NEONMAP0(vcgtz_v),
- NEONMAP0(vcgtzq_v),
- NEONMAP0(vclez_v),
- NEONMAP0(vclezq_v),
- NEONMAP1(vcls_v, arm_neon_vcls, Add1ArgType),
- NEONMAP1(vclsq_v, arm_neon_vcls, Add1ArgType),
- NEONMAP0(vcltz_v),
- NEONMAP0(vcltzq_v),
- NEONMAP1(vclz_v, ctlz, Add1ArgType),
- NEONMAP1(vclzq_v, ctlz, Add1ArgType),
- NEONMAP1(vcnt_v, ctpop, Add1ArgType),
- NEONMAP1(vcntq_v, ctpop, Add1ArgType),
- NEONMAP1(vcvt_f16_f32, arm_neon_vcvtfp2hf, 0),
- NEONMAP0(vcvt_f16_v),
- NEONMAP1(vcvt_f32_f16, arm_neon_vcvthf2fp, 0),
- NEONMAP0(vcvt_f32_v),
- NEONMAP2(vcvt_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
- NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvt_n_s16_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_u16_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP0(vcvt_s16_v),
- NEONMAP0(vcvt_s32_v),
- NEONMAP0(vcvt_s64_v),
- NEONMAP0(vcvt_u16_v),
- NEONMAP0(vcvt_u32_v),
- NEONMAP0(vcvt_u64_v),
- NEONMAP1(vcvta_s16_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvta_u16_v, arm_neon_vcvtau, 0),
- NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0),
- NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0),
- NEONMAP1(vcvtaq_s16_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvtaq_u16_v, arm_neon_vcvtau, 0),
- NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0),
- NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0),
- NEONMAP1(vcvtm_s16_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtm_u16_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtmq_s16_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtmq_u16_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtn_s16_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtn_u16_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtnq_s16_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtnq_u16_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtp_s16_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtp_u16_v, arm_neon_vcvtpu, 0),
- NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0),
- NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0),
- NEONMAP1(vcvtpq_s16_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtpq_u16_v, arm_neon_vcvtpu, 0),
- NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0),
- NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0),
- NEONMAP0(vcvtq_f16_v),
- NEONMAP0(vcvtq_f32_v),
- NEONMAP2(vcvtq_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
- NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvtq_n_s16_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_u16_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP0(vcvtq_s16_v),
- NEONMAP0(vcvtq_s32_v),
- NEONMAP0(vcvtq_s64_v),
- NEONMAP0(vcvtq_u16_v),
- NEONMAP0(vcvtq_u32_v),
- NEONMAP0(vcvtq_u64_v),
- NEONMAP2(vdot_v, arm_neon_udot, arm_neon_sdot, 0),
- NEONMAP2(vdotq_v, arm_neon_udot, arm_neon_sdot, 0),
- NEONMAP0(vext_v),
- NEONMAP0(vextq_v),
- NEONMAP0(vfma_v),
- NEONMAP0(vfmaq_v),
- NEONMAP2(vhadd_v, arm_neon_vhaddu, arm_neon_vhadds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vhaddq_v, arm_neon_vhaddu, arm_neon_vhadds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vhsub_v, arm_neon_vhsubu, arm_neon_vhsubs, Add1ArgType | UnsignedAlts),
- NEONMAP2(vhsubq_v, arm_neon_vhsubu, arm_neon_vhsubs, Add1ArgType | UnsignedAlts),
- NEONMAP0(vld1_dup_v),
- NEONMAP1(vld1_v, arm_neon_vld1, 0),
- NEONMAP1(vld1_x2_v, arm_neon_vld1x2, 0),
- NEONMAP1(vld1_x3_v, arm_neon_vld1x3, 0),
- NEONMAP1(vld1_x4_v, arm_neon_vld1x4, 0),
- NEONMAP0(vld1q_dup_v),
- NEONMAP1(vld1q_v, arm_neon_vld1, 0),
- NEONMAP1(vld1q_x2_v, arm_neon_vld1x2, 0),
- NEONMAP1(vld1q_x3_v, arm_neon_vld1x3, 0),
- NEONMAP1(vld1q_x4_v, arm_neon_vld1x4, 0),
- NEONMAP1(vld2_dup_v, arm_neon_vld2dup, 0),
- NEONMAP1(vld2_lane_v, arm_neon_vld2lane, 0),
- NEONMAP1(vld2_v, arm_neon_vld2, 0),
- NEONMAP1(vld2q_dup_v, arm_neon_vld2dup, 0),
- NEONMAP1(vld2q_lane_v, arm_neon_vld2lane, 0),
- NEONMAP1(vld2q_v, arm_neon_vld2, 0),
- NEONMAP1(vld3_dup_v, arm_neon_vld3dup, 0),
- NEONMAP1(vld3_lane_v, arm_neon_vld3lane, 0),
- NEONMAP1(vld3_v, arm_neon_vld3, 0),
- NEONMAP1(vld3q_dup_v, arm_neon_vld3dup, 0),
- NEONMAP1(vld3q_lane_v, arm_neon_vld3lane, 0),
- NEONMAP1(vld3q_v, arm_neon_vld3, 0),
- NEONMAP1(vld4_dup_v, arm_neon_vld4dup, 0),
- NEONMAP1(vld4_lane_v, arm_neon_vld4lane, 0),
- NEONMAP1(vld4_v, arm_neon_vld4, 0),
- NEONMAP1(vld4q_dup_v, arm_neon_vld4dup, 0),
- NEONMAP1(vld4q_lane_v, arm_neon_vld4lane, 0),
- NEONMAP1(vld4q_v, arm_neon_vld4, 0),
- NEONMAP2(vmax_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
- NEONMAP1(vmaxnm_v, arm_neon_vmaxnm, Add1ArgType),
- NEONMAP1(vmaxnmq_v, arm_neon_vmaxnm, Add1ArgType),
- NEONMAP2(vmaxq_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
- NEONMAP2(vmin_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
- NEONMAP1(vminnm_v, arm_neon_vminnm, Add1ArgType),
- NEONMAP1(vminnmq_v, arm_neon_vminnm, Add1ArgType),
- NEONMAP2(vminq_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
- NEONMAP0(vmovl_v),
- NEONMAP0(vmovn_v),
- NEONMAP1(vmul_v, arm_neon_vmulp, Add1ArgType),
- NEONMAP0(vmull_v),
- NEONMAP1(vmulq_v, arm_neon_vmulp, Add1ArgType),
- NEONMAP2(vpadal_v, arm_neon_vpadalu, arm_neon_vpadals, UnsignedAlts),
- NEONMAP2(vpadalq_v, arm_neon_vpadalu, arm_neon_vpadals, UnsignedAlts),
- NEONMAP1(vpadd_v, arm_neon_vpadd, Add1ArgType),
- NEONMAP2(vpaddl_v, arm_neon_vpaddlu, arm_neon_vpaddls, UnsignedAlts),
- NEONMAP2(vpaddlq_v, arm_neon_vpaddlu, arm_neon_vpaddls, UnsignedAlts),
- NEONMAP1(vpaddq_v, arm_neon_vpadd, Add1ArgType),
- NEONMAP2(vpmax_v, arm_neon_vpmaxu, arm_neon_vpmaxs, Add1ArgType | UnsignedAlts),
- NEONMAP2(vpmin_v, arm_neon_vpminu, arm_neon_vpmins, Add1ArgType | UnsignedAlts),
- NEONMAP1(vqabs_v, arm_neon_vqabs, Add1ArgType),
- NEONMAP1(vqabsq_v, arm_neon_vqabs, Add1ArgType),
- NEONMAP2(vqadd_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqaddq_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqdmlal_v, arm_neon_vqdmull, arm_neon_vqadds, 0),
- NEONMAP2(vqdmlsl_v, arm_neon_vqdmull, arm_neon_vqsubs, 0),
- NEONMAP1(vqdmulh_v, arm_neon_vqdmulh, Add1ArgType),
- NEONMAP1(vqdmulhq_v, arm_neon_vqdmulh, Add1ArgType),
- NEONMAP1(vqdmull_v, arm_neon_vqdmull, Add1ArgType),
- NEONMAP2(vqmovn_v, arm_neon_vqmovnu, arm_neon_vqmovns, Add1ArgType | UnsignedAlts),
- NEONMAP1(vqmovun_v, arm_neon_vqmovnsu, Add1ArgType),
- NEONMAP1(vqneg_v, arm_neon_vqneg, Add1ArgType),
- NEONMAP1(vqnegq_v, arm_neon_vqneg, Add1ArgType),
- NEONMAP1(vqrdmulh_v, arm_neon_vqrdmulh, Add1ArgType),
- NEONMAP1(vqrdmulhq_v, arm_neon_vqrdmulh, Add1ArgType),
- NEONMAP2(vqrshl_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqrshlq_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqshl_n_v, arm_neon_vqshiftu, arm_neon_vqshifts, UnsignedAlts),
- NEONMAP2(vqshl_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqshlq_n_v, arm_neon_vqshiftu, arm_neon_vqshifts, UnsignedAlts),
- NEONMAP2(vqshlq_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
- NEONMAP1(vqshlu_n_v, arm_neon_vqshiftsu, 0),
- NEONMAP1(vqshluq_n_v, arm_neon_vqshiftsu, 0),
- NEONMAP2(vqsub_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqsubq_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
- NEONMAP1(vraddhn_v, arm_neon_vraddhn, Add1ArgType),
- NEONMAP2(vrecpe_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
- NEONMAP2(vrecpeq_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
- NEONMAP1(vrecps_v, arm_neon_vrecps, Add1ArgType),
- NEONMAP1(vrecpsq_v, arm_neon_vrecps, Add1ArgType),
- NEONMAP2(vrhadd_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
- NEONMAP2(vrhaddq_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
- NEONMAP1(vrnd_v, arm_neon_vrintz, Add1ArgType),
- NEONMAP1(vrnda_v, arm_neon_vrinta, Add1ArgType),
- NEONMAP1(vrndaq_v, arm_neon_vrinta, Add1ArgType),
- NEONMAP0(vrndi_v),
- NEONMAP0(vrndiq_v),
- NEONMAP1(vrndm_v, arm_neon_vrintm, Add1ArgType),
- NEONMAP1(vrndmq_v, arm_neon_vrintm, Add1ArgType),
- NEONMAP1(vrndn_v, arm_neon_vrintn, Add1ArgType),
- NEONMAP1(vrndnq_v, arm_neon_vrintn, Add1ArgType),
- NEONMAP1(vrndp_v, arm_neon_vrintp, Add1ArgType),
- NEONMAP1(vrndpq_v, arm_neon_vrintp, Add1ArgType),
- NEONMAP1(vrndq_v, arm_neon_vrintz, Add1ArgType),
- NEONMAP1(vrndx_v, arm_neon_vrintx, Add1ArgType),
- NEONMAP1(vrndxq_v, arm_neon_vrintx, Add1ArgType),
- NEONMAP2(vrshl_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
- NEONMAP2(vrshlq_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
- NEONMAP2(vrshr_n_v, arm_neon_vrshiftu, arm_neon_vrshifts, UnsignedAlts),
- NEONMAP2(vrshrq_n_v, arm_neon_vrshiftu, arm_neon_vrshifts, UnsignedAlts),
- NEONMAP2(vrsqrte_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
- NEONMAP2(vrsqrteq_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
- NEONMAP1(vrsqrts_v, arm_neon_vrsqrts, Add1ArgType),
- NEONMAP1(vrsqrtsq_v, arm_neon_vrsqrts, Add1ArgType),
- NEONMAP1(vrsubhn_v, arm_neon_vrsubhn, Add1ArgType),
- NEONMAP1(vsha1su0q_v, arm_neon_sha1su0, 0),
- NEONMAP1(vsha1su1q_v, arm_neon_sha1su1, 0),
- NEONMAP1(vsha256h2q_v, arm_neon_sha256h2, 0),
- NEONMAP1(vsha256hq_v, arm_neon_sha256h, 0),
- NEONMAP1(vsha256su0q_v, arm_neon_sha256su0, 0),
- NEONMAP1(vsha256su1q_v, arm_neon_sha256su1, 0),
- NEONMAP0(vshl_n_v),
- NEONMAP2(vshl_v, arm_neon_vshiftu, arm_neon_vshifts, Add1ArgType | UnsignedAlts),
- NEONMAP0(vshll_n_v),
- NEONMAP0(vshlq_n_v),
- NEONMAP2(vshlq_v, arm_neon_vshiftu, arm_neon_vshifts, Add1ArgType | UnsignedAlts),
- NEONMAP0(vshr_n_v),
- NEONMAP0(vshrn_n_v),
- NEONMAP0(vshrq_n_v),
- NEONMAP1(vst1_v, arm_neon_vst1, 0),
- NEONMAP1(vst1_x2_v, arm_neon_vst1x2, 0),
- NEONMAP1(vst1_x3_v, arm_neon_vst1x3, 0),
- NEONMAP1(vst1_x4_v, arm_neon_vst1x4, 0),
- NEONMAP1(vst1q_v, arm_neon_vst1, 0),
- NEONMAP1(vst1q_x2_v, arm_neon_vst1x2, 0),
- NEONMAP1(vst1q_x3_v, arm_neon_vst1x3, 0),
- NEONMAP1(vst1q_x4_v, arm_neon_vst1x4, 0),
- NEONMAP1(vst2_lane_v, arm_neon_vst2lane, 0),
- NEONMAP1(vst2_v, arm_neon_vst2, 0),
- NEONMAP1(vst2q_lane_v, arm_neon_vst2lane, 0),
- NEONMAP1(vst2q_v, arm_neon_vst2, 0),
- NEONMAP1(vst3_lane_v, arm_neon_vst3lane, 0),
- NEONMAP1(vst3_v, arm_neon_vst3, 0),
- NEONMAP1(vst3q_lane_v, arm_neon_vst3lane, 0),
- NEONMAP1(vst3q_v, arm_neon_vst3, 0),
- NEONMAP1(vst4_lane_v, arm_neon_vst4lane, 0),
- NEONMAP1(vst4_v, arm_neon_vst4, 0),
- NEONMAP1(vst4q_lane_v, arm_neon_vst4lane, 0),
- NEONMAP1(vst4q_v, arm_neon_vst4, 0),
- NEONMAP0(vsubhn_v),
- NEONMAP0(vtrn_v),
- NEONMAP0(vtrnq_v),
- NEONMAP0(vtst_v),
- NEONMAP0(vtstq_v),
- NEONMAP0(vuzp_v),
- NEONMAP0(vuzpq_v),
- NEONMAP0(vzip_v),
- NEONMAP0(vzipq_v)
-};
-
-static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
- NEONMAP1(vabs_v, aarch64_neon_abs, 0),
- NEONMAP1(vabsq_v, aarch64_neon_abs, 0),
- NEONMAP0(vaddhn_v),
- NEONMAP1(vaesdq_v, aarch64_crypto_aesd, 0),
- NEONMAP1(vaeseq_v, aarch64_crypto_aese, 0),
- NEONMAP1(vaesimcq_v, aarch64_crypto_aesimc, 0),
- NEONMAP1(vaesmcq_v, aarch64_crypto_aesmc, 0),
- NEONMAP1(vcage_v, aarch64_neon_facge, 0),
- NEONMAP1(vcageq_v, aarch64_neon_facge, 0),
- NEONMAP1(vcagt_v, aarch64_neon_facgt, 0),
- NEONMAP1(vcagtq_v, aarch64_neon_facgt, 0),
- NEONMAP1(vcale_v, aarch64_neon_facge, 0),
- NEONMAP1(vcaleq_v, aarch64_neon_facge, 0),
- NEONMAP1(vcalt_v, aarch64_neon_facgt, 0),
- NEONMAP1(vcaltq_v, aarch64_neon_facgt, 0),
- NEONMAP0(vceqz_v),
- NEONMAP0(vceqzq_v),
- NEONMAP0(vcgez_v),
- NEONMAP0(vcgezq_v),
- NEONMAP0(vcgtz_v),
- NEONMAP0(vcgtzq_v),
- NEONMAP0(vclez_v),
- NEONMAP0(vclezq_v),
- NEONMAP1(vcls_v, aarch64_neon_cls, Add1ArgType),
- NEONMAP1(vclsq_v, aarch64_neon_cls, Add1ArgType),
- NEONMAP0(vcltz_v),
- NEONMAP0(vcltzq_v),
- NEONMAP1(vclz_v, ctlz, Add1ArgType),
- NEONMAP1(vclzq_v, ctlz, Add1ArgType),
- NEONMAP1(vcnt_v, ctpop, Add1ArgType),
- NEONMAP1(vcntq_v, ctpop, Add1ArgType),
- NEONMAP1(vcvt_f16_f32, aarch64_neon_vcvtfp2hf, 0),
- NEONMAP0(vcvt_f16_v),
- NEONMAP1(vcvt_f32_f16, aarch64_neon_vcvthf2fp, 0),
- NEONMAP0(vcvt_f32_v),
- NEONMAP2(vcvt_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP2(vcvt_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP2(vcvt_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvt_n_s16_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_u16_v, aarch64_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvt_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvt_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
- NEONMAP0(vcvtq_f16_v),
- NEONMAP0(vcvtq_f32_v),
- NEONMAP2(vcvtq_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP2(vcvtq_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP2(vcvtq_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvtq_n_s16_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_u16_v, aarch64_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvtq_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvtq_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
- NEONMAP1(vcvtx_f32_v, aarch64_neon_fcvtxn, AddRetType | Add1ArgType),
- NEONMAP2(vdot_v, aarch64_neon_udot, aarch64_neon_sdot, 0),
- NEONMAP2(vdotq_v, aarch64_neon_udot, aarch64_neon_sdot, 0),
- NEONMAP0(vext_v),
- NEONMAP0(vextq_v),
- NEONMAP0(vfma_v),
- NEONMAP0(vfmaq_v),
- NEONMAP1(vfmlal_high_v, aarch64_neon_fmlal2, 0),
- NEONMAP1(vfmlal_low_v, aarch64_neon_fmlal, 0),
- NEONMAP1(vfmlalq_high_v, aarch64_neon_fmlal2, 0),
- NEONMAP1(vfmlalq_low_v, aarch64_neon_fmlal, 0),
- NEONMAP1(vfmlsl_high_v, aarch64_neon_fmlsl2, 0),
- NEONMAP1(vfmlsl_low_v, aarch64_neon_fmlsl, 0),
- NEONMAP1(vfmlslq_high_v, aarch64_neon_fmlsl2, 0),
- NEONMAP1(vfmlslq_low_v, aarch64_neon_fmlsl, 0),
- NEONMAP2(vhadd_v, aarch64_neon_uhadd, aarch64_neon_shadd, Add1ArgType | UnsignedAlts),
- NEONMAP2(vhaddq_v, aarch64_neon_uhadd, aarch64_neon_shadd, Add1ArgType | UnsignedAlts),
- NEONMAP2(vhsub_v, aarch64_neon_uhsub, aarch64_neon_shsub, Add1ArgType | UnsignedAlts),
- NEONMAP2(vhsubq_v, aarch64_neon_uhsub, aarch64_neon_shsub, Add1ArgType | UnsignedAlts),
- NEONMAP1(vld1_x2_v, aarch64_neon_ld1x2, 0),
- NEONMAP1(vld1_x3_v, aarch64_neon_ld1x3, 0),
- NEONMAP1(vld1_x4_v, aarch64_neon_ld1x4, 0),
- NEONMAP1(vld1q_x2_v, aarch64_neon_ld1x2, 0),
- NEONMAP1(vld1q_x3_v, aarch64_neon_ld1x3, 0),
- NEONMAP1(vld1q_x4_v, aarch64_neon_ld1x4, 0),
- NEONMAP0(vmovl_v),
- NEONMAP0(vmovn_v),
- NEONMAP1(vmul_v, aarch64_neon_pmul, Add1ArgType),
- NEONMAP1(vmulq_v, aarch64_neon_pmul, Add1ArgType),
- NEONMAP1(vpadd_v, aarch64_neon_addp, Add1ArgType),
- NEONMAP2(vpaddl_v, aarch64_neon_uaddlp, aarch64_neon_saddlp, UnsignedAlts),
- NEONMAP2(vpaddlq_v, aarch64_neon_uaddlp, aarch64_neon_saddlp, UnsignedAlts),
- NEONMAP1(vpaddq_v, aarch64_neon_addp, Add1ArgType),
- NEONMAP1(vqabs_v, aarch64_neon_sqabs, Add1ArgType),
- NEONMAP1(vqabsq_v, aarch64_neon_sqabs, Add1ArgType),
- NEONMAP2(vqadd_v, aarch64_neon_uqadd, aarch64_neon_sqadd, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqaddq_v, aarch64_neon_uqadd, aarch64_neon_sqadd, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqdmlal_v, aarch64_neon_sqdmull, aarch64_neon_sqadd, 0),
- NEONMAP2(vqdmlsl_v, aarch64_neon_sqdmull, aarch64_neon_sqsub, 0),
- NEONMAP1(vqdmulh_v, aarch64_neon_sqdmulh, Add1ArgType),
- NEONMAP1(vqdmulhq_v, aarch64_neon_sqdmulh, Add1ArgType),
- NEONMAP1(vqdmull_v, aarch64_neon_sqdmull, Add1ArgType),
- NEONMAP2(vqmovn_v, aarch64_neon_uqxtn, aarch64_neon_sqxtn, Add1ArgType | UnsignedAlts),
- NEONMAP1(vqmovun_v, aarch64_neon_sqxtun, Add1ArgType),
- NEONMAP1(vqneg_v, aarch64_neon_sqneg, Add1ArgType),
- NEONMAP1(vqnegq_v, aarch64_neon_sqneg, Add1ArgType),
- NEONMAP1(vqrdmulh_v, aarch64_neon_sqrdmulh, Add1ArgType),
- NEONMAP1(vqrdmulhq_v, aarch64_neon_sqrdmulh, Add1ArgType),
- NEONMAP2(vqrshl_v, aarch64_neon_uqrshl, aarch64_neon_sqrshl, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqrshlq_v, aarch64_neon_uqrshl, aarch64_neon_sqrshl, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqshl_n_v, aarch64_neon_uqshl, aarch64_neon_sqshl, UnsignedAlts),
- NEONMAP2(vqshl_v, aarch64_neon_uqshl, aarch64_neon_sqshl, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqshlq_n_v, aarch64_neon_uqshl, aarch64_neon_sqshl,UnsignedAlts),
- NEONMAP2(vqshlq_v, aarch64_neon_uqshl, aarch64_neon_sqshl, Add1ArgType | UnsignedAlts),
- NEONMAP1(vqshlu_n_v, aarch64_neon_sqshlu, 0),
- NEONMAP1(vqshluq_n_v, aarch64_neon_sqshlu, 0),
- NEONMAP2(vqsub_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
- NEONMAP2(vqsubq_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
- NEONMAP1(vraddhn_v, aarch64_neon_raddhn, Add1ArgType),
- NEONMAP2(vrecpe_v, aarch64_neon_frecpe, aarch64_neon_urecpe, 0),
- NEONMAP2(vrecpeq_v, aarch64_neon_frecpe, aarch64_neon_urecpe, 0),
- NEONMAP1(vrecps_v, aarch64_neon_frecps, Add1ArgType),
- NEONMAP1(vrecpsq_v, aarch64_neon_frecps, Add1ArgType),
- NEONMAP2(vrhadd_v, aarch64_neon_urhadd, aarch64_neon_srhadd, Add1ArgType | UnsignedAlts),
- NEONMAP2(vrhaddq_v, aarch64_neon_urhadd, aarch64_neon_srhadd, Add1ArgType | UnsignedAlts),
- NEONMAP0(vrndi_v),
- NEONMAP0(vrndiq_v),
- NEONMAP2(vrshl_v, aarch64_neon_urshl, aarch64_neon_srshl, Add1ArgType | UnsignedAlts),
- NEONMAP2(vrshlq_v, aarch64_neon_urshl, aarch64_neon_srshl, Add1ArgType | UnsignedAlts),
- NEONMAP2(vrshr_n_v, aarch64_neon_urshl, aarch64_neon_srshl, UnsignedAlts),
- NEONMAP2(vrshrq_n_v, aarch64_neon_urshl, aarch64_neon_srshl, UnsignedAlts),
- NEONMAP2(vrsqrte_v, aarch64_neon_frsqrte, aarch64_neon_ursqrte, 0),
- NEONMAP2(vrsqrteq_v, aarch64_neon_frsqrte, aarch64_neon_ursqrte, 0),
- NEONMAP1(vrsqrts_v, aarch64_neon_frsqrts, Add1ArgType),
- NEONMAP1(vrsqrtsq_v, aarch64_neon_frsqrts, Add1ArgType),
- NEONMAP1(vrsubhn_v, aarch64_neon_rsubhn, Add1ArgType),
- NEONMAP1(vsha1su0q_v, aarch64_crypto_sha1su0, 0),
- NEONMAP1(vsha1su1q_v, aarch64_crypto_sha1su1, 0),
- NEONMAP1(vsha256h2q_v, aarch64_crypto_sha256h2, 0),
- NEONMAP1(vsha256hq_v, aarch64_crypto_sha256h, 0),
- NEONMAP1(vsha256su0q_v, aarch64_crypto_sha256su0, 0),
- NEONMAP1(vsha256su1q_v, aarch64_crypto_sha256su1, 0),
- NEONMAP0(vshl_n_v),
- NEONMAP2(vshl_v, aarch64_neon_ushl, aarch64_neon_sshl, Add1ArgType | UnsignedAlts),
- NEONMAP0(vshll_n_v),
- NEONMAP0(vshlq_n_v),
- NEONMAP2(vshlq_v, aarch64_neon_ushl, aarch64_neon_sshl, Add1ArgType | UnsignedAlts),
- NEONMAP0(vshr_n_v),
- NEONMAP0(vshrn_n_v),
- NEONMAP0(vshrq_n_v),
- NEONMAP1(vst1_x2_v, aarch64_neon_st1x2, 0),
- NEONMAP1(vst1_x3_v, aarch64_neon_st1x3, 0),
- NEONMAP1(vst1_x4_v, aarch64_neon_st1x4, 0),
- NEONMAP1(vst1q_x2_v, aarch64_neon_st1x2, 0),
- NEONMAP1(vst1q_x3_v, aarch64_neon_st1x3, 0),
- NEONMAP1(vst1q_x4_v, aarch64_neon_st1x4, 0),
- NEONMAP0(vsubhn_v),
- NEONMAP0(vtst_v),
- NEONMAP0(vtstq_v),
-};
-
-static const NeonIntrinsicInfo AArch64SISDIntrinsicMap[] = {
- NEONMAP1(vabdd_f64, aarch64_sisd_fabd, Add1ArgType),
- NEONMAP1(vabds_f32, aarch64_sisd_fabd, Add1ArgType),
- NEONMAP1(vabsd_s64, aarch64_neon_abs, Add1ArgType),
- NEONMAP1(vaddlv_s32, aarch64_neon_saddlv, AddRetType | Add1ArgType),
- NEONMAP1(vaddlv_u32, aarch64_neon_uaddlv, AddRetType | Add1ArgType),
- NEONMAP1(vaddlvq_s32, aarch64_neon_saddlv, AddRetType | Add1ArgType),
- NEONMAP1(vaddlvq_u32, aarch64_neon_uaddlv, AddRetType | Add1ArgType),
- NEONMAP1(vaddv_f32, aarch64_neon_faddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddv_s32, aarch64_neon_saddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddv_u32, aarch64_neon_uaddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddvq_f32, aarch64_neon_faddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddvq_f64, aarch64_neon_faddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddvq_s32, aarch64_neon_saddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddvq_s64, aarch64_neon_saddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddvq_u32, aarch64_neon_uaddv, AddRetType | Add1ArgType),
- NEONMAP1(vaddvq_u64, aarch64_neon_uaddv, AddRetType | Add1ArgType),
- NEONMAP1(vcaged_f64, aarch64_neon_facge, AddRetType | Add1ArgType),
- NEONMAP1(vcages_f32, aarch64_neon_facge, AddRetType | Add1ArgType),
- NEONMAP1(vcagtd_f64, aarch64_neon_facgt, AddRetType | Add1ArgType),
- NEONMAP1(vcagts_f32, aarch64_neon_facgt, AddRetType | Add1ArgType),
- NEONMAP1(vcaled_f64, aarch64_neon_facge, AddRetType | Add1ArgType),
- NEONMAP1(vcales_f32, aarch64_neon_facge, AddRetType | Add1ArgType),
- NEONMAP1(vcaltd_f64, aarch64_neon_facgt, AddRetType | Add1ArgType),
- NEONMAP1(vcalts_f32, aarch64_neon_facgt, AddRetType | Add1ArgType),
- NEONMAP1(vcvtad_s64_f64, aarch64_neon_fcvtas, AddRetType | Add1ArgType),
- NEONMAP1(vcvtad_u64_f64, aarch64_neon_fcvtau, AddRetType | Add1ArgType),
- NEONMAP1(vcvtas_s32_f32, aarch64_neon_fcvtas, AddRetType | Add1ArgType),
- NEONMAP1(vcvtas_u32_f32, aarch64_neon_fcvtau, AddRetType | Add1ArgType),
- NEONMAP1(vcvtd_n_f64_s64, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvtd_n_f64_u64, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvtd_n_s64_f64, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType),
- NEONMAP1(vcvtd_n_u64_f64, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtmd_s64_f64, aarch64_neon_fcvtms, AddRetType | Add1ArgType),
- NEONMAP1(vcvtmd_u64_f64, aarch64_neon_fcvtmu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtms_s32_f32, aarch64_neon_fcvtms, AddRetType | Add1ArgType),
- NEONMAP1(vcvtms_u32_f32, aarch64_neon_fcvtmu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtnd_s64_f64, aarch64_neon_fcvtns, AddRetType | Add1ArgType),
- NEONMAP1(vcvtnd_u64_f64, aarch64_neon_fcvtnu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtns_s32_f32, aarch64_neon_fcvtns, AddRetType | Add1ArgType),
- NEONMAP1(vcvtns_u32_f32, aarch64_neon_fcvtnu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtpd_s64_f64, aarch64_neon_fcvtps, AddRetType | Add1ArgType),
- NEONMAP1(vcvtpd_u64_f64, aarch64_neon_fcvtpu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtps_s32_f32, aarch64_neon_fcvtps, AddRetType | Add1ArgType),
- NEONMAP1(vcvtps_u32_f32, aarch64_neon_fcvtpu, AddRetType | Add1ArgType),
- NEONMAP1(vcvts_n_f32_s32, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvts_n_f32_u32, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvts_n_s32_f32, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType),
- NEONMAP1(vcvts_n_u32_f32, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtxd_f32_f64, aarch64_sisd_fcvtxn, 0),
- NEONMAP1(vmaxnmv_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxnmvq_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxnmvq_f64, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxv_f32, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxv_s32, aarch64_neon_smaxv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxv_u32, aarch64_neon_umaxv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxvq_f32, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxvq_f64, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxvq_s32, aarch64_neon_smaxv, AddRetType | Add1ArgType),
- NEONMAP1(vmaxvq_u32, aarch64_neon_umaxv, AddRetType | Add1ArgType),
- NEONMAP1(vminnmv_f32, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
- NEONMAP1(vminnmvq_f32, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
- NEONMAP1(vminnmvq_f64, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
- NEONMAP1(vminv_f32, aarch64_neon_fminv, AddRetType | Add1ArgType),
- NEONMAP1(vminv_s32, aarch64_neon_sminv, AddRetType | Add1ArgType),
- NEONMAP1(vminv_u32, aarch64_neon_uminv, AddRetType | Add1ArgType),
- NEONMAP1(vminvq_f32, aarch64_neon_fminv, AddRetType | Add1ArgType),
- NEONMAP1(vminvq_f64, aarch64_neon_fminv, AddRetType | Add1ArgType),
- NEONMAP1(vminvq_s32, aarch64_neon_sminv, AddRetType | Add1ArgType),
- NEONMAP1(vminvq_u32, aarch64_neon_uminv, AddRetType | Add1ArgType),
- NEONMAP1(vmull_p64, aarch64_neon_pmull64, 0),
- NEONMAP1(vmulxd_f64, aarch64_neon_fmulx, Add1ArgType),
- NEONMAP1(vmulxs_f32, aarch64_neon_fmulx, Add1ArgType),
- NEONMAP1(vpaddd_s64, aarch64_neon_uaddv, AddRetType | Add1ArgType),
- NEONMAP1(vpaddd_u64, aarch64_neon_uaddv, AddRetType | Add1ArgType),
- NEONMAP1(vpmaxnmqd_f64, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
- NEONMAP1(vpmaxnms_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
- NEONMAP1(vpmaxqd_f64, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
- NEONMAP1(vpmaxs_f32, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
- NEONMAP1(vpminnmqd_f64, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
- NEONMAP1(vpminnms_f32, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
- NEONMAP1(vpminqd_f64, aarch64_neon_fminv, AddRetType | Add1ArgType),
- NEONMAP1(vpmins_f32, aarch64_neon_fminv, AddRetType | Add1ArgType),
- NEONMAP1(vqabsb_s8, aarch64_neon_sqabs, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqabsd_s64, aarch64_neon_sqabs, Add1ArgType),
- NEONMAP1(vqabsh_s16, aarch64_neon_sqabs, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqabss_s32, aarch64_neon_sqabs, Add1ArgType),
- NEONMAP1(vqaddb_s8, aarch64_neon_sqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqaddb_u8, aarch64_neon_uqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqaddd_s64, aarch64_neon_sqadd, Add1ArgType),
- NEONMAP1(vqaddd_u64, aarch64_neon_uqadd, Add1ArgType),
- NEONMAP1(vqaddh_s16, aarch64_neon_sqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqaddh_u16, aarch64_neon_uqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqadds_s32, aarch64_neon_sqadd, Add1ArgType),
- NEONMAP1(vqadds_u32, aarch64_neon_uqadd, Add1ArgType),
- NEONMAP1(vqdmulhh_s16, aarch64_neon_sqdmulh, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqdmulhs_s32, aarch64_neon_sqdmulh, Add1ArgType),
- NEONMAP1(vqdmullh_s16, aarch64_neon_sqdmull, VectorRet | Use128BitVectors),
- NEONMAP1(vqdmulls_s32, aarch64_neon_sqdmulls_scalar, 0),
- NEONMAP1(vqmovnd_s64, aarch64_neon_scalar_sqxtn, AddRetType | Add1ArgType),
- NEONMAP1(vqmovnd_u64, aarch64_neon_scalar_uqxtn, AddRetType | Add1ArgType),
- NEONMAP1(vqmovnh_s16, aarch64_neon_sqxtn, VectorRet | Use64BitVectors),
- NEONMAP1(vqmovnh_u16, aarch64_neon_uqxtn, VectorRet | Use64BitVectors),
- NEONMAP1(vqmovns_s32, aarch64_neon_sqxtn, VectorRet | Use64BitVectors),
- NEONMAP1(vqmovns_u32, aarch64_neon_uqxtn, VectorRet | Use64BitVectors),
- NEONMAP1(vqmovund_s64, aarch64_neon_scalar_sqxtun, AddRetType | Add1ArgType),
- NEONMAP1(vqmovunh_s16, aarch64_neon_sqxtun, VectorRet | Use64BitVectors),
- NEONMAP1(vqmovuns_s32, aarch64_neon_sqxtun, VectorRet | Use64BitVectors),
- NEONMAP1(vqnegb_s8, aarch64_neon_sqneg, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqnegd_s64, aarch64_neon_sqneg, Add1ArgType),
- NEONMAP1(vqnegh_s16, aarch64_neon_sqneg, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqnegs_s32, aarch64_neon_sqneg, Add1ArgType),
- NEONMAP1(vqrdmulhh_s16, aarch64_neon_sqrdmulh, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqrdmulhs_s32, aarch64_neon_sqrdmulh, Add1ArgType),
- NEONMAP1(vqrshlb_s8, aarch64_neon_sqrshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqrshlb_u8, aarch64_neon_uqrshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqrshld_s64, aarch64_neon_sqrshl, Add1ArgType),
- NEONMAP1(vqrshld_u64, aarch64_neon_uqrshl, Add1ArgType),
- NEONMAP1(vqrshlh_s16, aarch64_neon_sqrshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqrshlh_u16, aarch64_neon_uqrshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqrshls_s32, aarch64_neon_sqrshl, Add1ArgType),
- NEONMAP1(vqrshls_u32, aarch64_neon_uqrshl, Add1ArgType),
- NEONMAP1(vqrshrnd_n_s64, aarch64_neon_sqrshrn, AddRetType),
- NEONMAP1(vqrshrnd_n_u64, aarch64_neon_uqrshrn, AddRetType),
- NEONMAP1(vqrshrnh_n_s16, aarch64_neon_sqrshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqrshrnh_n_u16, aarch64_neon_uqrshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqrshrns_n_s32, aarch64_neon_sqrshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqrshrns_n_u32, aarch64_neon_uqrshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqrshrund_n_s64, aarch64_neon_sqrshrun, AddRetType),
- NEONMAP1(vqrshrunh_n_s16, aarch64_neon_sqrshrun, VectorRet | Use64BitVectors),
- NEONMAP1(vqrshruns_n_s32, aarch64_neon_sqrshrun, VectorRet | Use64BitVectors),
- NEONMAP1(vqshlb_n_s8, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshlb_n_u8, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshlb_s8, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshlb_u8, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshld_s64, aarch64_neon_sqshl, Add1ArgType),
- NEONMAP1(vqshld_u64, aarch64_neon_uqshl, Add1ArgType),
- NEONMAP1(vqshlh_n_s16, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshlh_n_u16, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshlh_s16, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshlh_u16, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshls_n_s32, aarch64_neon_sqshl, Add1ArgType),
- NEONMAP1(vqshls_n_u32, aarch64_neon_uqshl, Add1ArgType),
- NEONMAP1(vqshls_s32, aarch64_neon_sqshl, Add1ArgType),
- NEONMAP1(vqshls_u32, aarch64_neon_uqshl, Add1ArgType),
- NEONMAP1(vqshlub_n_s8, aarch64_neon_sqshlu, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshluh_n_s16, aarch64_neon_sqshlu, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqshlus_n_s32, aarch64_neon_sqshlu, Add1ArgType),
- NEONMAP1(vqshrnd_n_s64, aarch64_neon_sqshrn, AddRetType),
- NEONMAP1(vqshrnd_n_u64, aarch64_neon_uqshrn, AddRetType),
- NEONMAP1(vqshrnh_n_s16, aarch64_neon_sqshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqshrnh_n_u16, aarch64_neon_uqshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqshrns_n_s32, aarch64_neon_sqshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqshrns_n_u32, aarch64_neon_uqshrn, VectorRet | Use64BitVectors),
- NEONMAP1(vqshrund_n_s64, aarch64_neon_sqshrun, AddRetType),
- NEONMAP1(vqshrunh_n_s16, aarch64_neon_sqshrun, VectorRet | Use64BitVectors),
- NEONMAP1(vqshruns_n_s32, aarch64_neon_sqshrun, VectorRet | Use64BitVectors),
- NEONMAP1(vqsubb_s8, aarch64_neon_sqsub, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqsubb_u8, aarch64_neon_uqsub, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqsubd_s64, aarch64_neon_sqsub, Add1ArgType),
- NEONMAP1(vqsubd_u64, aarch64_neon_uqsub, Add1ArgType),
- NEONMAP1(vqsubh_s16, aarch64_neon_sqsub, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqsubh_u16, aarch64_neon_uqsub, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vqsubs_s32, aarch64_neon_sqsub, Add1ArgType),
- NEONMAP1(vqsubs_u32, aarch64_neon_uqsub, Add1ArgType),
- NEONMAP1(vrecped_f64, aarch64_neon_frecpe, Add1ArgType),
- NEONMAP1(vrecpes_f32, aarch64_neon_frecpe, Add1ArgType),
- NEONMAP1(vrecpxd_f64, aarch64_neon_frecpx, Add1ArgType),
- NEONMAP1(vrecpxs_f32, aarch64_neon_frecpx, Add1ArgType),
- NEONMAP1(vrshld_s64, aarch64_neon_srshl, Add1ArgType),
- NEONMAP1(vrshld_u64, aarch64_neon_urshl, Add1ArgType),
- NEONMAP1(vrsqrted_f64, aarch64_neon_frsqrte, Add1ArgType),
- NEONMAP1(vrsqrtes_f32, aarch64_neon_frsqrte, Add1ArgType),
- NEONMAP1(vrsqrtsd_f64, aarch64_neon_frsqrts, Add1ArgType),
- NEONMAP1(vrsqrtss_f32, aarch64_neon_frsqrts, Add1ArgType),
- NEONMAP1(vsha1cq_u32, aarch64_crypto_sha1c, 0),
- NEONMAP1(vsha1h_u32, aarch64_crypto_sha1h, 0),
- NEONMAP1(vsha1mq_u32, aarch64_crypto_sha1m, 0),
- NEONMAP1(vsha1pq_u32, aarch64_crypto_sha1p, 0),
- NEONMAP1(vshld_s64, aarch64_neon_sshl, Add1ArgType),
- NEONMAP1(vshld_u64, aarch64_neon_ushl, Add1ArgType),
- NEONMAP1(vslid_n_s64, aarch64_neon_vsli, Vectorize1ArgType),
- NEONMAP1(vslid_n_u64, aarch64_neon_vsli, Vectorize1ArgType),
- NEONMAP1(vsqaddb_u8, aarch64_neon_usqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vsqaddd_u64, aarch64_neon_usqadd, Add1ArgType),
- NEONMAP1(vsqaddh_u16, aarch64_neon_usqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vsqadds_u32, aarch64_neon_usqadd, Add1ArgType),
- NEONMAP1(vsrid_n_s64, aarch64_neon_vsri, Vectorize1ArgType),
- NEONMAP1(vsrid_n_u64, aarch64_neon_vsri, Vectorize1ArgType),
- NEONMAP1(vuqaddb_s8, aarch64_neon_suqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vuqaddd_s64, aarch64_neon_suqadd, Add1ArgType),
- NEONMAP1(vuqaddh_s16, aarch64_neon_suqadd, Vectorize1ArgType | Use64BitVectors),
- NEONMAP1(vuqadds_s32, aarch64_neon_suqadd, Add1ArgType),
- // FP16 scalar intrinisics go here.
- NEONMAP1(vabdh_f16, aarch64_sisd_fabd, Add1ArgType),
- NEONMAP1(vcvtah_s32_f16, aarch64_neon_fcvtas, AddRetType | Add1ArgType),
- NEONMAP1(vcvtah_s64_f16, aarch64_neon_fcvtas, AddRetType | Add1ArgType),
- NEONMAP1(vcvtah_u32_f16, aarch64_neon_fcvtau, AddRetType | Add1ArgType),
- NEONMAP1(vcvtah_u64_f16, aarch64_neon_fcvtau, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_f16_s32, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_f16_s64, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_f16_u32, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_f16_u64, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_s32_f16, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_s64_f16, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_u32_f16, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType),
- NEONMAP1(vcvth_n_u64_f16, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtmh_s32_f16, aarch64_neon_fcvtms, AddRetType | Add1ArgType),
- NEONMAP1(vcvtmh_s64_f16, aarch64_neon_fcvtms, AddRetType | Add1ArgType),
- NEONMAP1(vcvtmh_u32_f16, aarch64_neon_fcvtmu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtmh_u64_f16, aarch64_neon_fcvtmu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtnh_s32_f16, aarch64_neon_fcvtns, AddRetType | Add1ArgType),
- NEONMAP1(vcvtnh_s64_f16, aarch64_neon_fcvtns, AddRetType | Add1ArgType),
- NEONMAP1(vcvtnh_u32_f16, aarch64_neon_fcvtnu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtnh_u64_f16, aarch64_neon_fcvtnu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtph_s32_f16, aarch64_neon_fcvtps, AddRetType | Add1ArgType),
- NEONMAP1(vcvtph_s64_f16, aarch64_neon_fcvtps, AddRetType | Add1ArgType),
- NEONMAP1(vcvtph_u32_f16, aarch64_neon_fcvtpu, AddRetType | Add1ArgType),
- NEONMAP1(vcvtph_u64_f16, aarch64_neon_fcvtpu, AddRetType | Add1ArgType),
- NEONMAP1(vmulxh_f16, aarch64_neon_fmulx, Add1ArgType),
- NEONMAP1(vrecpeh_f16, aarch64_neon_frecpe, Add1ArgType),
- NEONMAP1(vrecpxh_f16, aarch64_neon_frecpx, Add1ArgType),
- NEONMAP1(vrsqrteh_f16, aarch64_neon_frsqrte, Add1ArgType),
- NEONMAP1(vrsqrtsh_f16, aarch64_neon_frsqrts, Add1ArgType),
-};
-
-#undef NEONMAP0
-#undef NEONMAP1
-#undef NEONMAP2
-
-static bool NEONSIMDIntrinsicsProvenSorted = false;
-
-static bool AArch64SIMDIntrinsicsProvenSorted = false;
-static bool AArch64SISDIntrinsicsProvenSorted = false;
-
-
-static const NeonIntrinsicInfo *
-findNeonIntrinsicInMap(ArrayRef<NeonIntrinsicInfo> IntrinsicMap,
- unsigned BuiltinID, bool &MapProvenSorted) {
-
-#ifndef NDEBUG
- if (!MapProvenSorted) {
- assert(std::is_sorted(std::begin(IntrinsicMap), std::end(IntrinsicMap)));
- MapProvenSorted = true;
- }
-#endif
-
- const NeonIntrinsicInfo *Builtin =
- std::lower_bound(IntrinsicMap.begin(), IntrinsicMap.end(), BuiltinID);
-
- if (Builtin != IntrinsicMap.end() && Builtin->BuiltinID == BuiltinID)
- return Builtin;
-
- return nullptr;
-}
-
-Function *CodeGenFunction::LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
- unsigned Modifier,
- llvm::Type *ArgType,
- const CallExpr *E) {
- int VectorSize = 0;
- if (Modifier & Use64BitVectors)
- VectorSize = 64;
- else if (Modifier & Use128BitVectors)
- VectorSize = 128;
-
- // Return type.
- SmallVector<llvm::Type *, 3> Tys;
- if (Modifier & AddRetType) {
- llvm::Type *Ty = ConvertType(E->getCallReturnType(getContext()));
- if (Modifier & VectorizeRetType)
- Ty = llvm::VectorType::get(
- Ty, VectorSize ? VectorSize / Ty->getPrimitiveSizeInBits() : 1);
-
- Tys.push_back(Ty);
- }
-
- // Arguments.
- if (Modifier & VectorizeArgTypes) {
- int Elts = VectorSize ? VectorSize / ArgType->getPrimitiveSizeInBits() : 1;
- ArgType = llvm::VectorType::get(ArgType, Elts);
- }
-
- if (Modifier & (Add1ArgType | Add2ArgTypes))
- Tys.push_back(ArgType);
-
- if (Modifier & Add2ArgTypes)
- Tys.push_back(ArgType);
-
- if (Modifier & InventFloatType)
- Tys.push_back(FloatTy);
-
- return CGM.getIntrinsic(IntrinsicID, Tys);
-}
-
-static Value *EmitCommonNeonSISDBuiltinExpr(CodeGenFunction &CGF,
- const NeonIntrinsicInfo &SISDInfo,
- SmallVectorImpl<Value *> &Ops,
- const CallExpr *E) {
- unsigned BuiltinID = SISDInfo.BuiltinID;
- unsigned int Int = SISDInfo.LLVMIntrinsic;
- unsigned Modifier = SISDInfo.TypeModifier;
- const char *s = SISDInfo.NameHint;
-
- switch (BuiltinID) {
- case NEON::BI__builtin_neon_vcled_s64:
- case NEON::BI__builtin_neon_vcled_u64:
- case NEON::BI__builtin_neon_vcles_f32:
- case NEON::BI__builtin_neon_vcled_f64:
- case NEON::BI__builtin_neon_vcltd_s64:
- case NEON::BI__builtin_neon_vcltd_u64:
- case NEON::BI__builtin_neon_vclts_f32:
- case NEON::BI__builtin_neon_vcltd_f64:
- case NEON::BI__builtin_neon_vcales_f32:
- case NEON::BI__builtin_neon_vcaled_f64:
- case NEON::BI__builtin_neon_vcalts_f32:
- case NEON::BI__builtin_neon_vcaltd_f64:
- // Only one direction of comparisons actually exist, cmle is actually a cmge
- // with swapped operands. The table gives us the right intrinsic but we
- // still need to do the swap.
- std::swap(Ops[0], Ops[1]);
- break;
- }
-
- assert(Int && "Generic code assumes a valid intrinsic");
-
- // Determine the type(s) of this overloaded AArch64 intrinsic.
- const Expr *Arg = E->getArg(0);
- llvm::Type *ArgTy = CGF.ConvertType(Arg->getType());
- Function *F = CGF.LookupNeonLLVMIntrinsic(Int, Modifier, ArgTy, E);
-
- int j = 0;
- ConstantInt *C0 = ConstantInt::get(CGF.SizeTy, 0);
- for (Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end();
- ai != ae; ++ai, ++j) {
- llvm::Type *ArgTy = ai->getType();
- if (Ops[j]->getType()->getPrimitiveSizeInBits() ==
- ArgTy->getPrimitiveSizeInBits())
- continue;
-
- assert(ArgTy->isVectorTy() && !Ops[j]->getType()->isVectorTy());
- // The constant argument to an _n_ intrinsic always has Int32Ty, so truncate
- // it before inserting.
- Ops[j] =
- CGF.Builder.CreateTruncOrBitCast(Ops[j], ArgTy->getVectorElementType());
- Ops[j] =
- CGF.Builder.CreateInsertElement(UndefValue::get(ArgTy), Ops[j], C0);
- }
-
- Value *Result = CGF.EmitNeonCall(F, Ops, s);
- llvm::Type *ResultType = CGF.ConvertType(E->getType());
- if (ResultType->getPrimitiveSizeInBits() <
- Result->getType()->getPrimitiveSizeInBits())
- return CGF.Builder.CreateExtractElement(Result, C0);
-
- return CGF.Builder.CreateBitCast(Result, ResultType, s);
-}
-
-Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
- unsigned BuiltinID, unsigned LLVMIntrinsic, unsigned AltLLVMIntrinsic,
- const char *NameHint, unsigned Modifier, const CallExpr *E,
- SmallVectorImpl<llvm::Value *> &Ops, Address PtrOp0, Address PtrOp1,
- llvm::Triple::ArchType Arch) {
- // Get the last argument, which specifies the vector type.
- llvm::APSInt NeonTypeConst;
- const Expr *Arg = E->getArg(E->getNumArgs() - 1);
- if (!Arg->isIntegerConstantExpr(NeonTypeConst, getContext()))
- return nullptr;
-
- // Determine the type of this overloaded NEON intrinsic.
- NeonTypeFlags Type(NeonTypeConst.getZExtValue());
- bool Usgn = Type.isUnsigned();
- bool Quad = Type.isQuad();
- const bool HasLegalHalfType = getTarget().hasLegalHalfType();
-
- llvm::VectorType *VTy = GetNeonType(this, Type, HasLegalHalfType);
- llvm::Type *Ty = VTy;
- if (!Ty)
- return nullptr;
-
- auto getAlignmentValue32 = [&](Address addr) -> Value* {
- return Builder.getInt32(addr.getAlignment().getQuantity());
- };
-
- unsigned Int = LLVMIntrinsic;
- if ((Modifier & UnsignedAlts) && !Usgn)
- Int = AltLLVMIntrinsic;
-
- switch (BuiltinID) {
- default: break;
- case NEON::BI__builtin_neon_vabs_v:
- case NEON::BI__builtin_neon_vabsq_v:
- if (VTy->getElementType()->isFloatingPointTy())
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::fabs, Ty), Ops, "vabs");
- return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Ty), Ops, "vabs");
- case NEON::BI__builtin_neon_vaddhn_v: {
- llvm::VectorType *SrcTy =
- llvm::VectorType::getExtendedElementVectorType(VTy);
-
- // %sum = add <4 x i32> %lhs, %rhs
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
- Ops[0] = Builder.CreateAdd(Ops[0], Ops[1], "vaddhn");
-
- // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
- Constant *ShiftAmt =
- ConstantInt::get(SrcTy, SrcTy->getScalarSizeInBits() / 2);
- Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vaddhn");
-
- // %res = trunc <4 x i32> %high to <4 x i16>
- return Builder.CreateTrunc(Ops[0], VTy, "vaddhn");
- }
- case NEON::BI__builtin_neon_vcale_v:
- case NEON::BI__builtin_neon_vcaleq_v:
- case NEON::BI__builtin_neon_vcalt_v:
- case NEON::BI__builtin_neon_vcaltq_v:
- std::swap(Ops[0], Ops[1]);
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vcage_v:
- case NEON::BI__builtin_neon_vcageq_v:
- case NEON::BI__builtin_neon_vcagt_v:
- case NEON::BI__builtin_neon_vcagtq_v: {
- llvm::Type *Ty;
- switch (VTy->getScalarSizeInBits()) {
- default: llvm_unreachable("unexpected type");
- case 32:
- Ty = FloatTy;
- break;
- case 64:
- Ty = DoubleTy;
- break;
- case 16:
- Ty = HalfTy;
- break;
- }
- llvm::Type *VecFlt = llvm::VectorType::get(Ty, VTy->getNumElements());
- llvm::Type *Tys[] = { VTy, VecFlt };
- Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
- return EmitNeonCall(F, Ops, NameHint);
- }
- case NEON::BI__builtin_neon_vceqz_v:
- case NEON::BI__builtin_neon_vceqzq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OEQ,
- ICmpInst::ICMP_EQ, "vceqz");
- case NEON::BI__builtin_neon_vcgez_v:
- case NEON::BI__builtin_neon_vcgezq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGE,
- ICmpInst::ICMP_SGE, "vcgez");
- case NEON::BI__builtin_neon_vclez_v:
- case NEON::BI__builtin_neon_vclezq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLE,
- ICmpInst::ICMP_SLE, "vclez");
- case NEON::BI__builtin_neon_vcgtz_v:
- case NEON::BI__builtin_neon_vcgtzq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGT,
- ICmpInst::ICMP_SGT, "vcgtz");
- case NEON::BI__builtin_neon_vcltz_v:
- case NEON::BI__builtin_neon_vcltzq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLT,
- ICmpInst::ICMP_SLT, "vcltz");
- case NEON::BI__builtin_neon_vclz_v:
- case NEON::BI__builtin_neon_vclzq_v:
- // We generate target-independent intrinsic, which needs a second argument
- // for whether or not clz of zero is undefined; on ARM it isn't.
- Ops.push_back(Builder.getInt1(getTarget().isCLZForZeroUndef()));
- break;
- case NEON::BI__builtin_neon_vcvt_f32_v:
- case NEON::BI__builtin_neon_vcvtq_f32_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, Quad),
- HasLegalHalfType);
- return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
- : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- case NEON::BI__builtin_neon_vcvt_f16_v:
- case NEON::BI__builtin_neon_vcvtq_f16_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float16, false, Quad),
- HasLegalHalfType);
- return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
- : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- case NEON::BI__builtin_neon_vcvt_n_f16_v:
- case NEON::BI__builtin_neon_vcvt_n_f32_v:
- case NEON::BI__builtin_neon_vcvt_n_f64_v:
- case NEON::BI__builtin_neon_vcvtq_n_f16_v:
- case NEON::BI__builtin_neon_vcvtq_n_f32_v:
- case NEON::BI__builtin_neon_vcvtq_n_f64_v: {
- llvm::Type *Tys[2] = { GetFloatNeonType(this, Type), Ty };
- Int = Usgn ? LLVMIntrinsic : AltLLVMIntrinsic;
- Function *F = CGM.getIntrinsic(Int, Tys);
- return EmitNeonCall(F, Ops, "vcvt_n");
- }
- case NEON::BI__builtin_neon_vcvt_n_s16_v:
- case NEON::BI__builtin_neon_vcvt_n_s32_v:
- case NEON::BI__builtin_neon_vcvt_n_u16_v:
- case NEON::BI__builtin_neon_vcvt_n_u32_v:
- case NEON::BI__builtin_neon_vcvt_n_s64_v:
- case NEON::BI__builtin_neon_vcvt_n_u64_v:
- case NEON::BI__builtin_neon_vcvtq_n_s16_v:
- case NEON::BI__builtin_neon_vcvtq_n_s32_v:
- case NEON::BI__builtin_neon_vcvtq_n_u16_v:
- case NEON::BI__builtin_neon_vcvtq_n_u32_v:
- case NEON::BI__builtin_neon_vcvtq_n_s64_v:
- case NEON::BI__builtin_neon_vcvtq_n_u64_v: {
- llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
- Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
- return EmitNeonCall(F, Ops, "vcvt_n");
- }
- case NEON::BI__builtin_neon_vcvt_s32_v:
- case NEON::BI__builtin_neon_vcvt_u32_v:
- case NEON::BI__builtin_neon_vcvt_s64_v:
- case NEON::BI__builtin_neon_vcvt_u64_v:
- case NEON::BI__builtin_neon_vcvt_s16_v:
- case NEON::BI__builtin_neon_vcvt_u16_v:
- case NEON::BI__builtin_neon_vcvtq_s32_v:
- case NEON::BI__builtin_neon_vcvtq_u32_v:
- case NEON::BI__builtin_neon_vcvtq_s64_v:
- case NEON::BI__builtin_neon_vcvtq_u64_v:
- case NEON::BI__builtin_neon_vcvtq_s16_v:
- case NEON::BI__builtin_neon_vcvtq_u16_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type));
- return Usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
- : Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
- }
- case NEON::BI__builtin_neon_vcvta_s16_v:
- case NEON::BI__builtin_neon_vcvta_s32_v:
- case NEON::BI__builtin_neon_vcvta_s64_v:
- case NEON::BI__builtin_neon_vcvta_u16_v:
- case NEON::BI__builtin_neon_vcvta_u32_v:
- case NEON::BI__builtin_neon_vcvta_u64_v:
- case NEON::BI__builtin_neon_vcvtaq_s16_v:
- case NEON::BI__builtin_neon_vcvtaq_s32_v:
- case NEON::BI__builtin_neon_vcvtaq_s64_v:
- case NEON::BI__builtin_neon_vcvtaq_u16_v:
- case NEON::BI__builtin_neon_vcvtaq_u32_v:
- case NEON::BI__builtin_neon_vcvtaq_u64_v:
- case NEON::BI__builtin_neon_vcvtn_s16_v:
- case NEON::BI__builtin_neon_vcvtn_s32_v:
- case NEON::BI__builtin_neon_vcvtn_s64_v:
- case NEON::BI__builtin_neon_vcvtn_u16_v:
- case NEON::BI__builtin_neon_vcvtn_u32_v:
- case NEON::BI__builtin_neon_vcvtn_u64_v:
- case NEON::BI__builtin_neon_vcvtnq_s16_v:
- case NEON::BI__builtin_neon_vcvtnq_s32_v:
- case NEON::BI__builtin_neon_vcvtnq_s64_v:
- case NEON::BI__builtin_neon_vcvtnq_u16_v:
- case NEON::BI__builtin_neon_vcvtnq_u32_v:
- case NEON::BI__builtin_neon_vcvtnq_u64_v:
- case NEON::BI__builtin_neon_vcvtp_s16_v:
- case NEON::BI__builtin_neon_vcvtp_s32_v:
- case NEON::BI__builtin_neon_vcvtp_s64_v:
- case NEON::BI__builtin_neon_vcvtp_u16_v:
- case NEON::BI__builtin_neon_vcvtp_u32_v:
- case NEON::BI__builtin_neon_vcvtp_u64_v:
- case NEON::BI__builtin_neon_vcvtpq_s16_v:
- case NEON::BI__builtin_neon_vcvtpq_s32_v:
- case NEON::BI__builtin_neon_vcvtpq_s64_v:
- case NEON::BI__builtin_neon_vcvtpq_u16_v:
- case NEON::BI__builtin_neon_vcvtpq_u32_v:
- case NEON::BI__builtin_neon_vcvtpq_u64_v:
- case NEON::BI__builtin_neon_vcvtm_s16_v:
- case NEON::BI__builtin_neon_vcvtm_s32_v:
- case NEON::BI__builtin_neon_vcvtm_s64_v:
- case NEON::BI__builtin_neon_vcvtm_u16_v:
- case NEON::BI__builtin_neon_vcvtm_u32_v:
- case NEON::BI__builtin_neon_vcvtm_u64_v:
- case NEON::BI__builtin_neon_vcvtmq_s16_v:
- case NEON::BI__builtin_neon_vcvtmq_s32_v:
- case NEON::BI__builtin_neon_vcvtmq_s64_v:
- case NEON::BI__builtin_neon_vcvtmq_u16_v:
- case NEON::BI__builtin_neon_vcvtmq_u32_v:
- case NEON::BI__builtin_neon_vcvtmq_u64_v: {
- llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
- return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, NameHint);
- }
- case NEON::BI__builtin_neon_vext_v:
- case NEON::BI__builtin_neon_vextq_v: {
- int CV = cast<ConstantInt>(Ops[2])->getSExtValue();
- SmallVector<uint32_t, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
- Indices.push_back(i+CV);
-
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- return Builder.CreateShuffleVector(Ops[0], Ops[1], Indices, "vext");
- }
- case NEON::BI__builtin_neon_vfma_v:
- case NEON::BI__builtin_neon_vfmaq_v: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
-
- // NEON intrinsic puts accumulator first, unlike the LLVM fma.
- return Builder.CreateCall(F, {Ops[1], Ops[2], Ops[0]});
- }
- case NEON::BI__builtin_neon_vld1_v:
- case NEON::BI__builtin_neon_vld1q_v: {
- llvm::Type *Tys[] = {Ty, Int8PtrTy};
- Ops.push_back(getAlignmentValue32(PtrOp0));
- return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, "vld1");
- }
- case NEON::BI__builtin_neon_vld1_x2_v:
- case NEON::BI__builtin_neon_vld1q_x2_v:
- case NEON::BI__builtin_neon_vld1_x3_v:
- case NEON::BI__builtin_neon_vld1q_x3_v:
- case NEON::BI__builtin_neon_vld1_x4_v:
- case NEON::BI__builtin_neon_vld1q_x4_v: {
- llvm::Type *PTy = llvm::PointerType::getUnqual(VTy->getVectorElementType());
- Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
- llvm::Type *Tys[2] = { VTy, PTy };
- Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
- Ops[1] = Builder.CreateCall(F, Ops[1], "vld1xN");
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld2_v:
- case NEON::BI__builtin_neon_vld2q_v:
- case NEON::BI__builtin_neon_vld3_v:
- case NEON::BI__builtin_neon_vld3q_v:
- case NEON::BI__builtin_neon_vld4_v:
- case NEON::BI__builtin_neon_vld4q_v:
- case NEON::BI__builtin_neon_vld2_dup_v:
- case NEON::BI__builtin_neon_vld2q_dup_v:
- case NEON::BI__builtin_neon_vld3_dup_v:
- case NEON::BI__builtin_neon_vld3q_dup_v:
- case NEON::BI__builtin_neon_vld4_dup_v:
- case NEON::BI__builtin_neon_vld4q_dup_v: {
- llvm::Type *Tys[] = {Ty, Int8PtrTy};
- Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
- Value *Align = getAlignmentValue32(PtrOp1);
- Ops[1] = Builder.CreateCall(F, {Ops[1], Align}, NameHint);
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld1_dup_v:
- case NEON::BI__builtin_neon_vld1q_dup_v: {
- Value *V = UndefValue::get(Ty);
- Ty = llvm::PointerType::getUnqual(VTy->getElementType());
- PtrOp0 = Builder.CreateBitCast(PtrOp0, Ty);
- LoadInst *Ld = Builder.CreateLoad(PtrOp0);
- llvm::Constant *CI = ConstantInt::get(SizeTy, 0);
- Ops[0] = Builder.CreateInsertElement(V, Ld, CI);
- return EmitNeonSplat(Ops[0], CI);
- }
- case NEON::BI__builtin_neon_vld2_lane_v:
- case NEON::BI__builtin_neon_vld2q_lane_v:
- case NEON::BI__builtin_neon_vld3_lane_v:
- case NEON::BI__builtin_neon_vld3q_lane_v:
- case NEON::BI__builtin_neon_vld4_lane_v:
- case NEON::BI__builtin_neon_vld4q_lane_v: {
- llvm::Type *Tys[] = {Ty, Int8PtrTy};
- Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
- for (unsigned I = 2; I < Ops.size() - 1; ++I)
- Ops[I] = Builder.CreateBitCast(Ops[I], Ty);
- Ops.push_back(getAlignmentValue32(PtrOp1));
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), NameHint);
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vmovl_v: {
- llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], DTy);
- if (Usgn)
- return Builder.CreateZExt(Ops[0], Ty, "vmovl");
- return Builder.CreateSExt(Ops[0], Ty, "vmovl");
- }
- case NEON::BI__builtin_neon_vmovn_v: {
- llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], QTy);
- return Builder.CreateTrunc(Ops[0], Ty, "vmovn");
- }
- case NEON::BI__builtin_neon_vmull_v:
- // FIXME: the integer vmull operations could be emitted in terms of pure
- // LLVM IR (2 exts followed by a mul). Unfortunately LLVM has a habit of
- // hoisting the exts outside loops. Until global ISel comes along that can
- // see through such movement this leads to bad CodeGen. So we need an
- // intrinsic for now.
- Int = Usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
- Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
- case NEON::BI__builtin_neon_vpadal_v:
- case NEON::BI__builtin_neon_vpadalq_v: {
- // The source operand type has twice as many elements of half the size.
- unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
- llvm::Type *EltTy =
- llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
- llvm::Type *NarrowTy =
- llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
- llvm::Type *Tys[2] = { Ty, NarrowTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, NameHint);
- }
- case NEON::BI__builtin_neon_vpaddl_v:
- case NEON::BI__builtin_neon_vpaddlq_v: {
- // The source operand type has twice as many elements of half the size.
- unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
- llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
- llvm::Type *NarrowTy =
- llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
- llvm::Type *Tys[2] = { Ty, NarrowTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vpaddl");
- }
- case NEON::BI__builtin_neon_vqdmlal_v:
- case NEON::BI__builtin_neon_vqdmlsl_v: {
- SmallVector<Value *, 2> MulOps(Ops.begin() + 1, Ops.end());
- Ops[1] =
- EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Ty), MulOps, "vqdmlal");
- Ops.resize(2);
- return EmitNeonCall(CGM.getIntrinsic(AltLLVMIntrinsic, Ty), Ops, NameHint);
- }
- case NEON::BI__builtin_neon_vqshl_n_v:
- case NEON::BI__builtin_neon_vqshlq_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshl_n",
- 1, false);
- case NEON::BI__builtin_neon_vqshlu_n_v:
- case NEON::BI__builtin_neon_vqshluq_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshlu_n",
- 1, false);
- case NEON::BI__builtin_neon_vrecpe_v:
- case NEON::BI__builtin_neon_vrecpeq_v:
- case NEON::BI__builtin_neon_vrsqrte_v:
- case NEON::BI__builtin_neon_vrsqrteq_v:
- Int = Ty->isFPOrFPVectorTy() ? LLVMIntrinsic : AltLLVMIntrinsic;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, NameHint);
- case NEON::BI__builtin_neon_vrndi_v:
- case NEON::BI__builtin_neon_vrndiq_v:
- Int = Intrinsic::nearbyint;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, NameHint);
- case NEON::BI__builtin_neon_vrshr_n_v:
- case NEON::BI__builtin_neon_vrshrq_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n",
- 1, true);
- case NEON::BI__builtin_neon_vshl_n_v:
- case NEON::BI__builtin_neon_vshlq_n_v:
- Ops[1] = EmitNeonShiftVector(Ops[1], Ty, false);
- return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1],
- "vshl_n");
- case NEON::BI__builtin_neon_vshll_n_v: {
- llvm::Type *SrcTy = llvm::VectorType::getTruncatedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- if (Usgn)
- Ops[0] = Builder.CreateZExt(Ops[0], VTy);
- else
- Ops[0] = Builder.CreateSExt(Ops[0], VTy);
- Ops[1] = EmitNeonShiftVector(Ops[1], VTy, false);
- return Builder.CreateShl(Ops[0], Ops[1], "vshll_n");
- }
- case NEON::BI__builtin_neon_vshrn_n_v: {
- llvm::Type *SrcTy = llvm::VectorType::getExtendedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- Ops[1] = EmitNeonShiftVector(Ops[1], SrcTy, false);
- if (Usgn)
- Ops[0] = Builder.CreateLShr(Ops[0], Ops[1]);
- else
- Ops[0] = Builder.CreateAShr(Ops[0], Ops[1]);
- return Builder.CreateTrunc(Ops[0], Ty, "vshrn_n");
- }
- case NEON::BI__builtin_neon_vshr_n_v:
- case NEON::BI__builtin_neon_vshrq_n_v:
- return EmitNeonRShiftImm(Ops[0], Ops[1], Ty, Usgn, "vshr_n");
- case NEON::BI__builtin_neon_vst1_v:
- case NEON::BI__builtin_neon_vst1q_v:
- case NEON::BI__builtin_neon_vst2_v:
- case NEON::BI__builtin_neon_vst2q_v:
- case NEON::BI__builtin_neon_vst3_v:
- case NEON::BI__builtin_neon_vst3q_v:
- case NEON::BI__builtin_neon_vst4_v:
- case NEON::BI__builtin_neon_vst4q_v:
- case NEON::BI__builtin_neon_vst2_lane_v:
- case NEON::BI__builtin_neon_vst2q_lane_v:
- case NEON::BI__builtin_neon_vst3_lane_v:
- case NEON::BI__builtin_neon_vst3q_lane_v:
- case NEON::BI__builtin_neon_vst4_lane_v:
- case NEON::BI__builtin_neon_vst4q_lane_v: {
- llvm::Type *Tys[] = {Int8PtrTy, Ty};
- Ops.push_back(getAlignmentValue32(PtrOp0));
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "");
- }
- case NEON::BI__builtin_neon_vst1_x2_v:
- case NEON::BI__builtin_neon_vst1q_x2_v:
- case NEON::BI__builtin_neon_vst1_x3_v:
- case NEON::BI__builtin_neon_vst1q_x3_v:
- case NEON::BI__builtin_neon_vst1_x4_v:
- case NEON::BI__builtin_neon_vst1q_x4_v: {
- llvm::Type *PTy = llvm::PointerType::getUnqual(VTy->getVectorElementType());
- // TODO: Currently in AArch32 mode the pointer operand comes first, whereas
- // in AArch64 it comes last. We may want to stick to one or another.
- if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be) {
- llvm::Type *Tys[2] = { VTy, PTy };
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());
- return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, "");
- }
- llvm::Type *Tys[2] = { PTy, VTy };
- return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, "");
- }
- case NEON::BI__builtin_neon_vsubhn_v: {
- llvm::VectorType *SrcTy =
- llvm::VectorType::getExtendedElementVectorType(VTy);
-
- // %sum = add <4 x i32> %lhs, %rhs
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
- Ops[0] = Builder.CreateSub(Ops[0], Ops[1], "vsubhn");
-
- // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
- Constant *ShiftAmt =
- ConstantInt::get(SrcTy, SrcTy->getScalarSizeInBits() / 2);
- Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vsubhn");
-
- // %res = trunc <4 x i32> %high to <4 x i16>
- return Builder.CreateTrunc(Ops[0], VTy, "vsubhn");
- }
- case NEON::BI__builtin_neon_vtrn_v:
- case NEON::BI__builtin_neon_vtrnq_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = nullptr;
-
- for (unsigned vi = 0; vi != 2; ++vi) {
- SmallVector<uint32_t, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
- Indices.push_back(i+vi);
- Indices.push_back(i+e+vi);
- }
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
- SV = Builder.CreateShuffleVector(Ops[1], Ops[2], Indices, "vtrn");
- SV = Builder.CreateDefaultAlignedStore(SV, Addr);
- }
- return SV;
- }
- case NEON::BI__builtin_neon_vtst_v:
- case NEON::BI__builtin_neon_vtstq_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[0] = Builder.CreateAnd(Ops[0], Ops[1]);
- Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
- ConstantAggregateZero::get(Ty));
- return Builder.CreateSExt(Ops[0], Ty, "vtst");
- }
- case NEON::BI__builtin_neon_vuzp_v:
- case NEON::BI__builtin_neon_vuzpq_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = nullptr;
-
- for (unsigned vi = 0; vi != 2; ++vi) {
- SmallVector<uint32_t, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
- Indices.push_back(2*i+vi);
-
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
- SV = Builder.CreateShuffleVector(Ops[1], Ops[2], Indices, "vuzp");
- SV = Builder.CreateDefaultAlignedStore(SV, Addr);
- }
- return SV;
- }
- case NEON::BI__builtin_neon_vzip_v:
- case NEON::BI__builtin_neon_vzipq_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = nullptr;
-
- for (unsigned vi = 0; vi != 2; ++vi) {
- SmallVector<uint32_t, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
- Indices.push_back((i + vi*e) >> 1);
- Indices.push_back(((i + vi*e) >> 1)+e);
- }
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
- SV = Builder.CreateShuffleVector(Ops[1], Ops[2], Indices, "vzip");
- SV = Builder.CreateDefaultAlignedStore(SV, Addr);
- }
- return SV;
- }
- case NEON::BI__builtin_neon_vdot_v:
- case NEON::BI__builtin_neon_vdotq_v: {
- llvm::Type *InputTy =
- llvm::VectorType::get(Int8Ty, Ty->getPrimitiveSizeInBits() / 8);
- llvm::Type *Tys[2] = { Ty, InputTy };
- Int = Usgn ? LLVMIntrinsic : AltLLVMIntrinsic;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vdot");
- }
- case NEON::BI__builtin_neon_vfmlal_low_v:
- case NEON::BI__builtin_neon_vfmlalq_low_v: {
- llvm::Type *InputTy =
- llvm::VectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
- llvm::Type *Tys[2] = { Ty, InputTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlal_low");
- }
- case NEON::BI__builtin_neon_vfmlsl_low_v:
- case NEON::BI__builtin_neon_vfmlslq_low_v: {
- llvm::Type *InputTy =
- llvm::VectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
- llvm::Type *Tys[2] = { Ty, InputTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlsl_low");
- }
- case NEON::BI__builtin_neon_vfmlal_high_v:
- case NEON::BI__builtin_neon_vfmlalq_high_v: {
- llvm::Type *InputTy =
- llvm::VectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
- llvm::Type *Tys[2] = { Ty, InputTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlal_high");
- }
- case NEON::BI__builtin_neon_vfmlsl_high_v:
- case NEON::BI__builtin_neon_vfmlslq_high_v: {
- llvm::Type *InputTy =
- llvm::VectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
- llvm::Type *Tys[2] = { Ty, InputTy };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlsl_high");
- }
- }
-
- assert(Int && "Expected valid intrinsic number");
-
- // Determine the type(s) of this overloaded AArch64 intrinsic.
- Function *F = LookupNeonLLVMIntrinsic(Int, Modifier, Ty, E);
-
- Value *Result = EmitNeonCall(F, Ops, NameHint);
- llvm::Type *ResultType = ConvertType(E->getType());
- // AArch64 intrinsic one-element vector type cast to
- // scalar type expected by the builtin
- return Builder.CreateBitCast(Result, ResultType, NameHint);
-}
-
-Value *CodeGenFunction::EmitAArch64CompareBuiltinExpr(
- Value *Op, llvm::Type *Ty, const CmpInst::Predicate Fp,
- const CmpInst::Predicate Ip, const Twine &Name) {
- llvm::Type *OTy = Op->getType();
-
- // FIXME: this is utterly horrific. We should not be looking at previous
- // codegen context to find out what needs doing. Unfortunately TableGen
- // currently gives us exactly the same calls for vceqz_f32 and vceqz_s32
- // (etc).
- if (BitCastInst *BI = dyn_cast<BitCastInst>(Op))
- OTy = BI->getOperand(0)->getType();
-
- Op = Builder.CreateBitCast(Op, OTy);
- if (OTy->getScalarType()->isFloatingPointTy()) {
- Op = Builder.CreateFCmp(Fp, Op, Constant::getNullValue(OTy));
- } else {
- Op = Builder.CreateICmp(Ip, Op, Constant::getNullValue(OTy));
- }
- return Builder.CreateSExt(Op, Ty, Name);
-}
-
-static Value *packTBLDVectorList(CodeGenFunction &CGF, ArrayRef<Value *> Ops,
- Value *ExtOp, Value *IndexOp,
- llvm::Type *ResTy, unsigned IntID,
- const char *Name) {
- SmallVector<Value *, 2> TblOps;
- if (ExtOp)
- TblOps.push_back(ExtOp);
-
- // Build a vector containing sequential number like (0, 1, 2, ..., 15)
- SmallVector<uint32_t, 16> Indices;
- llvm::VectorType *TblTy = cast<llvm::VectorType>(Ops[0]->getType());
- for (unsigned i = 0, e = TblTy->getNumElements(); i != e; ++i) {
- Indices.push_back(2*i);
- Indices.push_back(2*i+1);
- }
-
- int PairPos = 0, End = Ops.size() - 1;
- while (PairPos < End) {
- TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
- Ops[PairPos+1], Indices,
- Name));
- PairPos += 2;
- }
-
- // If there's an odd number of 64-bit lookup table, fill the high 64-bit
- // of the 128-bit lookup table with zero.
- if (PairPos == End) {
- Value *ZeroTbl = ConstantAggregateZero::get(TblTy);
- TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
- ZeroTbl, Indices, Name));
- }
-
- Function *TblF;
- TblOps.push_back(IndexOp);
- TblF = CGF.CGM.getIntrinsic(IntID, ResTy);
-
- return CGF.EmitNeonCall(TblF, TblOps, Name);
-}
-
-Value *CodeGenFunction::GetValueForARMHint(unsigned BuiltinID) {
- unsigned Value;
- switch (BuiltinID) {
- default:
- return nullptr;
- case ARM::BI__builtin_arm_nop:
- Value = 0;
- break;
- case ARM::BI__builtin_arm_yield:
- case ARM::BI__yield:
- Value = 1;
- break;
- case ARM::BI__builtin_arm_wfe:
- case ARM::BI__wfe:
- Value = 2;
- break;
- case ARM::BI__builtin_arm_wfi:
- case ARM::BI__wfi:
- Value = 3;
- break;
- case ARM::BI__builtin_arm_sev:
- case ARM::BI__sev:
- Value = 4;
- break;
- case ARM::BI__builtin_arm_sevl:
- case ARM::BI__sevl:
- Value = 5;
- break;
- }
-
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_hint),
- llvm::ConstantInt::get(Int32Ty, Value));
-}
-
-// Generates the IR for the read/write special register builtin,
-// ValueType is the type of the value that is to be written or read,
-// RegisterType is the type of the register being written to or read from.
-static Value *EmitSpecialRegisterBuiltin(CodeGenFunction &CGF,
- const CallExpr *E,
- llvm::Type *RegisterType,
- llvm::Type *ValueType,
- bool IsRead,
- StringRef SysReg = "") {
- // write and register intrinsics only support 32 and 64 bit operations.
- assert((RegisterType->isIntegerTy(32) || RegisterType->isIntegerTy(64))
- && "Unsupported size for register.");
-
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
- CodeGen::CodeGenModule &CGM = CGF.CGM;
- LLVMContext &Context = CGM.getLLVMContext();
-
- if (SysReg.empty()) {
- const Expr *SysRegStrExpr = E->getArg(0)->IgnoreParenCasts();
- SysReg = cast<clang::StringLiteral>(SysRegStrExpr)->getString();
- }
-
- llvm::Metadata *Ops[] = { llvm::MDString::get(Context, SysReg) };
- llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
- llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
-
- llvm::Type *Types[] = { RegisterType };
-
- bool MixedTypes = RegisterType->isIntegerTy(64) && ValueType->isIntegerTy(32);
- assert(!(RegisterType->isIntegerTy(32) && ValueType->isIntegerTy(64))
- && "Can't fit 64-bit value in 32-bit register");
-
- if (IsRead) {
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
- llvm::Value *Call = Builder.CreateCall(F, Metadata);
-
- if (MixedTypes)
- // Read into 64 bit register and then truncate result to 32 bit.
- return Builder.CreateTrunc(Call, ValueType);
-
- if (ValueType->isPointerTy())
- // Have i32/i64 result (Call) but want to return a VoidPtrTy (i8*).
- return Builder.CreateIntToPtr(Call, ValueType);
-
- return Call;
- }
-
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
- llvm::Value *ArgValue = CGF.EmitScalarExpr(E->getArg(1));
- if (MixedTypes) {
- // Extend 32 bit write value to 64 bit to pass to write.
- ArgValue = Builder.CreateZExt(ArgValue, RegisterType);
- return Builder.CreateCall(F, { Metadata, ArgValue });
- }
-
- if (ValueType->isPointerTy()) {
- // Have VoidPtrTy ArgValue but want to return an i32/i64.
- ArgValue = Builder.CreatePtrToInt(ArgValue, RegisterType);
- return Builder.CreateCall(F, { Metadata, ArgValue });
- }
-
- return Builder.CreateCall(F, { Metadata, ArgValue });
-}
-
-/// Return true if BuiltinID is an overloaded Neon intrinsic with an extra
-/// argument that specifies the vector type.
-static bool HasExtraNeonArgument(unsigned BuiltinID) {
- switch (BuiltinID) {
- default: break;
- case NEON::BI__builtin_neon_vget_lane_i8:
- case NEON::BI__builtin_neon_vget_lane_i16:
- case NEON::BI__builtin_neon_vget_lane_i32:
- case NEON::BI__builtin_neon_vget_lane_i64:
- case NEON::BI__builtin_neon_vget_lane_f32:
- case NEON::BI__builtin_neon_vgetq_lane_i8:
- case NEON::BI__builtin_neon_vgetq_lane_i16:
- case NEON::BI__builtin_neon_vgetq_lane_i32:
- case NEON::BI__builtin_neon_vgetq_lane_i64:
- case NEON::BI__builtin_neon_vgetq_lane_f32:
- case NEON::BI__builtin_neon_vset_lane_i8:
- case NEON::BI__builtin_neon_vset_lane_i16:
- case NEON::BI__builtin_neon_vset_lane_i32:
- case NEON::BI__builtin_neon_vset_lane_i64:
- case NEON::BI__builtin_neon_vset_lane_f32:
- case NEON::BI__builtin_neon_vsetq_lane_i8:
- case NEON::BI__builtin_neon_vsetq_lane_i16:
- case NEON::BI__builtin_neon_vsetq_lane_i32:
- case NEON::BI__builtin_neon_vsetq_lane_i64:
- case NEON::BI__builtin_neon_vsetq_lane_f32:
- case NEON::BI__builtin_neon_vsha1h_u32:
- case NEON::BI__builtin_neon_vsha1cq_u32:
- case NEON::BI__builtin_neon_vsha1pq_u32:
- case NEON::BI__builtin_neon_vsha1mq_u32:
- case clang::ARM::BI_MoveToCoprocessor:
- case clang::ARM::BI_MoveToCoprocessor2:
- return false;
- }
- return true;
-}
-
-Value *CodeGenFunction::EmitISOVolatileLoad(const CallExpr *E) {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- QualType ElTy = E->getArg(0)->getType()->getPointeeType();
- CharUnits LoadSize = getContext().getTypeSizeInChars(ElTy);
- llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(),
- LoadSize.getQuantity() * 8);
- Ptr = Builder.CreateBitCast(Ptr, ITy->getPointerTo());
- llvm::LoadInst *Load =
- Builder.CreateAlignedLoad(Ptr, LoadSize);
- Load->setVolatile(true);
- return Load;
-}
-
-Value *CodeGenFunction::EmitISOVolatileStore(const CallExpr *E) {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- Value *Value = EmitScalarExpr(E->getArg(1));
- QualType ElTy = E->getArg(0)->getType()->getPointeeType();
- CharUnits StoreSize = getContext().getTypeSizeInChars(ElTy);
- llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(),
- StoreSize.getQuantity() * 8);
- Ptr = Builder.CreateBitCast(Ptr, ITy->getPointerTo());
- llvm::StoreInst *Store =
- Builder.CreateAlignedStore(Value, Ptr,
- StoreSize);
- Store->setVolatile(true);
- return Store;
-}
-
-Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E,
- llvm::Triple::ArchType Arch) {
- if (auto Hint = GetValueForARMHint(BuiltinID))
- return Hint;
-
- if (BuiltinID == ARM::BI__emit) {
- bool IsThumb = getTarget().getTriple().getArch() == llvm::Triple::thumb;
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, /*Variadic=*/false);
-
- Expr::EvalResult Result;
- if (!E->getArg(0)->EvaluateAsInt(Result, CGM.getContext()))
- llvm_unreachable("Sema will ensure that the parameter is constant");
-
- llvm::APSInt Value = Result.Val.getInt();
- uint64_t ZExtValue = Value.zextOrTrunc(IsThumb ? 16 : 32).getZExtValue();
-
- llvm::InlineAsm *Emit =
- IsThumb ? InlineAsm::get(FTy, ".inst.n 0x" + utohexstr(ZExtValue), "",
- /*SideEffects=*/true)
- : InlineAsm::get(FTy, ".inst 0x" + utohexstr(ZExtValue), "",
- /*SideEffects=*/true);
-
- return Builder.CreateCall(Emit);
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_dbg) {
- Value *Option = EmitScalarExpr(E->getArg(0));
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_dbg), Option);
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *RW = EmitScalarExpr(E->getArg(1));
- Value *IsData = EmitScalarExpr(E->getArg(2));
-
- // Locality is not supported on ARM target
- Value *Locality = llvm::ConstantInt::get(Int32Ty, 3);
-
- Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
- return Builder.CreateCall(F, {Address, RW, Locality, IsData});
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_rbit) {
- llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
- return Builder.CreateCall(
- CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit");
- }
-
- if (BuiltinID == ARM::BI__clear_cache) {
- assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments");
- const FunctionDecl *FD = E->getDirectCallee();
- Value *Ops[2];
- for (unsigned i = 0; i < 2; i++)
- Ops[i] = EmitScalarExpr(E->getArg(i));
- llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
- llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
- StringRef Name = FD->getName();
- return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_mcrr ||
- BuiltinID == ARM::BI__builtin_arm_mcrr2) {
- Function *F;
-
- switch (BuiltinID) {
- default: llvm_unreachable("unexpected builtin");
- case ARM::BI__builtin_arm_mcrr:
- F = CGM.getIntrinsic(Intrinsic::arm_mcrr);
- break;
- case ARM::BI__builtin_arm_mcrr2:
- F = CGM.getIntrinsic(Intrinsic::arm_mcrr2);
- break;
- }
-
- // MCRR{2} instruction has 5 operands but
- // the intrinsic has 4 because Rt and Rt2
- // are represented as a single unsigned 64
- // bit integer in the intrinsic definition
- // but internally it's represented as 2 32
- // bit integers.
-
- Value *Coproc = EmitScalarExpr(E->getArg(0));
- Value *Opc1 = EmitScalarExpr(E->getArg(1));
- Value *RtAndRt2 = EmitScalarExpr(E->getArg(2));
- Value *CRm = EmitScalarExpr(E->getArg(3));
-
- Value *C1 = llvm::ConstantInt::get(Int64Ty, 32);
- Value *Rt = Builder.CreateTruncOrBitCast(RtAndRt2, Int32Ty);
- Value *Rt2 = Builder.CreateLShr(RtAndRt2, C1);
- Rt2 = Builder.CreateTruncOrBitCast(Rt2, Int32Ty);
-
- return Builder.CreateCall(F, {Coproc, Opc1, Rt, Rt2, CRm});
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_mrrc ||
- BuiltinID == ARM::BI__builtin_arm_mrrc2) {
- Function *F;
-
- switch (BuiltinID) {
- default: llvm_unreachable("unexpected builtin");
- case ARM::BI__builtin_arm_mrrc:
- F = CGM.getIntrinsic(Intrinsic::arm_mrrc);
- break;
- case ARM::BI__builtin_arm_mrrc2:
- F = CGM.getIntrinsic(Intrinsic::arm_mrrc2);
- break;
- }
-
- Value *Coproc = EmitScalarExpr(E->getArg(0));
- Value *Opc1 = EmitScalarExpr(E->getArg(1));
- Value *CRm = EmitScalarExpr(E->getArg(2));
- Value *RtAndRt2 = Builder.CreateCall(F, {Coproc, Opc1, CRm});
-
- // Returns an unsigned 64 bit integer, represented
- // as two 32 bit integers.
-
- Value *Rt = Builder.CreateExtractValue(RtAndRt2, 1);
- Value *Rt1 = Builder.CreateExtractValue(RtAndRt2, 0);
- Rt = Builder.CreateZExt(Rt, Int64Ty);
- Rt1 = Builder.CreateZExt(Rt1, Int64Ty);
-
- Value *ShiftCast = llvm::ConstantInt::get(Int64Ty, 32);
- RtAndRt2 = Builder.CreateShl(Rt, ShiftCast, "shl", true);
- RtAndRt2 = Builder.CreateOr(RtAndRt2, Rt1);
-
- return Builder.CreateBitCast(RtAndRt2, ConvertType(E->getType()));
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_ldrexd ||
- ((BuiltinID == ARM::BI__builtin_arm_ldrex ||
- BuiltinID == ARM::BI__builtin_arm_ldaex) &&
- getContext().getTypeSize(E->getType()) == 64) ||
- BuiltinID == ARM::BI__ldrexd) {
- Function *F;
-
- switch (BuiltinID) {
- default: llvm_unreachable("unexpected builtin");
- case ARM::BI__builtin_arm_ldaex:
- F = CGM.getIntrinsic(Intrinsic::arm_ldaexd);
- break;
- case ARM::BI__builtin_arm_ldrexd:
- case ARM::BI__builtin_arm_ldrex:
- case ARM::BI__ldrexd:
- F = CGM.getIntrinsic(Intrinsic::arm_ldrexd);
- break;
- }
-
- Value *LdPtr = EmitScalarExpr(E->getArg(0));
- Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy),
- "ldrexd");
-
- Value *Val0 = Builder.CreateExtractValue(Val, 1);
- Value *Val1 = Builder.CreateExtractValue(Val, 0);
- Val0 = Builder.CreateZExt(Val0, Int64Ty);
- Val1 = Builder.CreateZExt(Val1, Int64Ty);
-
- Value *ShiftCst = llvm::ConstantInt::get(Int64Ty, 32);
- Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */);
- Val = Builder.CreateOr(Val, Val1);
- return Builder.CreateBitCast(Val, ConvertType(E->getType()));
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
- BuiltinID == ARM::BI__builtin_arm_ldaex) {
- Value *LoadAddr = EmitScalarExpr(E->getArg(0));
-
- QualType Ty = E->getType();
- llvm::Type *RealResTy = ConvertType(Ty);
- llvm::Type *PtrTy = llvm::IntegerType::get(
- getLLVMContext(), getContext().getTypeSize(Ty))->getPointerTo();
- LoadAddr = Builder.CreateBitCast(LoadAddr, PtrTy);
-
- Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_ldaex
- ? Intrinsic::arm_ldaex
- : Intrinsic::arm_ldrex,
- PtrTy);
- Value *Val = Builder.CreateCall(F, LoadAddr, "ldrex");
-
- if (RealResTy->isPointerTy())
- return Builder.CreateIntToPtr(Val, RealResTy);
- else {
- llvm::Type *IntResTy = llvm::IntegerType::get(
- getLLVMContext(), CGM.getDataLayout().getTypeSizeInBits(RealResTy));
- Val = Builder.CreateTruncOrBitCast(Val, IntResTy);
- return Builder.CreateBitCast(Val, RealResTy);
- }
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_strexd ||
- ((BuiltinID == ARM::BI__builtin_arm_stlex ||
- BuiltinID == ARM::BI__builtin_arm_strex) &&
- getContext().getTypeSize(E->getArg(0)->getType()) == 64)) {
- Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
- ? Intrinsic::arm_stlexd
- : Intrinsic::arm_strexd);
- llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty);
-
- Address Tmp = CreateMemTemp(E->getArg(0)->getType());
- Value *Val = EmitScalarExpr(E->getArg(0));
- Builder.CreateStore(Val, Tmp);
-
- Address LdPtr = Builder.CreateBitCast(Tmp,llvm::PointerType::getUnqual(STy));
- Val = Builder.CreateLoad(LdPtr);
-
- Value *Arg0 = Builder.CreateExtractValue(Val, 0);
- Value *Arg1 = Builder.CreateExtractValue(Val, 1);
- Value *StPtr = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), Int8PtrTy);
- return Builder.CreateCall(F, {Arg0, Arg1, StPtr}, "strexd");
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_strex ||
- BuiltinID == ARM::BI__builtin_arm_stlex) {
- Value *StoreVal = EmitScalarExpr(E->getArg(0));
- Value *StoreAddr = EmitScalarExpr(E->getArg(1));
-
- QualType Ty = E->getArg(0)->getType();
- llvm::Type *StoreTy = llvm::IntegerType::get(getLLVMContext(),
- getContext().getTypeSize(Ty));
- StoreAddr = Builder.CreateBitCast(StoreAddr, StoreTy->getPointerTo());
-
- if (StoreVal->getType()->isPointerTy())
- StoreVal = Builder.CreatePtrToInt(StoreVal, Int32Ty);
- else {
- llvm::Type *IntTy = llvm::IntegerType::get(
- getLLVMContext(),
- CGM.getDataLayout().getTypeSizeInBits(StoreVal->getType()));
- StoreVal = Builder.CreateBitCast(StoreVal, IntTy);
- StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int32Ty);
- }
-
- Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
- ? Intrinsic::arm_stlex
- : Intrinsic::arm_strex,
- StoreAddr->getType());
- return Builder.CreateCall(F, {StoreVal, StoreAddr}, "strex");
- }
-
- switch (BuiltinID) {
- case ARM::BI__iso_volatile_load8:
- case ARM::BI__iso_volatile_load16:
- case ARM::BI__iso_volatile_load32:
- case ARM::BI__iso_volatile_load64:
- return EmitISOVolatileLoad(E);
- case ARM::BI__iso_volatile_store8:
- case ARM::BI__iso_volatile_store16:
- case ARM::BI__iso_volatile_store32:
- case ARM::BI__iso_volatile_store64:
- return EmitISOVolatileStore(E);
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_clrex) {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_clrex);
- return Builder.CreateCall(F);
- }
-
- // CRC32
- Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic;
- switch (BuiltinID) {
- case ARM::BI__builtin_arm_crc32b:
- CRCIntrinsicID = Intrinsic::arm_crc32b; break;
- case ARM::BI__builtin_arm_crc32cb:
- CRCIntrinsicID = Intrinsic::arm_crc32cb; break;
- case ARM::BI__builtin_arm_crc32h:
- CRCIntrinsicID = Intrinsic::arm_crc32h; break;
- case ARM::BI__builtin_arm_crc32ch:
- CRCIntrinsicID = Intrinsic::arm_crc32ch; break;
- case ARM::BI__builtin_arm_crc32w:
- case ARM::BI__builtin_arm_crc32d:
- CRCIntrinsicID = Intrinsic::arm_crc32w; break;
- case ARM::BI__builtin_arm_crc32cw:
- case ARM::BI__builtin_arm_crc32cd:
- CRCIntrinsicID = Intrinsic::arm_crc32cw; break;
- }
-
- if (CRCIntrinsicID != Intrinsic::not_intrinsic) {
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- Value *Arg1 = EmitScalarExpr(E->getArg(1));
-
- // crc32{c,}d intrinsics are implemnted as two calls to crc32{c,}w
- // intrinsics, hence we need different codegen for these cases.
- if (BuiltinID == ARM::BI__builtin_arm_crc32d ||
- BuiltinID == ARM::BI__builtin_arm_crc32cd) {
- Value *C1 = llvm::ConstantInt::get(Int64Ty, 32);
- Value *Arg1a = Builder.CreateTruncOrBitCast(Arg1, Int32Ty);
- Value *Arg1b = Builder.CreateLShr(Arg1, C1);
- Arg1b = Builder.CreateTruncOrBitCast(Arg1b, Int32Ty);
-
- Function *F = CGM.getIntrinsic(CRCIntrinsicID);
- Value *Res = Builder.CreateCall(F, {Arg0, Arg1a});
- return Builder.CreateCall(F, {Res, Arg1b});
- } else {
- Arg1 = Builder.CreateZExtOrBitCast(Arg1, Int32Ty);
-
- Function *F = CGM.getIntrinsic(CRCIntrinsicID);
- return Builder.CreateCall(F, {Arg0, Arg1});
- }
- }
-
- if (BuiltinID == ARM::BI__builtin_arm_rsr ||
- BuiltinID == ARM::BI__builtin_arm_rsr64 ||
- BuiltinID == ARM::BI__builtin_arm_rsrp ||
- BuiltinID == ARM::BI__builtin_arm_wsr ||
- BuiltinID == ARM::BI__builtin_arm_wsr64 ||
- BuiltinID == ARM::BI__builtin_arm_wsrp) {
-
- bool IsRead = BuiltinID == ARM::BI__builtin_arm_rsr ||
- BuiltinID == ARM::BI__builtin_arm_rsr64 ||
- BuiltinID == ARM::BI__builtin_arm_rsrp;
-
- bool IsPointerBuiltin = BuiltinID == ARM::BI__builtin_arm_rsrp ||
- BuiltinID == ARM::BI__builtin_arm_wsrp;
-
- bool Is64Bit = BuiltinID == ARM::BI__builtin_arm_rsr64 ||
- BuiltinID == ARM::BI__builtin_arm_wsr64;
-
- llvm::Type *ValueType;
- llvm::Type *RegisterType;
- if (IsPointerBuiltin) {
- ValueType = VoidPtrTy;
- RegisterType = Int32Ty;
- } else if (Is64Bit) {
- ValueType = RegisterType = Int64Ty;
- } else {
- ValueType = RegisterType = Int32Ty;
- }
-
- return EmitSpecialRegisterBuiltin(*this, E, RegisterType, ValueType, IsRead);
- }
-
- // Find out if any arguments are required to be integer constant
- // expressions.
- unsigned ICEArguments = 0;
- ASTContext::GetBuiltinTypeError Error;
- getContext().GetBuiltinType(BuiltinID, Error, &ICEArguments);
- assert(Error == ASTContext::GE_None && "Should not codegen an error");
-
- auto getAlignmentValue32 = [&](Address addr) -> Value* {
- return Builder.getInt32(addr.getAlignment().getQuantity());
- };
-
- Address PtrOp0 = Address::invalid();
- Address PtrOp1 = Address::invalid();
- SmallVector<Value*, 4> Ops;
- bool HasExtraArg = HasExtraNeonArgument(BuiltinID);
- unsigned NumArgs = E->getNumArgs() - (HasExtraArg ? 1 : 0);
- for (unsigned i = 0, e = NumArgs; i != e; i++) {
- if (i == 0) {
- switch (BuiltinID) {
- case NEON::BI__builtin_neon_vld1_v:
- case NEON::BI__builtin_neon_vld1q_v:
- case NEON::BI__builtin_neon_vld1q_lane_v:
- case NEON::BI__builtin_neon_vld1_lane_v:
- case NEON::BI__builtin_neon_vld1_dup_v:
- case NEON::BI__builtin_neon_vld1q_dup_v:
- case NEON::BI__builtin_neon_vst1_v:
- case NEON::BI__builtin_neon_vst1q_v:
- case NEON::BI__builtin_neon_vst1q_lane_v:
- case NEON::BI__builtin_neon_vst1_lane_v:
- case NEON::BI__builtin_neon_vst2_v:
- case NEON::BI__builtin_neon_vst2q_v:
- case NEON::BI__builtin_neon_vst2_lane_v:
- case NEON::BI__builtin_neon_vst2q_lane_v:
- case NEON::BI__builtin_neon_vst3_v:
- case NEON::BI__builtin_neon_vst3q_v:
- case NEON::BI__builtin_neon_vst3_lane_v:
- case NEON::BI__builtin_neon_vst3q_lane_v:
- case NEON::BI__builtin_neon_vst4_v:
- case NEON::BI__builtin_neon_vst4q_v:
- case NEON::BI__builtin_neon_vst4_lane_v:
- case NEON::BI__builtin_neon_vst4q_lane_v:
- // Get the alignment for the argument in addition to the value;
- // we'll use it later.
- PtrOp0 = EmitPointerWithAlignment(E->getArg(0));
- Ops.push_back(PtrOp0.getPointer());
- continue;
- }
- }
- if (i == 1) {
- switch (BuiltinID) {
- case NEON::BI__builtin_neon_vld2_v:
- case NEON::BI__builtin_neon_vld2q_v:
- case NEON::BI__builtin_neon_vld3_v:
- case NEON::BI__builtin_neon_vld3q_v:
- case NEON::BI__builtin_neon_vld4_v:
- case NEON::BI__builtin_neon_vld4q_v:
- case NEON::BI__builtin_neon_vld2_lane_v:
- case NEON::BI__builtin_neon_vld2q_lane_v:
- case NEON::BI__builtin_neon_vld3_lane_v:
- case NEON::BI__builtin_neon_vld3q_lane_v:
- case NEON::BI__builtin_neon_vld4_lane_v:
- case NEON::BI__builtin_neon_vld4q_lane_v:
- case NEON::BI__builtin_neon_vld2_dup_v:
- case NEON::BI__builtin_neon_vld2q_dup_v:
- case NEON::BI__builtin_neon_vld3_dup_v:
- case NEON::BI__builtin_neon_vld3q_dup_v:
- case NEON::BI__builtin_neon_vld4_dup_v:
- case NEON::BI__builtin_neon_vld4q_dup_v:
- // Get the alignment for the argument in addition to the value;
- // we'll use it later.
- PtrOp1 = EmitPointerWithAlignment(E->getArg(1));
- Ops.push_back(PtrOp1.getPointer());
- continue;
- }
- }
-
- if ((ICEArguments & (1 << i)) == 0) {
- Ops.push_back(EmitScalarExpr(E->getArg(i)));
- } else {
- // If this is required to be a constant, constant fold it so that we know
- // that the generated intrinsic gets a ConstantInt.
- llvm::APSInt Result;
- bool IsConst = E->getArg(i)->isIntegerConstantExpr(Result, getContext());
- assert(IsConst && "Constant arg isn't actually constant?"); (void)IsConst;
- Ops.push_back(llvm::ConstantInt::get(getLLVMContext(), Result));
- }
- }
-
- switch (BuiltinID) {
- default: break;
-
- case NEON::BI__builtin_neon_vget_lane_i8:
- case NEON::BI__builtin_neon_vget_lane_i16:
- case NEON::BI__builtin_neon_vget_lane_i32:
- case NEON::BI__builtin_neon_vget_lane_i64:
- case NEON::BI__builtin_neon_vget_lane_f32:
- case NEON::BI__builtin_neon_vgetq_lane_i8:
- case NEON::BI__builtin_neon_vgetq_lane_i16:
- case NEON::BI__builtin_neon_vgetq_lane_i32:
- case NEON::BI__builtin_neon_vgetq_lane_i64:
- case NEON::BI__builtin_neon_vgetq_lane_f32:
- return Builder.CreateExtractElement(Ops[0], Ops[1], "vget_lane");
-
- case NEON::BI__builtin_neon_vrndns_f32: {
- Value *Arg = EmitScalarExpr(E->getArg(0));
- llvm::Type *Tys[] = {Arg->getType()};
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vrintn, Tys);
- return Builder.CreateCall(F, {Arg}, "vrndn"); }
-
- case NEON::BI__builtin_neon_vset_lane_i8:
- case NEON::BI__builtin_neon_vset_lane_i16:
- case NEON::BI__builtin_neon_vset_lane_i32:
- case NEON::BI__builtin_neon_vset_lane_i64:
- case NEON::BI__builtin_neon_vset_lane_f32:
- case NEON::BI__builtin_neon_vsetq_lane_i8:
- case NEON::BI__builtin_neon_vsetq_lane_i16:
- case NEON::BI__builtin_neon_vsetq_lane_i32:
- case NEON::BI__builtin_neon_vsetq_lane_i64:
- case NEON::BI__builtin_neon_vsetq_lane_f32:
- return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
-
- case NEON::BI__builtin_neon_vsha1h_u32:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1h), Ops,
- "vsha1h");
- case NEON::BI__builtin_neon_vsha1cq_u32:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1c), Ops,
- "vsha1h");
- case NEON::BI__builtin_neon_vsha1pq_u32:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1p), Ops,
- "vsha1h");
- case NEON::BI__builtin_neon_vsha1mq_u32:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1m), Ops,
- "vsha1h");
-
- // The ARM _MoveToCoprocessor builtins put the input register value as
- // the first argument, but the LLVM intrinsic expects it as the third one.
- case ARM::BI_MoveToCoprocessor:
- case ARM::BI_MoveToCoprocessor2: {
- Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI_MoveToCoprocessor ?
- Intrinsic::arm_mcr : Intrinsic::arm_mcr2);
- return Builder.CreateCall(F, {Ops[1], Ops[2], Ops[0],
- Ops[3], Ops[4], Ops[5]});
- }
- case ARM::BI_BitScanForward:
- case ARM::BI_BitScanForward64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E);
- case ARM::BI_BitScanReverse:
- case ARM::BI_BitScanReverse64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E);
-
- case ARM::BI_InterlockedAnd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E);
- case ARM::BI_InterlockedExchange64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E);
- case ARM::BI_InterlockedExchangeAdd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E);
- case ARM::BI_InterlockedExchangeSub64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E);
- case ARM::BI_InterlockedOr64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E);
- case ARM::BI_InterlockedXor64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E);
- case ARM::BI_InterlockedDecrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E);
- case ARM::BI_InterlockedIncrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E);
- case ARM::BI_InterlockedExchangeAdd8_acq:
- case ARM::BI_InterlockedExchangeAdd16_acq:
- case ARM::BI_InterlockedExchangeAdd_acq:
- case ARM::BI_InterlockedExchangeAdd64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_acq, E);
- case ARM::BI_InterlockedExchangeAdd8_rel:
- case ARM::BI_InterlockedExchangeAdd16_rel:
- case ARM::BI_InterlockedExchangeAdd_rel:
- case ARM::BI_InterlockedExchangeAdd64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_rel, E);
- case ARM::BI_InterlockedExchangeAdd8_nf:
- case ARM::BI_InterlockedExchangeAdd16_nf:
- case ARM::BI_InterlockedExchangeAdd_nf:
- case ARM::BI_InterlockedExchangeAdd64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_nf, E);
- case ARM::BI_InterlockedExchange8_acq:
- case ARM::BI_InterlockedExchange16_acq:
- case ARM::BI_InterlockedExchange_acq:
- case ARM::BI_InterlockedExchange64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_acq, E);
- case ARM::BI_InterlockedExchange8_rel:
- case ARM::BI_InterlockedExchange16_rel:
- case ARM::BI_InterlockedExchange_rel:
- case ARM::BI_InterlockedExchange64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_rel, E);
- case ARM::BI_InterlockedExchange8_nf:
- case ARM::BI_InterlockedExchange16_nf:
- case ARM::BI_InterlockedExchange_nf:
- case ARM::BI_InterlockedExchange64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_nf, E);
- case ARM::BI_InterlockedCompareExchange8_acq:
- case ARM::BI_InterlockedCompareExchange16_acq:
- case ARM::BI_InterlockedCompareExchange_acq:
- case ARM::BI_InterlockedCompareExchange64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_acq, E);
- case ARM::BI_InterlockedCompareExchange8_rel:
- case ARM::BI_InterlockedCompareExchange16_rel:
- case ARM::BI_InterlockedCompareExchange_rel:
- case ARM::BI_InterlockedCompareExchange64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_rel, E);
- case ARM::BI_InterlockedCompareExchange8_nf:
- case ARM::BI_InterlockedCompareExchange16_nf:
- case ARM::BI_InterlockedCompareExchange_nf:
- case ARM::BI_InterlockedCompareExchange64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_nf, E);
- case ARM::BI_InterlockedOr8_acq:
- case ARM::BI_InterlockedOr16_acq:
- case ARM::BI_InterlockedOr_acq:
- case ARM::BI_InterlockedOr64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_acq, E);
- case ARM::BI_InterlockedOr8_rel:
- case ARM::BI_InterlockedOr16_rel:
- case ARM::BI_InterlockedOr_rel:
- case ARM::BI_InterlockedOr64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_rel, E);
- case ARM::BI_InterlockedOr8_nf:
- case ARM::BI_InterlockedOr16_nf:
- case ARM::BI_InterlockedOr_nf:
- case ARM::BI_InterlockedOr64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_nf, E);
- case ARM::BI_InterlockedXor8_acq:
- case ARM::BI_InterlockedXor16_acq:
- case ARM::BI_InterlockedXor_acq:
- case ARM::BI_InterlockedXor64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_acq, E);
- case ARM::BI_InterlockedXor8_rel:
- case ARM::BI_InterlockedXor16_rel:
- case ARM::BI_InterlockedXor_rel:
- case ARM::BI_InterlockedXor64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_rel, E);
- case ARM::BI_InterlockedXor8_nf:
- case ARM::BI_InterlockedXor16_nf:
- case ARM::BI_InterlockedXor_nf:
- case ARM::BI_InterlockedXor64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_nf, E);
- case ARM::BI_InterlockedAnd8_acq:
- case ARM::BI_InterlockedAnd16_acq:
- case ARM::BI_InterlockedAnd_acq:
- case ARM::BI_InterlockedAnd64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_acq, E);
- case ARM::BI_InterlockedAnd8_rel:
- case ARM::BI_InterlockedAnd16_rel:
- case ARM::BI_InterlockedAnd_rel:
- case ARM::BI_InterlockedAnd64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_rel, E);
- case ARM::BI_InterlockedAnd8_nf:
- case ARM::BI_InterlockedAnd16_nf:
- case ARM::BI_InterlockedAnd_nf:
- case ARM::BI_InterlockedAnd64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_nf, E);
- case ARM::BI_InterlockedIncrement16_acq:
- case ARM::BI_InterlockedIncrement_acq:
- case ARM::BI_InterlockedIncrement64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_acq, E);
- case ARM::BI_InterlockedIncrement16_rel:
- case ARM::BI_InterlockedIncrement_rel:
- case ARM::BI_InterlockedIncrement64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_rel, E);
- case ARM::BI_InterlockedIncrement16_nf:
- case ARM::BI_InterlockedIncrement_nf:
- case ARM::BI_InterlockedIncrement64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_nf, E);
- case ARM::BI_InterlockedDecrement16_acq:
- case ARM::BI_InterlockedDecrement_acq:
- case ARM::BI_InterlockedDecrement64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_acq, E);
- case ARM::BI_InterlockedDecrement16_rel:
- case ARM::BI_InterlockedDecrement_rel:
- case ARM::BI_InterlockedDecrement64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_rel, E);
- case ARM::BI_InterlockedDecrement16_nf:
- case ARM::BI_InterlockedDecrement_nf:
- case ARM::BI_InterlockedDecrement64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_nf, E);
- }
-
- // Get the last argument, which specifies the vector type.
- assert(HasExtraArg);
- llvm::APSInt Result;
- const Expr *Arg = E->getArg(E->getNumArgs()-1);
- if (!Arg->isIntegerConstantExpr(Result, getContext()))
- return nullptr;
-
- if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f ||
- BuiltinID == ARM::BI__builtin_arm_vcvtr_d) {
- // Determine the overloaded type of this builtin.
- llvm::Type *Ty;
- if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f)
- Ty = FloatTy;
- else
- Ty = DoubleTy;
-
- // Determine whether this is an unsigned conversion or not.
- bool usgn = Result.getZExtValue() == 1;
- unsigned Int = usgn ? Intrinsic::arm_vcvtru : Intrinsic::arm_vcvtr;
-
- // Call the appropriate intrinsic.
- Function *F = CGM.getIntrinsic(Int, Ty);
- return Builder.CreateCall(F, Ops, "vcvtr");
- }
-
- // Determine the type of this overloaded NEON intrinsic.
- NeonTypeFlags Type(Result.getZExtValue());
- bool usgn = Type.isUnsigned();
- bool rightShift = false;
-
- llvm::VectorType *VTy = GetNeonType(this, Type,
- getTarget().hasLegalHalfType());
- llvm::Type *Ty = VTy;
- if (!Ty)
- return nullptr;
-
- // Many NEON builtins have identical semantics and uses in ARM and
- // AArch64. Emit these in a single function.
- auto IntrinsicMap = makeArrayRef(ARMSIMDIntrinsicMap);
- const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
- IntrinsicMap, BuiltinID, NEONSIMDIntrinsicsProvenSorted);
- if (Builtin)
- return EmitCommonNeonBuiltinExpr(
- Builtin->BuiltinID, Builtin->LLVMIntrinsic, Builtin->AltLLVMIntrinsic,
- Builtin->NameHint, Builtin->TypeModifier, E, Ops, PtrOp0, PtrOp1, Arch);
-
- unsigned Int;
- switch (BuiltinID) {
- default: return nullptr;
- case NEON::BI__builtin_neon_vld1q_lane_v:
- // Handle 64-bit integer elements as a special case. Use shuffles of
- // one-element vectors to avoid poor code for i64 in the backend.
- if (VTy->getElementType()->isIntegerTy(64)) {
- // Extract the other lane.
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- uint32_t Lane = cast<ConstantInt>(Ops[2])->getZExtValue();
- Value *SV = llvm::ConstantVector::get(ConstantInt::get(Int32Ty, 1-Lane));
- Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV);
- // Load the value as a one-element vector.
- Ty = llvm::VectorType::get(VTy->getElementType(), 1);
- llvm::Type *Tys[] = {Ty, Int8PtrTy};
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Tys);
- Value *Align = getAlignmentValue32(PtrOp0);
- Value *Ld = Builder.CreateCall(F, {Ops[0], Align});
- // Combine them.
- uint32_t Indices[] = {1 - Lane, Lane};
- SV = llvm::ConstantDataVector::get(getLLVMContext(), Indices);
- return Builder.CreateShuffleVector(Ops[1], Ld, SV, "vld1q_lane");
- }
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vld1_lane_v: {
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- PtrOp0 = Builder.CreateElementBitCast(PtrOp0, VTy->getElementType());
- Value *Ld = Builder.CreateLoad(PtrOp0);
- return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane");
- }
- case NEON::BI__builtin_neon_vqrshrn_n_v:
- Int =
- usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n",
- 1, true);
- case NEON::BI__builtin_neon_vqrshrun_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqrshiftnsu, Ty),
- Ops, "vqrshrun_n", 1, true);
- case NEON::BI__builtin_neon_vqshrn_n_v:
- Int = usgn ? Intrinsic::arm_neon_vqshiftnu : Intrinsic::arm_neon_vqshiftns;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n",
- 1, true);
- case NEON::BI__builtin_neon_vqshrun_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqshiftnsu, Ty),
- Ops, "vqshrun_n", 1, true);
- case NEON::BI__builtin_neon_vrecpe_v:
- case NEON::BI__builtin_neon_vrecpeq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrecpe, Ty),
- Ops, "vrecpe");
- case NEON::BI__builtin_neon_vrshrn_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrshiftn, Ty),
- Ops, "vrshrn_n", 1, true);
- case NEON::BI__builtin_neon_vrsra_n_v:
- case NEON::BI__builtin_neon_vrsraq_n_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = EmitNeonShiftVector(Ops[2], Ty, true);
- Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
- Ops[1] = Builder.CreateCall(CGM.getIntrinsic(Int, Ty), {Ops[1], Ops[2]});
- return Builder.CreateAdd(Ops[0], Ops[1], "vrsra_n");
- case NEON::BI__builtin_neon_vsri_n_v:
- case NEON::BI__builtin_neon_vsriq_n_v:
- rightShift = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vsli_n_v:
- case NEON::BI__builtin_neon_vsliq_n_v:
- Ops[2] = EmitNeonShiftVector(Ops[2], Ty, rightShift);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftins, Ty),
- Ops, "vsli_n");
- case NEON::BI__builtin_neon_vsra_n_v:
- case NEON::BI__builtin_neon_vsraq_n_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = EmitNeonRShiftImm(Ops[1], Ops[2], Ty, usgn, "vsra_n");
- return Builder.CreateAdd(Ops[0], Ops[1]);
- case NEON::BI__builtin_neon_vst1q_lane_v:
- // Handle 64-bit integer elements as a special case. Use a shuffle to get
- // a one-element vector and avoid poor code for i64 in the backend.
- if (VTy->getElementType()->isIntegerTy(64)) {
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Value *SV = llvm::ConstantVector::get(cast<llvm::Constant>(Ops[2]));
- Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV);
- Ops[2] = getAlignmentValue32(PtrOp0);
- llvm::Type *Tys[] = {Int8PtrTy, Ops[1]->getType()};
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1,
- Tys), Ops);
- }
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vst1_lane_v: {
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- auto St = Builder.CreateStore(Ops[1], Builder.CreateBitCast(PtrOp0, Ty));
- return St;
- }
- case NEON::BI__builtin_neon_vtbl1_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl1),
- Ops, "vtbl1");
- case NEON::BI__builtin_neon_vtbl2_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl2),
- Ops, "vtbl2");
- case NEON::BI__builtin_neon_vtbl3_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl3),
- Ops, "vtbl3");
- case NEON::BI__builtin_neon_vtbl4_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl4),
- Ops, "vtbl4");
- case NEON::BI__builtin_neon_vtbx1_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx1),
- Ops, "vtbx1");
- case NEON::BI__builtin_neon_vtbx2_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx2),
- Ops, "vtbx2");
- case NEON::BI__builtin_neon_vtbx3_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx3),
- Ops, "vtbx3");
- case NEON::BI__builtin_neon_vtbx4_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx4),
- Ops, "vtbx4");
- }
-}
-
-static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
- const CallExpr *E,
- SmallVectorImpl<Value *> &Ops,
- llvm::Triple::ArchType Arch) {
- unsigned int Int = 0;
- const char *s = nullptr;
-
- switch (BuiltinID) {
- default:
- return nullptr;
- case NEON::BI__builtin_neon_vtbl1_v:
- case NEON::BI__builtin_neon_vqtbl1_v:
- case NEON::BI__builtin_neon_vqtbl1q_v:
- case NEON::BI__builtin_neon_vtbl2_v:
- case NEON::BI__builtin_neon_vqtbl2_v:
- case NEON::BI__builtin_neon_vqtbl2q_v:
- case NEON::BI__builtin_neon_vtbl3_v:
- case NEON::BI__builtin_neon_vqtbl3_v:
- case NEON::BI__builtin_neon_vqtbl3q_v:
- case NEON::BI__builtin_neon_vtbl4_v:
- case NEON::BI__builtin_neon_vqtbl4_v:
- case NEON::BI__builtin_neon_vqtbl4q_v:
- break;
- case NEON::BI__builtin_neon_vtbx1_v:
- case NEON::BI__builtin_neon_vqtbx1_v:
- case NEON::BI__builtin_neon_vqtbx1q_v:
- case NEON::BI__builtin_neon_vtbx2_v:
- case NEON::BI__builtin_neon_vqtbx2_v:
- case NEON::BI__builtin_neon_vqtbx2q_v:
- case NEON::BI__builtin_neon_vtbx3_v:
- case NEON::BI__builtin_neon_vqtbx3_v:
- case NEON::BI__builtin_neon_vqtbx3q_v:
- case NEON::BI__builtin_neon_vtbx4_v:
- case NEON::BI__builtin_neon_vqtbx4_v:
- case NEON::BI__builtin_neon_vqtbx4q_v:
- break;
- }
-
- assert(E->getNumArgs() >= 3);
-
- // Get the last argument, which specifies the vector type.
- llvm::APSInt Result;
- const Expr *Arg = E->getArg(E->getNumArgs() - 1);
- if (!Arg->isIntegerConstantExpr(Result, CGF.getContext()))
- return nullptr;
-
- // Determine the type of this overloaded NEON intrinsic.
- NeonTypeFlags Type(Result.getZExtValue());
- llvm::VectorType *Ty = GetNeonType(&CGF, Type);
- if (!Ty)
- return nullptr;
-
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
-
- // AArch64 scalar builtins are not overloaded, they do not have an extra
- // argument that specifies the vector type, need to handle each case.
- switch (BuiltinID) {
- case NEON::BI__builtin_neon_vtbl1_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 1), nullptr,
- Ops[1], Ty, Intrinsic::aarch64_neon_tbl1,
- "vtbl1");
- }
- case NEON::BI__builtin_neon_vtbl2_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 2), nullptr,
- Ops[2], Ty, Intrinsic::aarch64_neon_tbl1,
- "vtbl1");
- }
- case NEON::BI__builtin_neon_vtbl3_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 3), nullptr,
- Ops[3], Ty, Intrinsic::aarch64_neon_tbl2,
- "vtbl2");
- }
- case NEON::BI__builtin_neon_vtbl4_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 4), nullptr,
- Ops[4], Ty, Intrinsic::aarch64_neon_tbl2,
- "vtbl2");
- }
- case NEON::BI__builtin_neon_vtbx1_v: {
- Value *TblRes =
- packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 1), nullptr, Ops[2],
- Ty, Intrinsic::aarch64_neon_tbl1, "vtbl1");
-
- llvm::Constant *EightV = ConstantInt::get(Ty, 8);
- Value *CmpRes = Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[2], EightV);
- CmpRes = Builder.CreateSExt(CmpRes, Ty);
-
- Value *EltsFromInput = Builder.CreateAnd(CmpRes, Ops[0]);
- Value *EltsFromTbl = Builder.CreateAnd(Builder.CreateNot(CmpRes), TblRes);
- return Builder.CreateOr(EltsFromInput, EltsFromTbl, "vtbx");
- }
- case NEON::BI__builtin_neon_vtbx2_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 2), Ops[0],
- Ops[3], Ty, Intrinsic::aarch64_neon_tbx1,
- "vtbx1");
- }
- case NEON::BI__builtin_neon_vtbx3_v: {
- Value *TblRes =
- packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 3), nullptr, Ops[4],
- Ty, Intrinsic::aarch64_neon_tbl2, "vtbl2");
-
- llvm::Constant *TwentyFourV = ConstantInt::get(Ty, 24);
- Value *CmpRes = Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[4],
- TwentyFourV);
- CmpRes = Builder.CreateSExt(CmpRes, Ty);
-
- Value *EltsFromInput = Builder.CreateAnd(CmpRes, Ops[0]);
- Value *EltsFromTbl = Builder.CreateAnd(Builder.CreateNot(CmpRes), TblRes);
- return Builder.CreateOr(EltsFromInput, EltsFromTbl, "vtbx");
- }
- case NEON::BI__builtin_neon_vtbx4_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 4), Ops[0],
- Ops[5], Ty, Intrinsic::aarch64_neon_tbx2,
- "vtbx2");
- }
- case NEON::BI__builtin_neon_vqtbl1_v:
- case NEON::BI__builtin_neon_vqtbl1q_v:
- Int = Intrinsic::aarch64_neon_tbl1; s = "vtbl1"; break;
- case NEON::BI__builtin_neon_vqtbl2_v:
- case NEON::BI__builtin_neon_vqtbl2q_v: {
- Int = Intrinsic::aarch64_neon_tbl2; s = "vtbl2"; break;
- case NEON::BI__builtin_neon_vqtbl3_v:
- case NEON::BI__builtin_neon_vqtbl3q_v:
- Int = Intrinsic::aarch64_neon_tbl3; s = "vtbl3"; break;
- case NEON::BI__builtin_neon_vqtbl4_v:
- case NEON::BI__builtin_neon_vqtbl4q_v:
- Int = Intrinsic::aarch64_neon_tbl4; s = "vtbl4"; break;
- case NEON::BI__builtin_neon_vqtbx1_v:
- case NEON::BI__builtin_neon_vqtbx1q_v:
- Int = Intrinsic::aarch64_neon_tbx1; s = "vtbx1"; break;
- case NEON::BI__builtin_neon_vqtbx2_v:
- case NEON::BI__builtin_neon_vqtbx2q_v:
- Int = Intrinsic::aarch64_neon_tbx2; s = "vtbx2"; break;
- case NEON::BI__builtin_neon_vqtbx3_v:
- case NEON::BI__builtin_neon_vqtbx3q_v:
- Int = Intrinsic::aarch64_neon_tbx3; s = "vtbx3"; break;
- case NEON::BI__builtin_neon_vqtbx4_v:
- case NEON::BI__builtin_neon_vqtbx4q_v:
- Int = Intrinsic::aarch64_neon_tbx4; s = "vtbx4"; break;
- }
- }
-
- if (!Int)
- return nullptr;
-
- Function *F = CGF.CGM.getIntrinsic(Int, Ty);
- return CGF.EmitNeonCall(F, Ops, s);
-}
-
-Value *CodeGenFunction::vectorWrapScalar16(Value *Op) {
- llvm::Type *VTy = llvm::VectorType::get(Int16Ty, 4);
- Op = Builder.CreateBitCast(Op, Int16Ty);
- Value *V = UndefValue::get(VTy);
- llvm::Constant *CI = ConstantInt::get(SizeTy, 0);
- Op = Builder.CreateInsertElement(V, Op, CI);
- return Op;
-}
-
-Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
- const CallExpr *E,
- llvm::Triple::ArchType Arch) {
- unsigned HintID = static_cast<unsigned>(-1);
- switch (BuiltinID) {
- default: break;
- case AArch64::BI__builtin_arm_nop:
- HintID = 0;
- break;
- case AArch64::BI__builtin_arm_yield:
- case AArch64::BI__yield:
- HintID = 1;
- break;
- case AArch64::BI__builtin_arm_wfe:
- case AArch64::BI__wfe:
- HintID = 2;
- break;
- case AArch64::BI__builtin_arm_wfi:
- case AArch64::BI__wfi:
- HintID = 3;
- break;
- case AArch64::BI__builtin_arm_sev:
- case AArch64::BI__sev:
- HintID = 4;
- break;
- case AArch64::BI__builtin_arm_sevl:
- case AArch64::BI__sevl:
- HintID = 5;
- break;
- }
-
- if (HintID != static_cast<unsigned>(-1)) {
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_hint);
- return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
- }
-
- if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *RW = EmitScalarExpr(E->getArg(1));
- Value *CacheLevel = EmitScalarExpr(E->getArg(2));
- Value *RetentionPolicy = EmitScalarExpr(E->getArg(3));
- Value *IsData = EmitScalarExpr(E->getArg(4));
-
- Value *Locality = nullptr;
- if (cast<llvm::ConstantInt>(RetentionPolicy)->isZero()) {
- // Temporal fetch, needs to convert cache level to locality.
- Locality = llvm::ConstantInt::get(Int32Ty,
- -cast<llvm::ConstantInt>(CacheLevel)->getValue() + 3);
- } else {
- // Streaming fetch.
- Locality = llvm::ConstantInt::get(Int32Ty, 0);
- }
-
- // FIXME: We need AArch64 specific LLVM intrinsic if we want to specify
- // PLDL3STRM or PLDL2STRM.
- Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
- return Builder.CreateCall(F, {Address, RW, Locality, IsData});
- }
-
- if (BuiltinID == AArch64::BI__builtin_arm_rbit) {
- assert((getContext().getTypeSize(E->getType()) == 32) &&
- "rbit of unusual size!");
- llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
- return Builder.CreateCall(
- CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit");
- }
- if (BuiltinID == AArch64::BI__builtin_arm_rbit64) {
- assert((getContext().getTypeSize(E->getType()) == 64) &&
- "rbit of unusual size!");
- llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
- return Builder.CreateCall(
- CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit");
- }
-
- if (BuiltinID == AArch64::BI__clear_cache) {
- assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments");
- const FunctionDecl *FD = E->getDirectCallee();
- Value *Ops[2];
- for (unsigned i = 0; i < 2; i++)
- Ops[i] = EmitScalarExpr(E->getArg(i));
- llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
- llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
- StringRef Name = FD->getName();
- return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
- }
-
- if ((BuiltinID == AArch64::BI__builtin_arm_ldrex ||
- BuiltinID == AArch64::BI__builtin_arm_ldaex) &&
- getContext().getTypeSize(E->getType()) == 128) {
- Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex
- ? Intrinsic::aarch64_ldaxp
- : Intrinsic::aarch64_ldxp);
-
- Value *LdPtr = EmitScalarExpr(E->getArg(0));
- Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy),
- "ldxp");
-
- Value *Val0 = Builder.CreateExtractValue(Val, 1);
- Value *Val1 = Builder.CreateExtractValue(Val, 0);
- llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128);
- Val0 = Builder.CreateZExt(Val0, Int128Ty);
- Val1 = Builder.CreateZExt(Val1, Int128Ty);
-
- Value *ShiftCst = llvm::ConstantInt::get(Int128Ty, 64);
- Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */);
- Val = Builder.CreateOr(Val, Val1);
- return Builder.CreateBitCast(Val, ConvertType(E->getType()));
- } else if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
- BuiltinID == AArch64::BI__builtin_arm_ldaex) {
- Value *LoadAddr = EmitScalarExpr(E->getArg(0));
-
- QualType Ty = E->getType();
- llvm::Type *RealResTy = ConvertType(Ty);
- llvm::Type *PtrTy = llvm::IntegerType::get(
- getLLVMContext(), getContext().getTypeSize(Ty))->getPointerTo();
- LoadAddr = Builder.CreateBitCast(LoadAddr, PtrTy);
-
- Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex
- ? Intrinsic::aarch64_ldaxr
- : Intrinsic::aarch64_ldxr,
- PtrTy);
- Value *Val = Builder.CreateCall(F, LoadAddr, "ldxr");
-
- if (RealResTy->isPointerTy())
- return Builder.CreateIntToPtr(Val, RealResTy);
-
- llvm::Type *IntResTy = llvm::IntegerType::get(
- getLLVMContext(), CGM.getDataLayout().getTypeSizeInBits(RealResTy));
- Val = Builder.CreateTruncOrBitCast(Val, IntResTy);
- return Builder.CreateBitCast(Val, RealResTy);
- }
-
- if ((BuiltinID == AArch64::BI__builtin_arm_strex ||
- BuiltinID == AArch64::BI__builtin_arm_stlex) &&
- getContext().getTypeSize(E->getArg(0)->getType()) == 128) {
- Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
- ? Intrinsic::aarch64_stlxp
- : Intrinsic::aarch64_stxp);
- llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty);
-
- Address Tmp = CreateMemTemp(E->getArg(0)->getType());
- EmitAnyExprToMem(E->getArg(0), Tmp, Qualifiers(), /*init*/ true);
-
- Tmp = Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(STy));
- llvm::Value *Val = Builder.CreateLoad(Tmp);
-
- Value *Arg0 = Builder.CreateExtractValue(Val, 0);
- Value *Arg1 = Builder.CreateExtractValue(Val, 1);
- Value *StPtr = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)),
- Int8PtrTy);
- return Builder.CreateCall(F, {Arg0, Arg1, StPtr}, "stxp");
- }
-
- if (BuiltinID == AArch64::BI__builtin_arm_strex ||
- BuiltinID == AArch64::BI__builtin_arm_stlex) {
- Value *StoreVal = EmitScalarExpr(E->getArg(0));
- Value *StoreAddr = EmitScalarExpr(E->getArg(1));
-
- QualType Ty = E->getArg(0)->getType();
- llvm::Type *StoreTy = llvm::IntegerType::get(getLLVMContext(),
- getContext().getTypeSize(Ty));
- StoreAddr = Builder.CreateBitCast(StoreAddr, StoreTy->getPointerTo());
-
- if (StoreVal->getType()->isPointerTy())
- StoreVal = Builder.CreatePtrToInt(StoreVal, Int64Ty);
- else {
- llvm::Type *IntTy = llvm::IntegerType::get(
- getLLVMContext(),
- CGM.getDataLayout().getTypeSizeInBits(StoreVal->getType()));
- StoreVal = Builder.CreateBitCast(StoreVal, IntTy);
- StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int64Ty);
- }
-
- Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
- ? Intrinsic::aarch64_stlxr
- : Intrinsic::aarch64_stxr,
- StoreAddr->getType());
- return Builder.CreateCall(F, {StoreVal, StoreAddr}, "stxr");
- }
-
- if (BuiltinID == AArch64::BI__getReg) {
- Expr::EvalResult Result;
- if (!E->getArg(0)->EvaluateAsInt(Result, CGM.getContext()))
- llvm_unreachable("Sema will ensure that the parameter is constant");
-
- llvm::APSInt Value = Result.Val.getInt();
- LLVMContext &Context = CGM.getLLVMContext();
- std::string Reg = Value == 31 ? "sp" : "x" + Value.toString(10);
-
- llvm::Metadata *Ops[] = {llvm::MDString::get(Context, Reg)};
- llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
- llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
-
- llvm::Value *F =
- CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
- return Builder.CreateCall(F, Metadata);
- }
-
- if (BuiltinID == AArch64::BI__builtin_arm_clrex) {
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_clrex);
- return Builder.CreateCall(F);
- }
-
- if (BuiltinID == AArch64::BI_ReadWriteBarrier)
- return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::SyncScope::SingleThread);
-
- // CRC32
- Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic;
- switch (BuiltinID) {
- case AArch64::BI__builtin_arm_crc32b:
- CRCIntrinsicID = Intrinsic::aarch64_crc32b; break;
- case AArch64::BI__builtin_arm_crc32cb:
- CRCIntrinsicID = Intrinsic::aarch64_crc32cb; break;
- case AArch64::BI__builtin_arm_crc32h:
- CRCIntrinsicID = Intrinsic::aarch64_crc32h; break;
- case AArch64::BI__builtin_arm_crc32ch:
- CRCIntrinsicID = Intrinsic::aarch64_crc32ch; break;
- case AArch64::BI__builtin_arm_crc32w:
- CRCIntrinsicID = Intrinsic::aarch64_crc32w; break;
- case AArch64::BI__builtin_arm_crc32cw:
- CRCIntrinsicID = Intrinsic::aarch64_crc32cw; break;
- case AArch64::BI__builtin_arm_crc32d:
- CRCIntrinsicID = Intrinsic::aarch64_crc32x; break;
- case AArch64::BI__builtin_arm_crc32cd:
- CRCIntrinsicID = Intrinsic::aarch64_crc32cx; break;
- }
-
- if (CRCIntrinsicID != Intrinsic::not_intrinsic) {
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- Value *Arg1 = EmitScalarExpr(E->getArg(1));
- Function *F = CGM.getIntrinsic(CRCIntrinsicID);
-
- llvm::Type *DataTy = F->getFunctionType()->getParamType(1);
- Arg1 = Builder.CreateZExtOrBitCast(Arg1, DataTy);
-
- return Builder.CreateCall(F, {Arg0, Arg1});
- }
-
- if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
- BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
- BuiltinID == AArch64::BI__builtin_arm_rsrp ||
- BuiltinID == AArch64::BI__builtin_arm_wsr ||
- BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
- BuiltinID == AArch64::BI__builtin_arm_wsrp) {
-
- bool IsRead = BuiltinID == AArch64::BI__builtin_arm_rsr ||
- BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
- BuiltinID == AArch64::BI__builtin_arm_rsrp;
-
- bool IsPointerBuiltin = BuiltinID == AArch64::BI__builtin_arm_rsrp ||
- BuiltinID == AArch64::BI__builtin_arm_wsrp;
-
- bool Is64Bit = BuiltinID != AArch64::BI__builtin_arm_rsr &&
- BuiltinID != AArch64::BI__builtin_arm_wsr;
-
- llvm::Type *ValueType;
- llvm::Type *RegisterType = Int64Ty;
- if (IsPointerBuiltin) {
- ValueType = VoidPtrTy;
- } else if (Is64Bit) {
- ValueType = Int64Ty;
- } else {
- ValueType = Int32Ty;
- }
-
- return EmitSpecialRegisterBuiltin(*this, E, RegisterType, ValueType, IsRead);
- }
-
- if (BuiltinID == AArch64::BI_ReadStatusReg ||
- BuiltinID == AArch64::BI_WriteStatusReg) {
- LLVMContext &Context = CGM.getLLVMContext();
-
- unsigned SysReg =
- E->getArg(0)->EvaluateKnownConstInt(getContext()).getZExtValue();
-
- std::string SysRegStr;
- llvm::raw_string_ostream(SysRegStr) <<
- ((1 << 1) | ((SysReg >> 14) & 1)) << ":" <<
- ((SysReg >> 11) & 7) << ":" <<
- ((SysReg >> 7) & 15) << ":" <<
- ((SysReg >> 3) & 15) << ":" <<
- ( SysReg & 7);
-
- llvm::Metadata *Ops[] = { llvm::MDString::get(Context, SysRegStr) };
- llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
- llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
-
- llvm::Type *RegisterType = Int64Ty;
- llvm::Type *Types[] = { RegisterType };
-
- if (BuiltinID == AArch64::BI_ReadStatusReg) {
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
-
- return Builder.CreateCall(F, Metadata);
- }
-
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
- llvm::Value *ArgValue = EmitScalarExpr(E->getArg(1));
-
- return Builder.CreateCall(F, { Metadata, ArgValue });
- }
-
- if (BuiltinID == AArch64::BI_AddressOfReturnAddress) {
- llvm::Value *F = CGM.getIntrinsic(Intrinsic::addressofreturnaddress);
- return Builder.CreateCall(F);
- }
-
- // Find out if any arguments are required to be integer constant
- // expressions.
- unsigned ICEArguments = 0;
- ASTContext::GetBuiltinTypeError Error;
- getContext().GetBuiltinType(BuiltinID, Error, &ICEArguments);
- assert(Error == ASTContext::GE_None && "Should not codegen an error");
-
- llvm::SmallVector<Value*, 4> Ops;
- for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
- if ((ICEArguments & (1 << i)) == 0) {
- Ops.push_back(EmitScalarExpr(E->getArg(i)));
- } else {
- // If this is required to be a constant, constant fold it so that we know
- // that the generated intrinsic gets a ConstantInt.
- llvm::APSInt Result;
- bool IsConst = E->getArg(i)->isIntegerConstantExpr(Result, getContext());
- assert(IsConst && "Constant arg isn't actually constant?");
- (void)IsConst;
- Ops.push_back(llvm::ConstantInt::get(getLLVMContext(), Result));
- }
- }
-
- auto SISDMap = makeArrayRef(AArch64SISDIntrinsicMap);
- const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
- SISDMap, BuiltinID, AArch64SISDIntrinsicsProvenSorted);
-
- if (Builtin) {
- Ops.push_back(EmitScalarExpr(E->getArg(E->getNumArgs() - 1)));
- Value *Result = EmitCommonNeonSISDBuiltinExpr(*this, *Builtin, Ops, E);
- assert(Result && "SISD intrinsic should have been handled");
- return Result;
- }
-
- llvm::APSInt Result;
- const Expr *Arg = E->getArg(E->getNumArgs()-1);
- NeonTypeFlags Type(0);
- if (Arg->isIntegerConstantExpr(Result, getContext()))
- // Determine the type of this overloaded NEON intrinsic.
- Type = NeonTypeFlags(Result.getZExtValue());
-
- bool usgn = Type.isUnsigned();
- bool quad = Type.isQuad();
-
- // Handle non-overloaded intrinsics first.
- switch (BuiltinID) {
- default: break;
- case NEON::BI__builtin_neon_vabsh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::fabs, HalfTy), Ops, "vabs");
- case NEON::BI__builtin_neon_vldrq_p128: {
- llvm::Type *Int128Ty = llvm::Type::getIntNTy(getLLVMContext(), 128);
- llvm::Type *Int128PTy = llvm::PointerType::get(Int128Ty, 0);
- Value *Ptr = Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int128PTy);
- return Builder.CreateAlignedLoad(Int128Ty, Ptr,
- CharUnits::fromQuantity(16));
- }
- case NEON::BI__builtin_neon_vstrq_p128: {
- llvm::Type *Int128PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), 128);
- Value *Ptr = Builder.CreateBitCast(Ops[0], Int128PTy);
- return Builder.CreateDefaultAlignedStore(EmitScalarExpr(E->getArg(1)), Ptr);
- }
- case NEON::BI__builtin_neon_vcvts_u32_f32:
- case NEON::BI__builtin_neon_vcvtd_u64_f64:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vcvts_s32_f32:
- case NEON::BI__builtin_neon_vcvtd_s64_f64: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- bool Is64 = Ops[0]->getType()->getPrimitiveSizeInBits() == 64;
- llvm::Type *InTy = Is64 ? Int64Ty : Int32Ty;
- llvm::Type *FTy = Is64 ? DoubleTy : FloatTy;
- Ops[0] = Builder.CreateBitCast(Ops[0], FTy);
- if (usgn)
- return Builder.CreateFPToUI(Ops[0], InTy);
- return Builder.CreateFPToSI(Ops[0], InTy);
- }
- case NEON::BI__builtin_neon_vcvts_f32_u32:
- case NEON::BI__builtin_neon_vcvtd_f64_u64:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vcvts_f32_s32:
- case NEON::BI__builtin_neon_vcvtd_f64_s64: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- bool Is64 = Ops[0]->getType()->getPrimitiveSizeInBits() == 64;
- llvm::Type *InTy = Is64 ? Int64Ty : Int32Ty;
- llvm::Type *FTy = Is64 ? DoubleTy : FloatTy;
- Ops[0] = Builder.CreateBitCast(Ops[0], InTy);
- if (usgn)
- return Builder.CreateUIToFP(Ops[0], FTy);
- return Builder.CreateSIToFP(Ops[0], FTy);
- }
- case NEON::BI__builtin_neon_vcvth_f16_u16:
- case NEON::BI__builtin_neon_vcvth_f16_u32:
- case NEON::BI__builtin_neon_vcvth_f16_u64:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vcvth_f16_s16:
- case NEON::BI__builtin_neon_vcvth_f16_s32:
- case NEON::BI__builtin_neon_vcvth_f16_s64: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- llvm::Type *FTy = HalfTy;
- llvm::Type *InTy;
- if (Ops[0]->getType()->getPrimitiveSizeInBits() == 64)
- InTy = Int64Ty;
- else if (Ops[0]->getType()->getPrimitiveSizeInBits() == 32)
- InTy = Int32Ty;
- else
- InTy = Int16Ty;
- Ops[0] = Builder.CreateBitCast(Ops[0], InTy);
- if (usgn)
- return Builder.CreateUIToFP(Ops[0], FTy);
- return Builder.CreateSIToFP(Ops[0], FTy);
- }
- case NEON::BI__builtin_neon_vcvth_u16_f16:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vcvth_s16_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = Builder.CreateBitCast(Ops[0], HalfTy);
- if (usgn)
- return Builder.CreateFPToUI(Ops[0], Int16Ty);
- return Builder.CreateFPToSI(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vcvth_u32_f16:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vcvth_s32_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = Builder.CreateBitCast(Ops[0], HalfTy);
- if (usgn)
- return Builder.CreateFPToUI(Ops[0], Int32Ty);
- return Builder.CreateFPToSI(Ops[0], Int32Ty);
- }
- case NEON::BI__builtin_neon_vcvth_u64_f16:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vcvth_s64_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = Builder.CreateBitCast(Ops[0], HalfTy);
- if (usgn)
- return Builder.CreateFPToUI(Ops[0], Int64Ty);
- return Builder.CreateFPToSI(Ops[0], Int64Ty);
- }
- case NEON::BI__builtin_neon_vcvtah_u16_f16:
- case NEON::BI__builtin_neon_vcvtmh_u16_f16:
- case NEON::BI__builtin_neon_vcvtnh_u16_f16:
- case NEON::BI__builtin_neon_vcvtph_u16_f16:
- case NEON::BI__builtin_neon_vcvtah_s16_f16:
- case NEON::BI__builtin_neon_vcvtmh_s16_f16:
- case NEON::BI__builtin_neon_vcvtnh_s16_f16:
- case NEON::BI__builtin_neon_vcvtph_s16_f16: {
- unsigned Int;
- llvm::Type* InTy = Int32Ty;
- llvm::Type* FTy = HalfTy;
- llvm::Type *Tys[2] = {InTy, FTy};
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vcvtah_u16_f16:
- Int = Intrinsic::aarch64_neon_fcvtau; break;
- case NEON::BI__builtin_neon_vcvtmh_u16_f16:
- Int = Intrinsic::aarch64_neon_fcvtmu; break;
- case NEON::BI__builtin_neon_vcvtnh_u16_f16:
- Int = Intrinsic::aarch64_neon_fcvtnu; break;
- case NEON::BI__builtin_neon_vcvtph_u16_f16:
- Int = Intrinsic::aarch64_neon_fcvtpu; break;
- case NEON::BI__builtin_neon_vcvtah_s16_f16:
- Int = Intrinsic::aarch64_neon_fcvtas; break;
- case NEON::BI__builtin_neon_vcvtmh_s16_f16:
- Int = Intrinsic::aarch64_neon_fcvtms; break;
- case NEON::BI__builtin_neon_vcvtnh_s16_f16:
- Int = Intrinsic::aarch64_neon_fcvtns; break;
- case NEON::BI__builtin_neon_vcvtph_s16_f16:
- Int = Intrinsic::aarch64_neon_fcvtps; break;
- }
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "fcvt");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vcaleh_f16:
- case NEON::BI__builtin_neon_vcalth_f16:
- case NEON::BI__builtin_neon_vcageh_f16:
- case NEON::BI__builtin_neon_vcagth_f16: {
- unsigned Int;
- llvm::Type* InTy = Int32Ty;
- llvm::Type* FTy = HalfTy;
- llvm::Type *Tys[2] = {InTy, FTy};
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vcageh_f16:
- Int = Intrinsic::aarch64_neon_facge; break;
- case NEON::BI__builtin_neon_vcagth_f16:
- Int = Intrinsic::aarch64_neon_facgt; break;
- case NEON::BI__builtin_neon_vcaleh_f16:
- Int = Intrinsic::aarch64_neon_facge; std::swap(Ops[0], Ops[1]); break;
- case NEON::BI__builtin_neon_vcalth_f16:
- Int = Intrinsic::aarch64_neon_facgt; std::swap(Ops[0], Ops[1]); break;
- }
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "facg");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vcvth_n_s16_f16:
- case NEON::BI__builtin_neon_vcvth_n_u16_f16: {
- unsigned Int;
- llvm::Type* InTy = Int32Ty;
- llvm::Type* FTy = HalfTy;
- llvm::Type *Tys[2] = {InTy, FTy};
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vcvth_n_s16_f16:
- Int = Intrinsic::aarch64_neon_vcvtfp2fxs; break;
- case NEON::BI__builtin_neon_vcvth_n_u16_f16:
- Int = Intrinsic::aarch64_neon_vcvtfp2fxu; break;
- }
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "fcvth_n");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vcvth_n_f16_s16:
- case NEON::BI__builtin_neon_vcvth_n_f16_u16: {
- unsigned Int;
- llvm::Type* FTy = HalfTy;
- llvm::Type* InTy = Int32Ty;
- llvm::Type *Tys[2] = {FTy, InTy};
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vcvth_n_f16_s16:
- Int = Intrinsic::aarch64_neon_vcvtfxs2fp;
- Ops[0] = Builder.CreateSExt(Ops[0], InTy, "sext");
- break;
- case NEON::BI__builtin_neon_vcvth_n_f16_u16:
- Int = Intrinsic::aarch64_neon_vcvtfxu2fp;
- Ops[0] = Builder.CreateZExt(Ops[0], InTy);
- break;
- }
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "fcvth_n");
- }
- case NEON::BI__builtin_neon_vpaddd_s64: {
- llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 2);
- Value *Vec = EmitScalarExpr(E->getArg(0));
- // The vector is v2f64, so make sure it's bitcast to that.
- Vec = Builder.CreateBitCast(Vec, Ty, "v2i64");
- llvm::Value *Idx0 = llvm::ConstantInt::get(SizeTy, 0);
- llvm::Value *Idx1 = llvm::ConstantInt::get(SizeTy, 1);
- Value *Op0 = Builder.CreateExtractElement(Vec, Idx0, "lane0");
- Value *Op1 = Builder.CreateExtractElement(Vec, Idx1, "lane1");
- // Pairwise addition of a v2f64 into a scalar f64.
- return Builder.CreateAdd(Op0, Op1, "vpaddd");
- }
- case NEON::BI__builtin_neon_vpaddd_f64: {
- llvm::Type *Ty =
- llvm::VectorType::get(DoubleTy, 2);
- Value *Vec = EmitScalarExpr(E->getArg(0));
- // The vector is v2f64, so make sure it's bitcast to that.
- Vec = Builder.CreateBitCast(Vec, Ty, "v2f64");
- llvm::Value *Idx0 = llvm::ConstantInt::get(SizeTy, 0);
- llvm::Value *Idx1 = llvm::ConstantInt::get(SizeTy, 1);
- Value *Op0 = Builder.CreateExtractElement(Vec, Idx0, "lane0");
- Value *Op1 = Builder.CreateExtractElement(Vec, Idx1, "lane1");
- // Pairwise addition of a v2f64 into a scalar f64.
- return Builder.CreateFAdd(Op0, Op1, "vpaddd");
- }
- case NEON::BI__builtin_neon_vpadds_f32: {
- llvm::Type *Ty =
- llvm::VectorType::get(FloatTy, 2);
- Value *Vec = EmitScalarExpr(E->getArg(0));
- // The vector is v2f32, so make sure it's bitcast to that.
- Vec = Builder.CreateBitCast(Vec, Ty, "v2f32");
- llvm::Value *Idx0 = llvm::ConstantInt::get(SizeTy, 0);
- llvm::Value *Idx1 = llvm::ConstantInt::get(SizeTy, 1);
- Value *Op0 = Builder.CreateExtractElement(Vec, Idx0, "lane0");
- Value *Op1 = Builder.CreateExtractElement(Vec, Idx1, "lane1");
- // Pairwise addition of a v2f32 into a scalar f32.
- return Builder.CreateFAdd(Op0, Op1, "vpaddd");
- }
- case NEON::BI__builtin_neon_vceqzd_s64:
- case NEON::BI__builtin_neon_vceqzd_f64:
- case NEON::BI__builtin_neon_vceqzs_f32:
- case NEON::BI__builtin_neon_vceqzh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitAArch64CompareBuiltinExpr(
- Ops[0], ConvertType(E->getCallReturnType(getContext())),
- ICmpInst::FCMP_OEQ, ICmpInst::ICMP_EQ, "vceqz");
- case NEON::BI__builtin_neon_vcgezd_s64:
- case NEON::BI__builtin_neon_vcgezd_f64:
- case NEON::BI__builtin_neon_vcgezs_f32:
- case NEON::BI__builtin_neon_vcgezh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitAArch64CompareBuiltinExpr(
- Ops[0], ConvertType(E->getCallReturnType(getContext())),
- ICmpInst::FCMP_OGE, ICmpInst::ICMP_SGE, "vcgez");
- case NEON::BI__builtin_neon_vclezd_s64:
- case NEON::BI__builtin_neon_vclezd_f64:
- case NEON::BI__builtin_neon_vclezs_f32:
- case NEON::BI__builtin_neon_vclezh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitAArch64CompareBuiltinExpr(
- Ops[0], ConvertType(E->getCallReturnType(getContext())),
- ICmpInst::FCMP_OLE, ICmpInst::ICMP_SLE, "vclez");
- case NEON::BI__builtin_neon_vcgtzd_s64:
- case NEON::BI__builtin_neon_vcgtzd_f64:
- case NEON::BI__builtin_neon_vcgtzs_f32:
- case NEON::BI__builtin_neon_vcgtzh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitAArch64CompareBuiltinExpr(
- Ops[0], ConvertType(E->getCallReturnType(getContext())),
- ICmpInst::FCMP_OGT, ICmpInst::ICMP_SGT, "vcgtz");
- case NEON::BI__builtin_neon_vcltzd_s64:
- case NEON::BI__builtin_neon_vcltzd_f64:
- case NEON::BI__builtin_neon_vcltzs_f32:
- case NEON::BI__builtin_neon_vcltzh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitAArch64CompareBuiltinExpr(
- Ops[0], ConvertType(E->getCallReturnType(getContext())),
- ICmpInst::FCMP_OLT, ICmpInst::ICMP_SLT, "vcltz");
-
- case NEON::BI__builtin_neon_vceqzd_u64: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = Builder.CreateBitCast(Ops[0], Int64Ty);
- Ops[0] =
- Builder.CreateICmpEQ(Ops[0], llvm::Constant::getNullValue(Int64Ty));
- return Builder.CreateSExt(Ops[0], Int64Ty, "vceqzd");
- }
- case NEON::BI__builtin_neon_vceqd_f64:
- case NEON::BI__builtin_neon_vcled_f64:
- case NEON::BI__builtin_neon_vcltd_f64:
- case NEON::BI__builtin_neon_vcged_f64:
- case NEON::BI__builtin_neon_vcgtd_f64: {
- llvm::CmpInst::Predicate P;
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vceqd_f64: P = llvm::FCmpInst::FCMP_OEQ; break;
- case NEON::BI__builtin_neon_vcled_f64: P = llvm::FCmpInst::FCMP_OLE; break;
- case NEON::BI__builtin_neon_vcltd_f64: P = llvm::FCmpInst::FCMP_OLT; break;
- case NEON::BI__builtin_neon_vcged_f64: P = llvm::FCmpInst::FCMP_OGE; break;
- case NEON::BI__builtin_neon_vcgtd_f64: P = llvm::FCmpInst::FCMP_OGT; break;
- }
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
- Ops[0] = Builder.CreateFCmp(P, Ops[0], Ops[1]);
- return Builder.CreateSExt(Ops[0], Int64Ty, "vcmpd");
- }
- case NEON::BI__builtin_neon_vceqs_f32:
- case NEON::BI__builtin_neon_vcles_f32:
- case NEON::BI__builtin_neon_vclts_f32:
- case NEON::BI__builtin_neon_vcges_f32:
- case NEON::BI__builtin_neon_vcgts_f32: {
- llvm::CmpInst::Predicate P;
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vceqs_f32: P = llvm::FCmpInst::FCMP_OEQ; break;
- case NEON::BI__builtin_neon_vcles_f32: P = llvm::FCmpInst::FCMP_OLE; break;
- case NEON::BI__builtin_neon_vclts_f32: P = llvm::FCmpInst::FCMP_OLT; break;
- case NEON::BI__builtin_neon_vcges_f32: P = llvm::FCmpInst::FCMP_OGE; break;
- case NEON::BI__builtin_neon_vcgts_f32: P = llvm::FCmpInst::FCMP_OGT; break;
- }
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], FloatTy);
- Ops[0] = Builder.CreateFCmp(P, Ops[0], Ops[1]);
- return Builder.CreateSExt(Ops[0], Int32Ty, "vcmpd");
- }
- case NEON::BI__builtin_neon_vceqh_f16:
- case NEON::BI__builtin_neon_vcleh_f16:
- case NEON::BI__builtin_neon_vclth_f16:
- case NEON::BI__builtin_neon_vcgeh_f16:
- case NEON::BI__builtin_neon_vcgth_f16: {
- llvm::CmpInst::Predicate P;
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vceqh_f16: P = llvm::FCmpInst::FCMP_OEQ; break;
- case NEON::BI__builtin_neon_vcleh_f16: P = llvm::FCmpInst::FCMP_OLE; break;
- case NEON::BI__builtin_neon_vclth_f16: P = llvm::FCmpInst::FCMP_OLT; break;
- case NEON::BI__builtin_neon_vcgeh_f16: P = llvm::FCmpInst::FCMP_OGE; break;
- case NEON::BI__builtin_neon_vcgth_f16: P = llvm::FCmpInst::FCMP_OGT; break;
- }
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Ops[0] = Builder.CreateBitCast(Ops[0], HalfTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], HalfTy);
- Ops[0] = Builder.CreateFCmp(P, Ops[0], Ops[1]);
- return Builder.CreateSExt(Ops[0], Int16Ty, "vcmpd");
- }
- case NEON::BI__builtin_neon_vceqd_s64:
- case NEON::BI__builtin_neon_vceqd_u64:
- case NEON::BI__builtin_neon_vcgtd_s64:
- case NEON::BI__builtin_neon_vcgtd_u64:
- case NEON::BI__builtin_neon_vcltd_s64:
- case NEON::BI__builtin_neon_vcltd_u64:
- case NEON::BI__builtin_neon_vcged_u64:
- case NEON::BI__builtin_neon_vcged_s64:
- case NEON::BI__builtin_neon_vcled_u64:
- case NEON::BI__builtin_neon_vcled_s64: {
- llvm::CmpInst::Predicate P;
- switch (BuiltinID) {
- default: llvm_unreachable("missing builtin ID in switch!");
- case NEON::BI__builtin_neon_vceqd_s64:
- case NEON::BI__builtin_neon_vceqd_u64:P = llvm::ICmpInst::ICMP_EQ;break;
- case NEON::BI__builtin_neon_vcgtd_s64:P = llvm::ICmpInst::ICMP_SGT;break;
- case NEON::BI__builtin_neon_vcgtd_u64:P = llvm::ICmpInst::ICMP_UGT;break;
- case NEON::BI__builtin_neon_vcltd_s64:P = llvm::ICmpInst::ICMP_SLT;break;
- case NEON::BI__builtin_neon_vcltd_u64:P = llvm::ICmpInst::ICMP_ULT;break;
- case NEON::BI__builtin_neon_vcged_u64:P = llvm::ICmpInst::ICMP_UGE;break;
- case NEON::BI__builtin_neon_vcged_s64:P = llvm::ICmpInst::ICMP_SGE;break;
- case NEON::BI__builtin_neon_vcled_u64:P = llvm::ICmpInst::ICMP_ULE;break;
- case NEON::BI__builtin_neon_vcled_s64:P = llvm::ICmpInst::ICMP_SLE;break;
- }
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Ops[0] = Builder.CreateBitCast(Ops[0], Int64Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Int64Ty);
- Ops[0] = Builder.CreateICmp(P, Ops[0], Ops[1]);
- return Builder.CreateSExt(Ops[0], Int64Ty, "vceqd");
- }
- case NEON::BI__builtin_neon_vtstd_s64:
- case NEON::BI__builtin_neon_vtstd_u64: {
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Ops[0] = Builder.CreateBitCast(Ops[0], Int64Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Int64Ty);
- Ops[0] = Builder.CreateAnd(Ops[0], Ops[1]);
- Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
- llvm::Constant::getNullValue(Int64Ty));
- return Builder.CreateSExt(Ops[0], Int64Ty, "vtstd");
- }
- case NEON::BI__builtin_neon_vset_lane_i8:
- case NEON::BI__builtin_neon_vset_lane_i16:
- case NEON::BI__builtin_neon_vset_lane_i32:
- case NEON::BI__builtin_neon_vset_lane_i64:
- case NEON::BI__builtin_neon_vset_lane_f32:
- case NEON::BI__builtin_neon_vsetq_lane_i8:
- case NEON::BI__builtin_neon_vsetq_lane_i16:
- case NEON::BI__builtin_neon_vsetq_lane_i32:
- case NEON::BI__builtin_neon_vsetq_lane_i64:
- case NEON::BI__builtin_neon_vsetq_lane_f32:
- Ops.push_back(EmitScalarExpr(E->getArg(2)));
- return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
- case NEON::BI__builtin_neon_vset_lane_f64:
- // The vector type needs a cast for the v1f64 variant.
- Ops[1] = Builder.CreateBitCast(Ops[1],
- llvm::VectorType::get(DoubleTy, 1));
- Ops.push_back(EmitScalarExpr(E->getArg(2)));
- return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
- case NEON::BI__builtin_neon_vsetq_lane_f64:
- // The vector type needs a cast for the v2f64 variant.
- Ops[1] = Builder.CreateBitCast(Ops[1],
- llvm::VectorType::get(DoubleTy, 2));
- Ops.push_back(EmitScalarExpr(E->getArg(2)));
- return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
-
- case NEON::BI__builtin_neon_vget_lane_i8:
- case NEON::BI__builtin_neon_vdupb_lane_i8:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int8Ty, 8));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vget_lane");
- case NEON::BI__builtin_neon_vgetq_lane_i8:
- case NEON::BI__builtin_neon_vdupb_laneq_i8:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int8Ty, 16));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vgetq_lane");
- case NEON::BI__builtin_neon_vget_lane_i16:
- case NEON::BI__builtin_neon_vduph_lane_i16:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int16Ty, 4));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vget_lane");
- case NEON::BI__builtin_neon_vgetq_lane_i16:
- case NEON::BI__builtin_neon_vduph_laneq_i16:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int16Ty, 8));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vgetq_lane");
- case NEON::BI__builtin_neon_vget_lane_i32:
- case NEON::BI__builtin_neon_vdups_lane_i32:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 2));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vget_lane");
- case NEON::BI__builtin_neon_vdups_lane_f32:
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::VectorType::get(FloatTy, 2));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vdups_lane");
- case NEON::BI__builtin_neon_vgetq_lane_i32:
- case NEON::BI__builtin_neon_vdups_laneq_i32:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 4));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vgetq_lane");
- case NEON::BI__builtin_neon_vget_lane_i64:
- case NEON::BI__builtin_neon_vdupd_lane_i64:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 1));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vget_lane");
- case NEON::BI__builtin_neon_vdupd_lane_f64:
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::VectorType::get(DoubleTy, 1));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vdupd_lane");
- case NEON::BI__builtin_neon_vgetq_lane_i64:
- case NEON::BI__builtin_neon_vdupd_laneq_i64:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vgetq_lane");
- case NEON::BI__builtin_neon_vget_lane_f32:
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::VectorType::get(FloatTy, 2));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vget_lane");
- case NEON::BI__builtin_neon_vget_lane_f64:
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::VectorType::get(DoubleTy, 1));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vget_lane");
- case NEON::BI__builtin_neon_vgetq_lane_f32:
- case NEON::BI__builtin_neon_vdups_laneq_f32:
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::VectorType::get(FloatTy, 4));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vgetq_lane");
- case NEON::BI__builtin_neon_vgetq_lane_f64:
- case NEON::BI__builtin_neon_vdupd_laneq_f64:
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::VectorType::get(DoubleTy, 2));
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vgetq_lane");
- case NEON::BI__builtin_neon_vaddh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- return Builder.CreateFAdd(Ops[0], Ops[1], "vaddh");
- case NEON::BI__builtin_neon_vsubh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- return Builder.CreateFSub(Ops[0], Ops[1], "vsubh");
- case NEON::BI__builtin_neon_vmulh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- return Builder.CreateFMul(Ops[0], Ops[1], "vmulh");
- case NEON::BI__builtin_neon_vdivh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- return Builder.CreateFDiv(Ops[0], Ops[1], "vdivh");
- case NEON::BI__builtin_neon_vfmah_f16: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, HalfTy);
- // NEON intrinsic puts accumulator first, unlike the LLVM fma.
- return Builder.CreateCall(F,
- {EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)), Ops[0]});
- }
- case NEON::BI__builtin_neon_vfmsh_f16: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, HalfTy);
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(HalfTy);
- Value* Sub = Builder.CreateFSub(Zero, EmitScalarExpr(E->getArg(1)), "vsubh");
- // NEON intrinsic puts accumulator first, unlike the LLVM fma.
- return Builder.CreateCall(F, {Sub, EmitScalarExpr(E->getArg(2)), Ops[0]});
- }
- case NEON::BI__builtin_neon_vaddd_s64:
- case NEON::BI__builtin_neon_vaddd_u64:
- return Builder.CreateAdd(Ops[0], EmitScalarExpr(E->getArg(1)), "vaddd");
- case NEON::BI__builtin_neon_vsubd_s64:
- case NEON::BI__builtin_neon_vsubd_u64:
- return Builder.CreateSub(Ops[0], EmitScalarExpr(E->getArg(1)), "vsubd");
- case NEON::BI__builtin_neon_vqdmlalh_s16:
- case NEON::BI__builtin_neon_vqdmlslh_s16: {
- SmallVector<Value *, 2> ProductOps;
- ProductOps.push_back(vectorWrapScalar16(Ops[1]));
- ProductOps.push_back(vectorWrapScalar16(EmitScalarExpr(E->getArg(2))));
- llvm::Type *VTy = llvm::VectorType::get(Int32Ty, 4);
- Ops[1] = EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmull, VTy),
- ProductOps, "vqdmlXl");
- Constant *CI = ConstantInt::get(SizeTy, 0);
- Ops[1] = Builder.CreateExtractElement(Ops[1], CI, "lane0");
-
- unsigned AccumInt = BuiltinID == NEON::BI__builtin_neon_vqdmlalh_s16
- ? Intrinsic::aarch64_neon_sqadd
- : Intrinsic::aarch64_neon_sqsub;
- return EmitNeonCall(CGM.getIntrinsic(AccumInt, Int32Ty), Ops, "vqdmlXl");
- }
- case NEON::BI__builtin_neon_vqshlud_n_s64: {
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqshlu, Int64Ty),
- Ops, "vqshlu_n");
- }
- case NEON::BI__builtin_neon_vqshld_n_u64:
- case NEON::BI__builtin_neon_vqshld_n_s64: {
- unsigned Int = BuiltinID == NEON::BI__builtin_neon_vqshld_n_u64
- ? Intrinsic::aarch64_neon_uqshl
- : Intrinsic::aarch64_neon_sqshl;
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty);
- return EmitNeonCall(CGM.getIntrinsic(Int, Int64Ty), Ops, "vqshl_n");
- }
- case NEON::BI__builtin_neon_vrshrd_n_u64:
- case NEON::BI__builtin_neon_vrshrd_n_s64: {
- unsigned Int = BuiltinID == NEON::BI__builtin_neon_vrshrd_n_u64
- ? Intrinsic::aarch64_neon_urshl
- : Intrinsic::aarch64_neon_srshl;
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- int SV = cast<ConstantInt>(Ops[1])->getSExtValue();
- Ops[1] = ConstantInt::get(Int64Ty, -SV);
- return EmitNeonCall(CGM.getIntrinsic(Int, Int64Ty), Ops, "vrshr_n");
- }
- case NEON::BI__builtin_neon_vrsrad_n_u64:
- case NEON::BI__builtin_neon_vrsrad_n_s64: {
- unsigned Int = BuiltinID == NEON::BI__builtin_neon_vrsrad_n_u64
- ? Intrinsic::aarch64_neon_urshl
- : Intrinsic::aarch64_neon_srshl;
- Ops[1] = Builder.CreateBitCast(Ops[1], Int64Ty);
- Ops.push_back(Builder.CreateNeg(EmitScalarExpr(E->getArg(2))));
- Ops[1] = Builder.CreateCall(CGM.getIntrinsic(Int, Int64Ty),
- {Ops[1], Builder.CreateSExt(Ops[2], Int64Ty)});
- return Builder.CreateAdd(Ops[0], Builder.CreateBitCast(Ops[1], Int64Ty));
- }
- case NEON::BI__builtin_neon_vshld_n_s64:
- case NEON::BI__builtin_neon_vshld_n_u64: {
- llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
- return Builder.CreateShl(
- Ops[0], ConstantInt::get(Int64Ty, Amt->getZExtValue()), "shld_n");
- }
- case NEON::BI__builtin_neon_vshrd_n_s64: {
- llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
- return Builder.CreateAShr(
- Ops[0], ConstantInt::get(Int64Ty, std::min(static_cast<uint64_t>(63),
- Amt->getZExtValue())),
- "shrd_n");
- }
- case NEON::BI__builtin_neon_vshrd_n_u64: {
- llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
- uint64_t ShiftAmt = Amt->getZExtValue();
- // Right-shifting an unsigned value by its size yields 0.
- if (ShiftAmt == 64)
- return ConstantInt::get(Int64Ty, 0);
- return Builder.CreateLShr(Ops[0], ConstantInt::get(Int64Ty, ShiftAmt),
- "shrd_n");
- }
- case NEON::BI__builtin_neon_vsrad_n_s64: {
- llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(2)));
- Ops[1] = Builder.CreateAShr(
- Ops[1], ConstantInt::get(Int64Ty, std::min(static_cast<uint64_t>(63),
- Amt->getZExtValue())),
- "shrd_n");
- return Builder.CreateAdd(Ops[0], Ops[1]);
- }
- case NEON::BI__builtin_neon_vsrad_n_u64: {
- llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(2)));
- uint64_t ShiftAmt = Amt->getZExtValue();
- // Right-shifting an unsigned value by its size yields 0.
- // As Op + 0 = Op, return Ops[0] directly.
- if (ShiftAmt == 64)
- return Ops[0];
- Ops[1] = Builder.CreateLShr(Ops[1], ConstantInt::get(Int64Ty, ShiftAmt),
- "shrd_n");
- return Builder.CreateAdd(Ops[0], Ops[1]);
- }
- case NEON::BI__builtin_neon_vqdmlalh_lane_s16:
- case NEON::BI__builtin_neon_vqdmlalh_laneq_s16:
- case NEON::BI__builtin_neon_vqdmlslh_lane_s16:
- case NEON::BI__builtin_neon_vqdmlslh_laneq_s16: {
- Ops[2] = Builder.CreateExtractElement(Ops[2], EmitScalarExpr(E->getArg(3)),
- "lane");
- SmallVector<Value *, 2> ProductOps;
- ProductOps.push_back(vectorWrapScalar16(Ops[1]));
- ProductOps.push_back(vectorWrapScalar16(Ops[2]));
- llvm::Type *VTy = llvm::VectorType::get(Int32Ty, 4);
- Ops[1] = EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmull, VTy),
- ProductOps, "vqdmlXl");
- Constant *CI = ConstantInt::get(SizeTy, 0);
- Ops[1] = Builder.CreateExtractElement(Ops[1], CI, "lane0");
- Ops.pop_back();
-
- unsigned AccInt = (BuiltinID == NEON::BI__builtin_neon_vqdmlalh_lane_s16 ||
- BuiltinID == NEON::BI__builtin_neon_vqdmlalh_laneq_s16)
- ? Intrinsic::aarch64_neon_sqadd
- : Intrinsic::aarch64_neon_sqsub;
- return EmitNeonCall(CGM.getIntrinsic(AccInt, Int32Ty), Ops, "vqdmlXl");
- }
- case NEON::BI__builtin_neon_vqdmlals_s32:
- case NEON::BI__builtin_neon_vqdmlsls_s32: {
- SmallVector<Value *, 2> ProductOps;
- ProductOps.push_back(Ops[1]);
- ProductOps.push_back(EmitScalarExpr(E->getArg(2)));
- Ops[1] =
- EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmulls_scalar),
- ProductOps, "vqdmlXl");
-
- unsigned AccumInt = BuiltinID == NEON::BI__builtin_neon_vqdmlals_s32
- ? Intrinsic::aarch64_neon_sqadd
- : Intrinsic::aarch64_neon_sqsub;
- return EmitNeonCall(CGM.getIntrinsic(AccumInt, Int64Ty), Ops, "vqdmlXl");
- }
- case NEON::BI__builtin_neon_vqdmlals_lane_s32:
- case NEON::BI__builtin_neon_vqdmlals_laneq_s32:
- case NEON::BI__builtin_neon_vqdmlsls_lane_s32:
- case NEON::BI__builtin_neon_vqdmlsls_laneq_s32: {
- Ops[2] = Builder.CreateExtractElement(Ops[2], EmitScalarExpr(E->getArg(3)),
- "lane");
- SmallVector<Value *, 2> ProductOps;
- ProductOps.push_back(Ops[1]);
- ProductOps.push_back(Ops[2]);
- Ops[1] =
- EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmulls_scalar),
- ProductOps, "vqdmlXl");
- Ops.pop_back();
-
- unsigned AccInt = (BuiltinID == NEON::BI__builtin_neon_vqdmlals_lane_s32 ||
- BuiltinID == NEON::BI__builtin_neon_vqdmlals_laneq_s32)
- ? Intrinsic::aarch64_neon_sqadd
- : Intrinsic::aarch64_neon_sqsub;
- return EmitNeonCall(CGM.getIntrinsic(AccInt, Int64Ty), Ops, "vqdmlXl");
- }
- }
-
- llvm::VectorType *VTy = GetNeonType(this, Type);
- llvm::Type *Ty = VTy;
- if (!Ty)
- return nullptr;
-
- // Not all intrinsics handled by the common case work for AArch64 yet, so only
- // defer to common code if it's been added to our special map.
- Builtin = findNeonIntrinsicInMap(AArch64SIMDIntrinsicMap, BuiltinID,
- AArch64SIMDIntrinsicsProvenSorted);
-
- if (Builtin)
- return EmitCommonNeonBuiltinExpr(
- Builtin->BuiltinID, Builtin->LLVMIntrinsic, Builtin->AltLLVMIntrinsic,
- Builtin->NameHint, Builtin->TypeModifier, E, Ops,
- /*never use addresses*/ Address::invalid(), Address::invalid(), Arch);
-
- if (Value *V = EmitAArch64TblBuiltinExpr(*this, BuiltinID, E, Ops, Arch))
- return V;
-
- unsigned Int;
- switch (BuiltinID) {
- default: return nullptr;
- case NEON::BI__builtin_neon_vbsl_v:
- case NEON::BI__builtin_neon_vbslq_v: {
- llvm::Type *BitTy = llvm::VectorType::getInteger(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], BitTy, "vbsl");
- Ops[1] = Builder.CreateBitCast(Ops[1], BitTy, "vbsl");
- Ops[2] = Builder.CreateBitCast(Ops[2], BitTy, "vbsl");
-
- Ops[1] = Builder.CreateAnd(Ops[0], Ops[1], "vbsl");
- Ops[2] = Builder.CreateAnd(Builder.CreateNot(Ops[0]), Ops[2], "vbsl");
- Ops[0] = Builder.CreateOr(Ops[1], Ops[2], "vbsl");
- return Builder.CreateBitCast(Ops[0], Ty);
- }
- case NEON::BI__builtin_neon_vfma_lane_v:
- case NEON::BI__builtin_neon_vfmaq_lane_v: { // Only used for FP types
- // The ARM builtins (and instructions) have the addend as the first
- // operand, but the 'fma' intrinsics have it last. Swap it around here.
- Value *Addend = Ops[0];
- Value *Multiplicand = Ops[1];
- Value *LaneSource = Ops[2];
- Ops[0] = Multiplicand;
- Ops[1] = LaneSource;
- Ops[2] = Addend;
-
- // Now adjust things to handle the lane access.
- llvm::Type *SourceTy = BuiltinID == NEON::BI__builtin_neon_vfmaq_lane_v ?
- llvm::VectorType::get(VTy->getElementType(), VTy->getNumElements() / 2) :
- VTy;
- llvm::Constant *cst = cast<Constant>(Ops[3]);
- Value *SV = llvm::ConstantVector::getSplat(VTy->getNumElements(), cst);
- Ops[1] = Builder.CreateBitCast(Ops[1], SourceTy);
- Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV, "lane");
-
- Ops.pop_back();
- Int = Intrinsic::fma;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "fmla");
- }
- case NEON::BI__builtin_neon_vfma_laneq_v: {
- llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
- // v1f64 fma should be mapped to Neon scalar f64 fma
- if (VTy && VTy->getElementType() == DoubleTy) {
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
- llvm::Type *VTy = GetNeonType(this,
- NeonTypeFlags(NeonTypeFlags::Float64, false, true));
- Ops[2] = Builder.CreateBitCast(Ops[2], VTy);
- Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
- Value *F = CGM.getIntrinsic(Intrinsic::fma, DoubleTy);
- Value *Result = Builder.CreateCall(F, {Ops[1], Ops[2], Ops[0]});
- return Builder.CreateBitCast(Result, Ty);
- }
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
-
- llvm::Type *STy = llvm::VectorType::get(VTy->getElementType(),
- VTy->getNumElements() * 2);
- Ops[2] = Builder.CreateBitCast(Ops[2], STy);
- Value* SV = llvm::ConstantVector::getSplat(VTy->getNumElements(),
- cast<ConstantInt>(Ops[3]));
- Ops[2] = Builder.CreateShuffleVector(Ops[2], Ops[2], SV, "lane");
-
- return Builder.CreateCall(F, {Ops[2], Ops[1], Ops[0]});
- }
- case NEON::BI__builtin_neon_vfmaq_laneq_v: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
-
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]));
- return Builder.CreateCall(F, {Ops[2], Ops[1], Ops[0]});
- }
- case NEON::BI__builtin_neon_vfmah_lane_f16:
- case NEON::BI__builtin_neon_vfmas_lane_f32:
- case NEON::BI__builtin_neon_vfmah_laneq_f16:
- case NEON::BI__builtin_neon_vfmas_laneq_f32:
- case NEON::BI__builtin_neon_vfmad_lane_f64:
- case NEON::BI__builtin_neon_vfmad_laneq_f64: {
- Ops.push_back(EmitScalarExpr(E->getArg(3)));
- llvm::Type *Ty = ConvertType(E->getCallReturnType(getContext()));
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
- return Builder.CreateCall(F, {Ops[1], Ops[2], Ops[0]});
- }
- case NEON::BI__builtin_neon_vmull_v:
- // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
- Int = usgn ? Intrinsic::aarch64_neon_umull : Intrinsic::aarch64_neon_smull;
- if (Type.isPoly()) Int = Intrinsic::aarch64_neon_pmull;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
- case NEON::BI__builtin_neon_vmax_v:
- case NEON::BI__builtin_neon_vmaxq_v:
- // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
- Int = usgn ? Intrinsic::aarch64_neon_umax : Intrinsic::aarch64_neon_smax;
- if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmax;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmax");
- case NEON::BI__builtin_neon_vmaxh_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Int = Intrinsic::aarch64_neon_fmax;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vmax");
- }
- case NEON::BI__builtin_neon_vmin_v:
- case NEON::BI__builtin_neon_vminq_v:
- // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
- Int = usgn ? Intrinsic::aarch64_neon_umin : Intrinsic::aarch64_neon_smin;
- if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmin;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmin");
- case NEON::BI__builtin_neon_vminh_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Int = Intrinsic::aarch64_neon_fmin;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vmin");
- }
- case NEON::BI__builtin_neon_vabd_v:
- case NEON::BI__builtin_neon_vabdq_v:
- // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
- Int = usgn ? Intrinsic::aarch64_neon_uabd : Intrinsic::aarch64_neon_sabd;
- if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fabd;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vabd");
- case NEON::BI__builtin_neon_vpadal_v:
- case NEON::BI__builtin_neon_vpadalq_v: {
- unsigned ArgElts = VTy->getNumElements();
- llvm::IntegerType *EltTy = cast<IntegerType>(VTy->getElementType());
- unsigned BitWidth = EltTy->getBitWidth();
- llvm::Type *ArgTy = llvm::VectorType::get(
- llvm::IntegerType::get(getLLVMContext(), BitWidth/2), 2*ArgElts);
- llvm::Type* Tys[2] = { VTy, ArgTy };
- Int = usgn ? Intrinsic::aarch64_neon_uaddlp : Intrinsic::aarch64_neon_saddlp;
- SmallVector<llvm::Value*, 1> TmpOps;
- TmpOps.push_back(Ops[1]);
- Function *F = CGM.getIntrinsic(Int, Tys);
- llvm::Value *tmp = EmitNeonCall(F, TmpOps, "vpadal");
- llvm::Value *addend = Builder.CreateBitCast(Ops[0], tmp->getType());
- return Builder.CreateAdd(tmp, addend);
- }
- case NEON::BI__builtin_neon_vpmin_v:
- case NEON::BI__builtin_neon_vpminq_v:
- // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
- Int = usgn ? Intrinsic::aarch64_neon_uminp : Intrinsic::aarch64_neon_sminp;
- if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fminp;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmin");
- case NEON::BI__builtin_neon_vpmax_v:
- case NEON::BI__builtin_neon_vpmaxq_v:
- // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
- Int = usgn ? Intrinsic::aarch64_neon_umaxp : Intrinsic::aarch64_neon_smaxp;
- if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmaxp;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmax");
- case NEON::BI__builtin_neon_vminnm_v:
- case NEON::BI__builtin_neon_vminnmq_v:
- Int = Intrinsic::aarch64_neon_fminnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vminnm");
- case NEON::BI__builtin_neon_vminnmh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Int = Intrinsic::aarch64_neon_fminnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vminnm");
- case NEON::BI__builtin_neon_vmaxnm_v:
- case NEON::BI__builtin_neon_vmaxnmq_v:
- Int = Intrinsic::aarch64_neon_fmaxnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmaxnm");
- case NEON::BI__builtin_neon_vmaxnmh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- Int = Intrinsic::aarch64_neon_fmaxnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vmaxnm");
- case NEON::BI__builtin_neon_vrecpss_f32: {
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_frecps, FloatTy),
- Ops, "vrecps");
- }
- case NEON::BI__builtin_neon_vrecpsd_f64:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_frecps, DoubleTy),
- Ops, "vrecps");
- case NEON::BI__builtin_neon_vrecpsh_f16:
- Ops.push_back(EmitScalarExpr(E->getArg(1)));
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_frecps, HalfTy),
- Ops, "vrecps");
- case NEON::BI__builtin_neon_vqshrun_n_v:
- Int = Intrinsic::aarch64_neon_sqshrun;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrun_n");
- case NEON::BI__builtin_neon_vqrshrun_n_v:
- Int = Intrinsic::aarch64_neon_sqrshrun;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrun_n");
- case NEON::BI__builtin_neon_vqshrn_n_v:
- Int = usgn ? Intrinsic::aarch64_neon_uqshrn : Intrinsic::aarch64_neon_sqshrn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n");
- case NEON::BI__builtin_neon_vrshrn_n_v:
- Int = Intrinsic::aarch64_neon_rshrn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshrn_n");
- case NEON::BI__builtin_neon_vqrshrn_n_v:
- Int = usgn ? Intrinsic::aarch64_neon_uqrshrn : Intrinsic::aarch64_neon_sqrshrn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n");
- case NEON::BI__builtin_neon_vrndah_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::round;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrnda");
- }
- case NEON::BI__builtin_neon_vrnda_v:
- case NEON::BI__builtin_neon_vrndaq_v: {
- Int = Intrinsic::round;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnda");
- }
- case NEON::BI__builtin_neon_vrndih_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::nearbyint;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrndi");
- }
- case NEON::BI__builtin_neon_vrndmh_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::floor;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrndm");
- }
- case NEON::BI__builtin_neon_vrndm_v:
- case NEON::BI__builtin_neon_vrndmq_v: {
- Int = Intrinsic::floor;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndm");
- }
- case NEON::BI__builtin_neon_vrndnh_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::aarch64_neon_frintn;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrndn");
- }
- case NEON::BI__builtin_neon_vrndn_v:
- case NEON::BI__builtin_neon_vrndnq_v: {
- Int = Intrinsic::aarch64_neon_frintn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndn");
- }
- case NEON::BI__builtin_neon_vrndns_f32: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::aarch64_neon_frintn;
- return EmitNeonCall(CGM.getIntrinsic(Int, FloatTy), Ops, "vrndn");
- }
- case NEON::BI__builtin_neon_vrndph_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::ceil;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrndp");
- }
- case NEON::BI__builtin_neon_vrndp_v:
- case NEON::BI__builtin_neon_vrndpq_v: {
- Int = Intrinsic::ceil;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndp");
- }
- case NEON::BI__builtin_neon_vrndxh_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::rint;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrndx");
- }
- case NEON::BI__builtin_neon_vrndx_v:
- case NEON::BI__builtin_neon_vrndxq_v: {
- Int = Intrinsic::rint;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndx");
- }
- case NEON::BI__builtin_neon_vrndh_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::trunc;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrndz");
- }
- case NEON::BI__builtin_neon_vrnd_v:
- case NEON::BI__builtin_neon_vrndq_v: {
- Int = Intrinsic::trunc;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndz");
- }
- case NEON::BI__builtin_neon_vcvt_f64_v:
- case NEON::BI__builtin_neon_vcvtq_f64_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
- return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
- : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- case NEON::BI__builtin_neon_vcvt_f64_f32: {
- assert(Type.getEltType() == NeonTypeFlags::Float64 && quad &&
- "unexpected vcvt_f64_f32 builtin");
- NeonTypeFlags SrcFlag = NeonTypeFlags(NeonTypeFlags::Float32, false, false);
- Ops[0] = Builder.CreateBitCast(Ops[0], GetNeonType(this, SrcFlag));
-
- return Builder.CreateFPExt(Ops[0], Ty, "vcvt");
- }
- case NEON::BI__builtin_neon_vcvt_f32_f64: {
- assert(Type.getEltType() == NeonTypeFlags::Float32 &&
- "unexpected vcvt_f32_f64 builtin");
- NeonTypeFlags SrcFlag = NeonTypeFlags(NeonTypeFlags::Float64, false, true);
- Ops[0] = Builder.CreateBitCast(Ops[0], GetNeonType(this, SrcFlag));
-
- return Builder.CreateFPTrunc(Ops[0], Ty, "vcvt");
- }
- case NEON::BI__builtin_neon_vcvt_s32_v:
- case NEON::BI__builtin_neon_vcvt_u32_v:
- case NEON::BI__builtin_neon_vcvt_s64_v:
- case NEON::BI__builtin_neon_vcvt_u64_v:
- case NEON::BI__builtin_neon_vcvt_s16_v:
- case NEON::BI__builtin_neon_vcvt_u16_v:
- case NEON::BI__builtin_neon_vcvtq_s32_v:
- case NEON::BI__builtin_neon_vcvtq_u32_v:
- case NEON::BI__builtin_neon_vcvtq_s64_v:
- case NEON::BI__builtin_neon_vcvtq_u64_v:
- case NEON::BI__builtin_neon_vcvtq_s16_v:
- case NEON::BI__builtin_neon_vcvtq_u16_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type));
- if (usgn)
- return Builder.CreateFPToUI(Ops[0], Ty);
- return Builder.CreateFPToSI(Ops[0], Ty);
- }
- case NEON::BI__builtin_neon_vcvta_s16_v:
- case NEON::BI__builtin_neon_vcvta_u16_v:
- case NEON::BI__builtin_neon_vcvta_s32_v:
- case NEON::BI__builtin_neon_vcvtaq_s16_v:
- case NEON::BI__builtin_neon_vcvtaq_s32_v:
- case NEON::BI__builtin_neon_vcvta_u32_v:
- case NEON::BI__builtin_neon_vcvtaq_u16_v:
- case NEON::BI__builtin_neon_vcvtaq_u32_v:
- case NEON::BI__builtin_neon_vcvta_s64_v:
- case NEON::BI__builtin_neon_vcvtaq_s64_v:
- case NEON::BI__builtin_neon_vcvta_u64_v:
- case NEON::BI__builtin_neon_vcvtaq_u64_v: {
- Int = usgn ? Intrinsic::aarch64_neon_fcvtau : Intrinsic::aarch64_neon_fcvtas;
- llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvta");
- }
- case NEON::BI__builtin_neon_vcvtm_s16_v:
- case NEON::BI__builtin_neon_vcvtm_s32_v:
- case NEON::BI__builtin_neon_vcvtmq_s16_v:
- case NEON::BI__builtin_neon_vcvtmq_s32_v:
- case NEON::BI__builtin_neon_vcvtm_u16_v:
- case NEON::BI__builtin_neon_vcvtm_u32_v:
- case NEON::BI__builtin_neon_vcvtmq_u16_v:
- case NEON::BI__builtin_neon_vcvtmq_u32_v:
- case NEON::BI__builtin_neon_vcvtm_s64_v:
- case NEON::BI__builtin_neon_vcvtmq_s64_v:
- case NEON::BI__builtin_neon_vcvtm_u64_v:
- case NEON::BI__builtin_neon_vcvtmq_u64_v: {
- Int = usgn ? Intrinsic::aarch64_neon_fcvtmu : Intrinsic::aarch64_neon_fcvtms;
- llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtm");
- }
- case NEON::BI__builtin_neon_vcvtn_s16_v:
- case NEON::BI__builtin_neon_vcvtn_s32_v:
- case NEON::BI__builtin_neon_vcvtnq_s16_v:
- case NEON::BI__builtin_neon_vcvtnq_s32_v:
- case NEON::BI__builtin_neon_vcvtn_u16_v:
- case NEON::BI__builtin_neon_vcvtn_u32_v:
- case NEON::BI__builtin_neon_vcvtnq_u16_v:
- case NEON::BI__builtin_neon_vcvtnq_u32_v:
- case NEON::BI__builtin_neon_vcvtn_s64_v:
- case NEON::BI__builtin_neon_vcvtnq_s64_v:
- case NEON::BI__builtin_neon_vcvtn_u64_v:
- case NEON::BI__builtin_neon_vcvtnq_u64_v: {
- Int = usgn ? Intrinsic::aarch64_neon_fcvtnu : Intrinsic::aarch64_neon_fcvtns;
- llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtn");
- }
- case NEON::BI__builtin_neon_vcvtp_s16_v:
- case NEON::BI__builtin_neon_vcvtp_s32_v:
- case NEON::BI__builtin_neon_vcvtpq_s16_v:
- case NEON::BI__builtin_neon_vcvtpq_s32_v:
- case NEON::BI__builtin_neon_vcvtp_u16_v:
- case NEON::BI__builtin_neon_vcvtp_u32_v:
- case NEON::BI__builtin_neon_vcvtpq_u16_v:
- case NEON::BI__builtin_neon_vcvtpq_u32_v:
- case NEON::BI__builtin_neon_vcvtp_s64_v:
- case NEON::BI__builtin_neon_vcvtpq_s64_v:
- case NEON::BI__builtin_neon_vcvtp_u64_v:
- case NEON::BI__builtin_neon_vcvtpq_u64_v: {
- Int = usgn ? Intrinsic::aarch64_neon_fcvtpu : Intrinsic::aarch64_neon_fcvtps;
- llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtp");
- }
- case NEON::BI__builtin_neon_vmulx_v:
- case NEON::BI__builtin_neon_vmulxq_v: {
- Int = Intrinsic::aarch64_neon_fmulx;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmulx");
- }
- case NEON::BI__builtin_neon_vmulxh_lane_f16:
- case NEON::BI__builtin_neon_vmulxh_laneq_f16: {
- // vmulx_lane should be mapped to Neon scalar mulx after
- // extracting the scalar element
- Ops.push_back(EmitScalarExpr(E->getArg(2)));
- Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2], "extract");
- Ops.pop_back();
- Int = Intrinsic::aarch64_neon_fmulx;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vmulx");
- }
- case NEON::BI__builtin_neon_vmul_lane_v:
- case NEON::BI__builtin_neon_vmul_laneq_v: {
- // v1f64 vmul_lane should be mapped to Neon scalar mul lane
- bool Quad = false;
- if (BuiltinID == NEON::BI__builtin_neon_vmul_laneq_v)
- Quad = true;
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- llvm::Type *VTy = GetNeonType(this,
- NeonTypeFlags(NeonTypeFlags::Float64, false, Quad));
- Ops[1] = Builder.CreateBitCast(Ops[1], VTy);
- Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2], "extract");
- Value *Result = Builder.CreateFMul(Ops[0], Ops[1]);
- return Builder.CreateBitCast(Result, Ty);
- }
- case NEON::BI__builtin_neon_vnegd_s64:
- return Builder.CreateNeg(EmitScalarExpr(E->getArg(0)), "vnegd");
- case NEON::BI__builtin_neon_vnegh_f16:
- return Builder.CreateFNeg(EmitScalarExpr(E->getArg(0)), "vnegh");
- case NEON::BI__builtin_neon_vpmaxnm_v:
- case NEON::BI__builtin_neon_vpmaxnmq_v: {
- Int = Intrinsic::aarch64_neon_fmaxnmp;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmaxnm");
- }
- case NEON::BI__builtin_neon_vpminnm_v:
- case NEON::BI__builtin_neon_vpminnmq_v: {
- Int = Intrinsic::aarch64_neon_fminnmp;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpminnm");
- }
- case NEON::BI__builtin_neon_vsqrth_f16: {
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Int = Intrinsic::sqrt;
- return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vsqrt");
- }
- case NEON::BI__builtin_neon_vsqrt_v:
- case NEON::BI__builtin_neon_vsqrtq_v: {
- Int = Intrinsic::sqrt;
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqrt");
- }
- case NEON::BI__builtin_neon_vrbit_v:
- case NEON::BI__builtin_neon_vrbitq_v: {
- Int = Intrinsic::aarch64_neon_rbit;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrbit");
- }
- case NEON::BI__builtin_neon_vaddv_u8:
- // FIXME: These are handled by the AArch64 scalar code.
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vaddv_s8: {
- Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vaddv_u16:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vaddv_s16: {
- Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vaddvq_u8:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vaddvq_s8: {
- Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 16);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vaddvq_u16:
- usgn = true;
- LLVM_FALLTHROUGH;
- case NEON::BI__builtin_neon_vaddvq_s16: {
- Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vmaxv_u8: {
- Int = Intrinsic::aarch64_neon_umaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vmaxv_u16: {
- Int = Intrinsic::aarch64_neon_umaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vmaxvq_u8: {
- Int = Intrinsic::aarch64_neon_umaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 16);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vmaxvq_u16: {
- Int = Intrinsic::aarch64_neon_umaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vmaxv_s8: {
- Int = Intrinsic::aarch64_neon_smaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vmaxv_s16: {
- Int = Intrinsic::aarch64_neon_smaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vmaxvq_s8: {
- Int = Intrinsic::aarch64_neon_smaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 16);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vmaxvq_s16: {
- Int = Intrinsic::aarch64_neon_smaxv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vmaxv_f16: {
- Int = Intrinsic::aarch64_neon_fmaxv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vmaxvq_f16: {
- Int = Intrinsic::aarch64_neon_fmaxv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vminv_u8: {
- Int = Intrinsic::aarch64_neon_uminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vminv_u16: {
- Int = Intrinsic::aarch64_neon_uminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vminvq_u8: {
- Int = Intrinsic::aarch64_neon_uminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 16);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vminvq_u16: {
- Int = Intrinsic::aarch64_neon_uminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vminv_s8: {
- Int = Intrinsic::aarch64_neon_sminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vminv_s16: {
- Int = Intrinsic::aarch64_neon_sminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vminvq_s8: {
- Int = Intrinsic::aarch64_neon_sminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 16);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int8Ty);
- }
- case NEON::BI__builtin_neon_vminvq_s16: {
- Int = Intrinsic::aarch64_neon_sminv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vminv_f16: {
- Int = Intrinsic::aarch64_neon_fminv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vminvq_f16: {
- Int = Intrinsic::aarch64_neon_fminv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vmaxnmv_f16: {
- Int = Intrinsic::aarch64_neon_fmaxnmv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vmaxnmvq_f16: {
- Int = Intrinsic::aarch64_neon_fmaxnmv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vminnmv_f16: {
- Int = Intrinsic::aarch64_neon_fminnmv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vminnmvq_f16: {
- Int = Intrinsic::aarch64_neon_fminnmv;
- Ty = HalfTy;
- VTy = llvm::VectorType::get(HalfTy, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv");
- return Builder.CreateTrunc(Ops[0], HalfTy);
- }
- case NEON::BI__builtin_neon_vmul_n_f64: {
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- Value *RHS = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), DoubleTy);
- return Builder.CreateFMul(Ops[0], RHS);
- }
- case NEON::BI__builtin_neon_vaddlv_u8: {
- Int = Intrinsic::aarch64_neon_uaddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vaddlv_u16: {
- Int = Intrinsic::aarch64_neon_uaddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- }
- case NEON::BI__builtin_neon_vaddlvq_u8: {
- Int = Intrinsic::aarch64_neon_uaddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 16);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vaddlvq_u16: {
- Int = Intrinsic::aarch64_neon_uaddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- }
- case NEON::BI__builtin_neon_vaddlv_s8: {
- Int = Intrinsic::aarch64_neon_saddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vaddlv_s16: {
- Int = Intrinsic::aarch64_neon_saddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 4);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- }
- case NEON::BI__builtin_neon_vaddlvq_s8: {
- Int = Intrinsic::aarch64_neon_saddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int8Ty, 16);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- return Builder.CreateTrunc(Ops[0], Int16Ty);
- }
- case NEON::BI__builtin_neon_vaddlvq_s16: {
- Int = Intrinsic::aarch64_neon_saddlv;
- Ty = Int32Ty;
- VTy = llvm::VectorType::get(Int16Ty, 8);
- llvm::Type *Tys[2] = { Ty, VTy };
- Ops.push_back(EmitScalarExpr(E->getArg(0)));
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
- }
- case NEON::BI__builtin_neon_vsri_n_v:
- case NEON::BI__builtin_neon_vsriq_n_v: {
- Int = Intrinsic::aarch64_neon_vsri;
- llvm::Function *Intrin = CGM.getIntrinsic(Int, Ty);
- return EmitNeonCall(Intrin, Ops, "vsri_n");
- }
- case NEON::BI__builtin_neon_vsli_n_v:
- case NEON::BI__builtin_neon_vsliq_n_v: {
- Int = Intrinsic::aarch64_neon_vsli;
- llvm::Function *Intrin = CGM.getIntrinsic(Int, Ty);
- return EmitNeonCall(Intrin, Ops, "vsli_n");
- }
- case NEON::BI__builtin_neon_vsra_n_v:
- case NEON::BI__builtin_neon_vsraq_n_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = EmitNeonRShiftImm(Ops[1], Ops[2], Ty, usgn, "vsra_n");
- return Builder.CreateAdd(Ops[0], Ops[1]);
- case NEON::BI__builtin_neon_vrsra_n_v:
- case NEON::BI__builtin_neon_vrsraq_n_v: {
- Int = usgn ? Intrinsic::aarch64_neon_urshl : Intrinsic::aarch64_neon_srshl;
- SmallVector<llvm::Value*,2> TmpOps;
- TmpOps.push_back(Ops[1]);
- TmpOps.push_back(Ops[2]);
- Function* F = CGM.getIntrinsic(Int, Ty);
- llvm::Value *tmp = EmitNeonCall(F, TmpOps, "vrshr_n", 1, true);
- Ops[0] = Builder.CreateBitCast(Ops[0], VTy);
- return Builder.CreateAdd(Ops[0], tmp);
- }
- case NEON::BI__builtin_neon_vld1_v:
- case NEON::BI__builtin_neon_vld1q_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(VTy));
- auto Alignment = CharUnits::fromQuantity(
- BuiltinID == NEON::BI__builtin_neon_vld1_v ? 8 : 16);
- return Builder.CreateAlignedLoad(VTy, Ops[0], Alignment);
- }
- case NEON::BI__builtin_neon_vst1_v:
- case NEON::BI__builtin_neon_vst1q_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(VTy));
- Ops[1] = Builder.CreateBitCast(Ops[1], VTy);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- case NEON::BI__builtin_neon_vld1_lane_v:
- case NEON::BI__builtin_neon_vld1q_lane_v: {
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ty = llvm::PointerType::getUnqual(VTy->getElementType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- auto Alignment = CharUnits::fromQuantity(
- BuiltinID == NEON::BI__builtin_neon_vld1_lane_v ? 8 : 16);
- Ops[0] =
- Builder.CreateAlignedLoad(VTy->getElementType(), Ops[0], Alignment);
- return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vld1_lane");
- }
- case NEON::BI__builtin_neon_vld1_dup_v:
- case NEON::BI__builtin_neon_vld1q_dup_v: {
- Value *V = UndefValue::get(Ty);
- Ty = llvm::PointerType::getUnqual(VTy->getElementType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- auto Alignment = CharUnits::fromQuantity(
- BuiltinID == NEON::BI__builtin_neon_vld1_dup_v ? 8 : 16);
- Ops[0] =
- Builder.CreateAlignedLoad(VTy->getElementType(), Ops[0], Alignment);
- llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
- Ops[0] = Builder.CreateInsertElement(V, Ops[0], CI);
- return EmitNeonSplat(Ops[0], CI);
- }
- case NEON::BI__builtin_neon_vst1_lane_v:
- case NEON::BI__builtin_neon_vst1q_lane_v:
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- return Builder.CreateDefaultAlignedStore(Ops[1],
- Builder.CreateBitCast(Ops[0], Ty));
- case NEON::BI__builtin_neon_vld2_v:
- case NEON::BI__builtin_neon_vld2q_v: {
- llvm::Type *PTy = llvm::PointerType::getUnqual(VTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
- llvm::Type *Tys[2] = { VTy, PTy };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld2, Tys);
- Ops[1] = Builder.CreateCall(F, Ops[1], "vld2");
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld3_v:
- case NEON::BI__builtin_neon_vld3q_v: {
- llvm::Type *PTy = llvm::PointerType::getUnqual(VTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
- llvm::Type *Tys[2] = { VTy, PTy };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld3, Tys);
- Ops[1] = Builder.CreateCall(F, Ops[1], "vld3");
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld4_v:
- case NEON::BI__builtin_neon_vld4q_v: {
- llvm::Type *PTy = llvm::PointerType::getUnqual(VTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
- llvm::Type *Tys[2] = { VTy, PTy };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld4, Tys);
- Ops[1] = Builder.CreateCall(F, Ops[1], "vld4");
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld2_dup_v:
- case NEON::BI__builtin_neon_vld2q_dup_v: {
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(VTy->getElementType());
- Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
- llvm::Type *Tys[2] = { VTy, PTy };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld2r, Tys);
- Ops[1] = Builder.CreateCall(F, Ops[1], "vld2");
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld3_dup_v:
- case NEON::BI__builtin_neon_vld3q_dup_v: {
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(VTy->getElementType());
- Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
- llvm::Type *Tys[2] = { VTy, PTy };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld3r, Tys);
- Ops[1] = Builder.CreateCall(F, Ops[1], "vld3");
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld4_dup_v:
- case NEON::BI__builtin_neon_vld4q_dup_v: {
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(VTy->getElementType());
- Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
- llvm::Type *Tys[2] = { VTy, PTy };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld4r, Tys);
- Ops[1] = Builder.CreateCall(F, Ops[1], "vld4");
- Ops[0] = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld2_lane_v:
- case NEON::BI__builtin_neon_vld2q_lane_v: {
- llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld2lane, Tys);
- Ops.push_back(Ops[1]);
- Ops.erase(Ops.begin()+1);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Ops[3] = Builder.CreateZExt(Ops[3], Int64Ty);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane");
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld3_lane_v:
- case NEON::BI__builtin_neon_vld3q_lane_v: {
- llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld3lane, Tys);
- Ops.push_back(Ops[1]);
- Ops.erase(Ops.begin()+1);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
- Ops[4] = Builder.CreateZExt(Ops[4], Int64Ty);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vld4_lane_v:
- case NEON::BI__builtin_neon_vld4q_lane_v: {
- llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld4lane, Tys);
- Ops.push_back(Ops[1]);
- Ops.erase(Ops.begin()+1);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
- Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
- Ops[5] = Builder.CreateZExt(Ops[5], Int64Ty);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld4_lane");
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case NEON::BI__builtin_neon_vst2_v:
- case NEON::BI__builtin_neon_vst2q_v: {
- Ops.push_back(Ops[0]);
- Ops.erase(Ops.begin());
- llvm::Type *Tys[2] = { VTy, Ops[2]->getType() };
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st2, Tys),
- Ops, "");
- }
- case NEON::BI__builtin_neon_vst2_lane_v:
- case NEON::BI__builtin_neon_vst2q_lane_v: {
- Ops.push_back(Ops[0]);
- Ops.erase(Ops.begin());
- Ops[2] = Builder.CreateZExt(Ops[2], Int64Ty);
- llvm::Type *Tys[2] = { VTy, Ops[3]->getType() };
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st2lane, Tys),
- Ops, "");
- }
- case NEON::BI__builtin_neon_vst3_v:
- case NEON::BI__builtin_neon_vst3q_v: {
- Ops.push_back(Ops[0]);
- Ops.erase(Ops.begin());
- llvm::Type *Tys[2] = { VTy, Ops[3]->getType() };
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st3, Tys),
- Ops, "");
- }
- case NEON::BI__builtin_neon_vst3_lane_v:
- case NEON::BI__builtin_neon_vst3q_lane_v: {
- Ops.push_back(Ops[0]);
- Ops.erase(Ops.begin());
- Ops[3] = Builder.CreateZExt(Ops[3], Int64Ty);
- llvm::Type *Tys[2] = { VTy, Ops[4]->getType() };
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st3lane, Tys),
- Ops, "");
- }
- case NEON::BI__builtin_neon_vst4_v:
- case NEON::BI__builtin_neon_vst4q_v: {
- Ops.push_back(Ops[0]);
- Ops.erase(Ops.begin());
- llvm::Type *Tys[2] = { VTy, Ops[4]->getType() };
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st4, Tys),
- Ops, "");
- }
- case NEON::BI__builtin_neon_vst4_lane_v:
- case NEON::BI__builtin_neon_vst4q_lane_v: {
- Ops.push_back(Ops[0]);
- Ops.erase(Ops.begin());
- Ops[4] = Builder.CreateZExt(Ops[4], Int64Ty);
- llvm::Type *Tys[2] = { VTy, Ops[5]->getType() };
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st4lane, Tys),
- Ops, "");
- }
- case NEON::BI__builtin_neon_vtrn_v:
- case NEON::BI__builtin_neon_vtrnq_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = nullptr;
-
- for (unsigned vi = 0; vi != 2; ++vi) {
- SmallVector<uint32_t, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
- Indices.push_back(i+vi);
- Indices.push_back(i+e+vi);
- }
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
- SV = Builder.CreateShuffleVector(Ops[1], Ops[2], Indices, "vtrn");
- SV = Builder.CreateDefaultAlignedStore(SV, Addr);
- }
- return SV;
- }
- case NEON::BI__builtin_neon_vuzp_v:
- case NEON::BI__builtin_neon_vuzpq_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = nullptr;
-
- for (unsigned vi = 0; vi != 2; ++vi) {
- SmallVector<uint32_t, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
- Indices.push_back(2*i+vi);
-
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
- SV = Builder.CreateShuffleVector(Ops[1], Ops[2], Indices, "vuzp");
- SV = Builder.CreateDefaultAlignedStore(SV, Addr);
- }
- return SV;
- }
- case NEON::BI__builtin_neon_vzip_v:
- case NEON::BI__builtin_neon_vzipq_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = nullptr;
-
- for (unsigned vi = 0; vi != 2; ++vi) {
- SmallVector<uint32_t, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
- Indices.push_back((i + vi*e) >> 1);
- Indices.push_back(((i + vi*e) >> 1)+e);
- }
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
- SV = Builder.CreateShuffleVector(Ops[1], Ops[2], Indices, "vzip");
- SV = Builder.CreateDefaultAlignedStore(SV, Addr);
- }
- return SV;
- }
- case NEON::BI__builtin_neon_vqtbl1q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl1, Ty),
- Ops, "vtbl1");
- }
- case NEON::BI__builtin_neon_vqtbl2q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl2, Ty),
- Ops, "vtbl2");
- }
- case NEON::BI__builtin_neon_vqtbl3q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl3, Ty),
- Ops, "vtbl3");
- }
- case NEON::BI__builtin_neon_vqtbl4q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl4, Ty),
- Ops, "vtbl4");
- }
- case NEON::BI__builtin_neon_vqtbx1q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx1, Ty),
- Ops, "vtbx1");
- }
- case NEON::BI__builtin_neon_vqtbx2q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx2, Ty),
- Ops, "vtbx2");
- }
- case NEON::BI__builtin_neon_vqtbx3q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx3, Ty),
- Ops, "vtbx3");
- }
- case NEON::BI__builtin_neon_vqtbx4q_v: {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx4, Ty),
- Ops, "vtbx4");
- }
- case NEON::BI__builtin_neon_vsqadd_v:
- case NEON::BI__builtin_neon_vsqaddq_v: {
- Int = Intrinsic::aarch64_neon_usqadd;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqadd");
- }
- case NEON::BI__builtin_neon_vuqadd_v:
- case NEON::BI__builtin_neon_vuqaddq_v: {
- Int = Intrinsic::aarch64_neon_suqadd;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd");
- }
- case AArch64::BI__iso_volatile_load8:
- case AArch64::BI__iso_volatile_load16:
- case AArch64::BI__iso_volatile_load32:
- case AArch64::BI__iso_volatile_load64:
- return EmitISOVolatileLoad(E);
- case AArch64::BI__iso_volatile_store8:
- case AArch64::BI__iso_volatile_store16:
- case AArch64::BI__iso_volatile_store32:
- case AArch64::BI__iso_volatile_store64:
- return EmitISOVolatileStore(E);
- case AArch64::BI_BitScanForward:
- case AArch64::BI_BitScanForward64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E);
- case AArch64::BI_BitScanReverse:
- case AArch64::BI_BitScanReverse64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E);
- case AArch64::BI_InterlockedAnd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E);
- case AArch64::BI_InterlockedExchange64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E);
- case AArch64::BI_InterlockedExchangeAdd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E);
- case AArch64::BI_InterlockedExchangeSub64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E);
- case AArch64::BI_InterlockedOr64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E);
- case AArch64::BI_InterlockedXor64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E);
- case AArch64::BI_InterlockedDecrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E);
- case AArch64::BI_InterlockedIncrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E);
- case AArch64::BI_InterlockedExchangeAdd8_acq:
- case AArch64::BI_InterlockedExchangeAdd16_acq:
- case AArch64::BI_InterlockedExchangeAdd_acq:
- case AArch64::BI_InterlockedExchangeAdd64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_acq, E);
- case AArch64::BI_InterlockedExchangeAdd8_rel:
- case AArch64::BI_InterlockedExchangeAdd16_rel:
- case AArch64::BI_InterlockedExchangeAdd_rel:
- case AArch64::BI_InterlockedExchangeAdd64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_rel, E);
- case AArch64::BI_InterlockedExchangeAdd8_nf:
- case AArch64::BI_InterlockedExchangeAdd16_nf:
- case AArch64::BI_InterlockedExchangeAdd_nf:
- case AArch64::BI_InterlockedExchangeAdd64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_nf, E);
- case AArch64::BI_InterlockedExchange8_acq:
- case AArch64::BI_InterlockedExchange16_acq:
- case AArch64::BI_InterlockedExchange_acq:
- case AArch64::BI_InterlockedExchange64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_acq, E);
- case AArch64::BI_InterlockedExchange8_rel:
- case AArch64::BI_InterlockedExchange16_rel:
- case AArch64::BI_InterlockedExchange_rel:
- case AArch64::BI_InterlockedExchange64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_rel, E);
- case AArch64::BI_InterlockedExchange8_nf:
- case AArch64::BI_InterlockedExchange16_nf:
- case AArch64::BI_InterlockedExchange_nf:
- case AArch64::BI_InterlockedExchange64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_nf, E);
- case AArch64::BI_InterlockedCompareExchange8_acq:
- case AArch64::BI_InterlockedCompareExchange16_acq:
- case AArch64::BI_InterlockedCompareExchange_acq:
- case AArch64::BI_InterlockedCompareExchange64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_acq, E);
- case AArch64::BI_InterlockedCompareExchange8_rel:
- case AArch64::BI_InterlockedCompareExchange16_rel:
- case AArch64::BI_InterlockedCompareExchange_rel:
- case AArch64::BI_InterlockedCompareExchange64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_rel, E);
- case AArch64::BI_InterlockedCompareExchange8_nf:
- case AArch64::BI_InterlockedCompareExchange16_nf:
- case AArch64::BI_InterlockedCompareExchange_nf:
- case AArch64::BI_InterlockedCompareExchange64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_nf, E);
- case AArch64::BI_InterlockedOr8_acq:
- case AArch64::BI_InterlockedOr16_acq:
- case AArch64::BI_InterlockedOr_acq:
- case AArch64::BI_InterlockedOr64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_acq, E);
- case AArch64::BI_InterlockedOr8_rel:
- case AArch64::BI_InterlockedOr16_rel:
- case AArch64::BI_InterlockedOr_rel:
- case AArch64::BI_InterlockedOr64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_rel, E);
- case AArch64::BI_InterlockedOr8_nf:
- case AArch64::BI_InterlockedOr16_nf:
- case AArch64::BI_InterlockedOr_nf:
- case AArch64::BI_InterlockedOr64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_nf, E);
- case AArch64::BI_InterlockedXor8_acq:
- case AArch64::BI_InterlockedXor16_acq:
- case AArch64::BI_InterlockedXor_acq:
- case AArch64::BI_InterlockedXor64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_acq, E);
- case AArch64::BI_InterlockedXor8_rel:
- case AArch64::BI_InterlockedXor16_rel:
- case AArch64::BI_InterlockedXor_rel:
- case AArch64::BI_InterlockedXor64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_rel, E);
- case AArch64::BI_InterlockedXor8_nf:
- case AArch64::BI_InterlockedXor16_nf:
- case AArch64::BI_InterlockedXor_nf:
- case AArch64::BI_InterlockedXor64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_nf, E);
- case AArch64::BI_InterlockedAnd8_acq:
- case AArch64::BI_InterlockedAnd16_acq:
- case AArch64::BI_InterlockedAnd_acq:
- case AArch64::BI_InterlockedAnd64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_acq, E);
- case AArch64::BI_InterlockedAnd8_rel:
- case AArch64::BI_InterlockedAnd16_rel:
- case AArch64::BI_InterlockedAnd_rel:
- case AArch64::BI_InterlockedAnd64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_rel, E);
- case AArch64::BI_InterlockedAnd8_nf:
- case AArch64::BI_InterlockedAnd16_nf:
- case AArch64::BI_InterlockedAnd_nf:
- case AArch64::BI_InterlockedAnd64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_nf, E);
- case AArch64::BI_InterlockedIncrement16_acq:
- case AArch64::BI_InterlockedIncrement_acq:
- case AArch64::BI_InterlockedIncrement64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_acq, E);
- case AArch64::BI_InterlockedIncrement16_rel:
- case AArch64::BI_InterlockedIncrement_rel:
- case AArch64::BI_InterlockedIncrement64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_rel, E);
- case AArch64::BI_InterlockedIncrement16_nf:
- case AArch64::BI_InterlockedIncrement_nf:
- case AArch64::BI_InterlockedIncrement64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_nf, E);
- case AArch64::BI_InterlockedDecrement16_acq:
- case AArch64::BI_InterlockedDecrement_acq:
- case AArch64::BI_InterlockedDecrement64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_acq, E);
- case AArch64::BI_InterlockedDecrement16_rel:
- case AArch64::BI_InterlockedDecrement_rel:
- case AArch64::BI_InterlockedDecrement64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_rel, E);
- case AArch64::BI_InterlockedDecrement16_nf:
- case AArch64::BI_InterlockedDecrement_nf:
- case AArch64::BI_InterlockedDecrement64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_nf, E);
-
- case AArch64::BI_InterlockedAdd: {
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- Value *Arg1 = EmitScalarExpr(E->getArg(1));
- AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
- AtomicRMWInst::Add, Arg0, Arg1,
- llvm::AtomicOrdering::SequentiallyConsistent);
- return Builder.CreateAdd(RMWI, Arg1);
- }
- }
-}
-
-llvm::Value *CodeGenFunction::
-BuildVector(ArrayRef<llvm::Value*> Ops) {
- assert((Ops.size() & (Ops.size() - 1)) == 0 &&
- "Not a power-of-two sized vector!");
- bool AllConstants = true;
- for (unsigned i = 0, e = Ops.size(); i != e && AllConstants; ++i)
- AllConstants &= isa<Constant>(Ops[i]);
-
- // If this is a constant vector, create a ConstantVector.
- if (AllConstants) {
- SmallVector<llvm::Constant*, 16> CstOps;
- for (unsigned i = 0, e = Ops.size(); i != e; ++i)
- CstOps.push_back(cast<Constant>(Ops[i]));
- return llvm::ConstantVector::get(CstOps);
- }
-
- // Otherwise, insertelement the values to build the vector.
- Value *Result =
- llvm::UndefValue::get(llvm::VectorType::get(Ops[0]->getType(), Ops.size()));
-
- for (unsigned i = 0, e = Ops.size(); i != e; ++i)
- Result = Builder.CreateInsertElement(Result, Ops[i], Builder.getInt32(i));
-
- return Result;
-}
-
-// Convert the mask from an integer type to a vector of i1.
-static Value *getMaskVecValue(CodeGenFunction &CGF, Value *Mask,
- unsigned NumElts) {
-
- llvm::VectorType *MaskTy = llvm::VectorType::get(CGF.Builder.getInt1Ty(),
- cast<IntegerType>(Mask->getType())->getBitWidth());
- Value *MaskVec = CGF.Builder.CreateBitCast(Mask, MaskTy);
-
- // If we have less than 8 elements, then the starting mask was an i8 and
- // we need to extract down to the right number of elements.
- if (NumElts < 8) {
- uint32_t Indices[4];
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = i;
- MaskVec = CGF.Builder.CreateShuffleVector(MaskVec, MaskVec,
- makeArrayRef(Indices, NumElts),
- "extract");
- }
- return MaskVec;
-}
-
-static Value *EmitX86MaskedStore(CodeGenFunction &CGF,
- ArrayRef<Value *> Ops,
- unsigned Align) {
- // Cast the pointer to right type.
- Value *Ptr = CGF.Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
-
- Value *MaskVec = getMaskVecValue(CGF, Ops[2],
- Ops[1]->getType()->getVectorNumElements());
-
- return CGF.Builder.CreateMaskedStore(Ops[1], Ptr, Align, MaskVec);
-}
-
-static Value *EmitX86MaskedLoad(CodeGenFunction &CGF,
- ArrayRef<Value *> Ops, unsigned Align) {
- // Cast the pointer to right type.
- Value *Ptr = CGF.Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(Ops[1]->getType()));
-
- Value *MaskVec = getMaskVecValue(CGF, Ops[2],
- Ops[1]->getType()->getVectorNumElements());
-
- return CGF.Builder.CreateMaskedLoad(Ptr, Align, MaskVec, Ops[1]);
-}
-
-static Value *EmitX86ExpandLoad(CodeGenFunction &CGF,
- ArrayRef<Value *> Ops) {
- llvm::Type *ResultTy = Ops[1]->getType();
- llvm::Type *PtrTy = ResultTy->getVectorElementType();
-
- // Cast the pointer to element type.
- Value *Ptr = CGF.Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(PtrTy));
-
- Value *MaskVec = getMaskVecValue(CGF, Ops[2],
- ResultTy->getVectorNumElements());
-
- llvm::Function *F = CGF.CGM.getIntrinsic(Intrinsic::masked_expandload,
- ResultTy);
- return CGF.Builder.CreateCall(F, { Ptr, MaskVec, Ops[1] });
-}
-
-static Value *EmitX86CompressStore(CodeGenFunction &CGF,
- ArrayRef<Value *> Ops) {
- llvm::Type *ResultTy = Ops[1]->getType();
- llvm::Type *PtrTy = ResultTy->getVectorElementType();
-
- // Cast the pointer to element type.
- Value *Ptr = CGF.Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(PtrTy));
-
- Value *MaskVec = getMaskVecValue(CGF, Ops[2],
- ResultTy->getVectorNumElements());
-
- llvm::Function *F = CGF.CGM.getIntrinsic(Intrinsic::masked_compressstore,
- ResultTy);
- return CGF.Builder.CreateCall(F, { Ops[1], Ptr, MaskVec });
-}
-
-static Value *EmitX86MaskLogic(CodeGenFunction &CGF, Instruction::BinaryOps Opc,
- ArrayRef<Value *> Ops,
- bool InvertLHS = false) {
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
- Value *LHS = getMaskVecValue(CGF, Ops[0], NumElts);
- Value *RHS = getMaskVecValue(CGF, Ops[1], NumElts);
-
- if (InvertLHS)
- LHS = CGF.Builder.CreateNot(LHS);
-
- return CGF.Builder.CreateBitCast(CGF.Builder.CreateBinOp(Opc, LHS, RHS),
- Ops[0]->getType());
-}
-
-static Value *EmitX86FunnelShift(CodeGenFunction &CGF, Value *Op0, Value *Op1,
- Value *Amt, bool IsRight) {
- llvm::Type *Ty = Op0->getType();
-
- // Amount may be scalar immediate, in which case create a splat vector.
- // Funnel shifts amounts are treated as modulo and types are all power-of-2 so
- // we only care about the lowest log2 bits anyway.
- if (Amt->getType() != Ty) {
- unsigned NumElts = Ty->getVectorNumElements();
- Amt = CGF.Builder.CreateIntCast(Amt, Ty->getScalarType(), false);
- Amt = CGF.Builder.CreateVectorSplat(NumElts, Amt);
- }
-
- unsigned IID = IsRight ? Intrinsic::fshr : Intrinsic::fshl;
- Value *F = CGF.CGM.getIntrinsic(IID, Ty);
- return CGF.Builder.CreateCall(F, {Op0, Op1, Amt});
-}
-
-static Value *EmitX86Select(CodeGenFunction &CGF,
- Value *Mask, Value *Op0, Value *Op1) {
-
- // If the mask is all ones just return first argument.
- if (const auto *C = dyn_cast<Constant>(Mask))
- if (C->isAllOnesValue())
- return Op0;
-
- Mask = getMaskVecValue(CGF, Mask, Op0->getType()->getVectorNumElements());
-
- return CGF.Builder.CreateSelect(Mask, Op0, Op1);
-}
-
-static Value *EmitX86ScalarSelect(CodeGenFunction &CGF,
- Value *Mask, Value *Op0, Value *Op1) {
- // If the mask is all ones just return first argument.
- if (const auto *C = dyn_cast<Constant>(Mask))
- if (C->isAllOnesValue())
- return Op0;
-
- llvm::VectorType *MaskTy =
- llvm::VectorType::get(CGF.Builder.getInt1Ty(),
- Mask->getType()->getIntegerBitWidth());
- Mask = CGF.Builder.CreateBitCast(Mask, MaskTy);
- Mask = CGF.Builder.CreateExtractElement(Mask, (uint64_t)0);
- return CGF.Builder.CreateSelect(Mask, Op0, Op1);
-}
-
-static Value *EmitX86MaskedCompareResult(CodeGenFunction &CGF, Value *Cmp,
- unsigned NumElts, Value *MaskIn) {
- if (MaskIn) {
- const auto *C = dyn_cast<Constant>(MaskIn);
- if (!C || !C->isAllOnesValue())
- Cmp = CGF.Builder.CreateAnd(Cmp, getMaskVecValue(CGF, MaskIn, NumElts));
- }
-
- if (NumElts < 8) {
- uint32_t Indices[8];
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = i;
- for (unsigned i = NumElts; i != 8; ++i)
- Indices[i] = i % NumElts + NumElts;
- Cmp = CGF.Builder.CreateShuffleVector(
- Cmp, llvm::Constant::getNullValue(Cmp->getType()), Indices);
- }
-
- return CGF.Builder.CreateBitCast(Cmp,
- IntegerType::get(CGF.getLLVMContext(),
- std::max(NumElts, 8U)));
-}
-
-static Value *EmitX86MaskedCompare(CodeGenFunction &CGF, unsigned CC,
- bool Signed, ArrayRef<Value *> Ops) {
- assert((Ops.size() == 2 || Ops.size() == 4) &&
- "Unexpected number of arguments");
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- Value *Cmp;
-
- if (CC == 3) {
- Cmp = Constant::getNullValue(
- llvm::VectorType::get(CGF.Builder.getInt1Ty(), NumElts));
- } else if (CC == 7) {
- Cmp = Constant::getAllOnesValue(
- llvm::VectorType::get(CGF.Builder.getInt1Ty(), NumElts));
- } else {
- ICmpInst::Predicate Pred;
- switch (CC) {
- default: llvm_unreachable("Unknown condition code");
- case 0: Pred = ICmpInst::ICMP_EQ; break;
- case 1: Pred = Signed ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT; break;
- case 2: Pred = Signed ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; break;
- case 4: Pred = ICmpInst::ICMP_NE; break;
- case 5: Pred = Signed ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE; break;
- case 6: Pred = Signed ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT; break;
- }
- Cmp = CGF.Builder.CreateICmp(Pred, Ops[0], Ops[1]);
- }
-
- Value *MaskIn = nullptr;
- if (Ops.size() == 4)
- MaskIn = Ops[3];
-
- return EmitX86MaskedCompareResult(CGF, Cmp, NumElts, MaskIn);
-}
-
-static Value *EmitX86ConvertToMask(CodeGenFunction &CGF, Value *In) {
- Value *Zero = Constant::getNullValue(In->getType());
- return EmitX86MaskedCompare(CGF, 1, true, { In, Zero });
-}
-
-static Value *EmitX86Abs(CodeGenFunction &CGF, ArrayRef<Value *> Ops) {
-
- llvm::Type *Ty = Ops[0]->getType();
- Value *Zero = llvm::Constant::getNullValue(Ty);
- Value *Sub = CGF.Builder.CreateSub(Zero, Ops[0]);
- Value *Cmp = CGF.Builder.CreateICmp(ICmpInst::ICMP_SGT, Ops[0], Zero);
- Value *Res = CGF.Builder.CreateSelect(Cmp, Ops[0], Sub);
- return Res;
-}
-
-static Value *EmitX86MinMax(CodeGenFunction &CGF, ICmpInst::Predicate Pred,
- ArrayRef<Value *> Ops) {
- Value *Cmp = CGF.Builder.CreateICmp(Pred, Ops[0], Ops[1]);
- Value *Res = CGF.Builder.CreateSelect(Cmp, Ops[0], Ops[1]);
-
- assert(Ops.size() == 2);
- return Res;
-}
-
-// Lowers X86 FMA intrinsics to IR.
-static Value *EmitX86FMAExpr(CodeGenFunction &CGF, ArrayRef<Value *> Ops,
- unsigned BuiltinID, bool IsAddSub) {
-
- bool Subtract = false;
- Intrinsic::ID IID = Intrinsic::not_intrinsic;
- switch (BuiltinID) {
- default: break;
- case clang::X86::BI__builtin_ia32_vfmsubps512_mask3:
- Subtract = true;
- LLVM_FALLTHROUGH;
- case clang::X86::BI__builtin_ia32_vfmaddps512_mask:
- case clang::X86::BI__builtin_ia32_vfmaddps512_maskz:
- case clang::X86::BI__builtin_ia32_vfmaddps512_mask3:
- IID = llvm::Intrinsic::x86_avx512_vfmadd_ps_512; break;
- case clang::X86::BI__builtin_ia32_vfmsubpd512_mask3:
- Subtract = true;
- LLVM_FALLTHROUGH;
- case clang::X86::BI__builtin_ia32_vfmaddpd512_mask:
- case clang::X86::BI__builtin_ia32_vfmaddpd512_maskz:
- case clang::X86::BI__builtin_ia32_vfmaddpd512_mask3:
- IID = llvm::Intrinsic::x86_avx512_vfmadd_pd_512; break;
- case clang::X86::BI__builtin_ia32_vfmsubaddps512_mask3:
- Subtract = true;
- LLVM_FALLTHROUGH;
- case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask:
- case clang::X86::BI__builtin_ia32_vfmaddsubps512_maskz:
- case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask3:
- IID = llvm::Intrinsic::x86_avx512_vfmaddsub_ps_512;
- break;
- case clang::X86::BI__builtin_ia32_vfmsubaddpd512_mask3:
- Subtract = true;
- LLVM_FALLTHROUGH;
- case clang::X86::BI__builtin_ia32_vfmaddsubpd512_mask:
- case clang::X86::BI__builtin_ia32_vfmaddsubpd512_maskz:
- case clang::X86::BI__builtin_ia32_vfmaddsubpd512_mask3:
- IID = llvm::Intrinsic::x86_avx512_vfmaddsub_pd_512;
- break;
- }
-
- Value *A = Ops[0];
- Value *B = Ops[1];
- Value *C = Ops[2];
-
- if (Subtract)
- C = CGF.Builder.CreateFNeg(C);
-
- Value *Res;
-
- // Only handle in case of _MM_FROUND_CUR_DIRECTION/4 (no rounding).
- if (IID != Intrinsic::not_intrinsic &&
- cast<llvm::ConstantInt>(Ops.back())->getZExtValue() != (uint64_t)4) {
- Function *Intr = CGF.CGM.getIntrinsic(IID);
- Res = CGF.Builder.CreateCall(Intr, {A, B, C, Ops.back() });
- } else {
- llvm::Type *Ty = A->getType();
- Function *FMA = CGF.CGM.getIntrinsic(Intrinsic::fma, Ty);
- Res = CGF.Builder.CreateCall(FMA, {A, B, C} );
-
- if (IsAddSub) {
- // Negate even elts in C using a mask.
- unsigned NumElts = Ty->getVectorNumElements();
- SmallVector<uint32_t, 16> Indices(NumElts);
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = i + (i % 2) * NumElts;
-
- Value *NegC = CGF.Builder.CreateFNeg(C);
- Value *FMSub = CGF.Builder.CreateCall(FMA, {A, B, NegC} );
- Res = CGF.Builder.CreateShuffleVector(FMSub, Res, Indices);
- }
- }
-
- // Handle any required masking.
- Value *MaskFalseVal = nullptr;
- switch (BuiltinID) {
- case clang::X86::BI__builtin_ia32_vfmaddps512_mask:
- case clang::X86::BI__builtin_ia32_vfmaddpd512_mask:
- case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask:
- case clang::X86::BI__builtin_ia32_vfmaddsubpd512_mask:
- MaskFalseVal = Ops[0];
- break;
- case clang::X86::BI__builtin_ia32_vfmaddps512_maskz:
- case clang::X86::BI__builtin_ia32_vfmaddpd512_maskz:
- case clang::X86::BI__builtin_ia32_vfmaddsubps512_maskz:
- case clang::X86::BI__builtin_ia32_vfmaddsubpd512_maskz:
- MaskFalseVal = Constant::getNullValue(Ops[0]->getType());
- break;
- case clang::X86::BI__builtin_ia32_vfmsubps512_mask3:
- case clang::X86::BI__builtin_ia32_vfmaddps512_mask3:
- case clang::X86::BI__builtin_ia32_vfmsubpd512_mask3:
- case clang::X86::BI__builtin_ia32_vfmaddpd512_mask3:
- case clang::X86::BI__builtin_ia32_vfmsubaddps512_mask3:
- case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask3:
- case clang::X86::BI__builtin_ia32_vfmsubaddpd512_mask3:
- case clang::X86::BI__builtin_ia32_vfmaddsubpd512_mask3:
- MaskFalseVal = Ops[2];
- break;
- }
-
- if (MaskFalseVal)
- return EmitX86Select(CGF, Ops[3], Res, MaskFalseVal);
-
- return Res;
-}
-
-static Value *
-EmitScalarFMAExpr(CodeGenFunction &CGF, MutableArrayRef<Value *> Ops,
- Value *Upper, bool ZeroMask = false, unsigned PTIdx = 0,
- bool NegAcc = false) {
- unsigned Rnd = 4;
- if (Ops.size() > 4)
- Rnd = cast<llvm::ConstantInt>(Ops[4])->getZExtValue();
-
- if (NegAcc)
- Ops[2] = CGF.Builder.CreateFNeg(Ops[2]);
-
- Ops[0] = CGF.Builder.CreateExtractElement(Ops[0], (uint64_t)0);
- Ops[1] = CGF.Builder.CreateExtractElement(Ops[1], (uint64_t)0);
- Ops[2] = CGF.Builder.CreateExtractElement(Ops[2], (uint64_t)0);
- Value *Res;
- if (Rnd != 4) {
- Intrinsic::ID IID = Ops[0]->getType()->getPrimitiveSizeInBits() == 32 ?
- Intrinsic::x86_avx512_vfmadd_f32 :
- Intrinsic::x86_avx512_vfmadd_f64;
- Res = CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(IID),
- {Ops[0], Ops[1], Ops[2], Ops[4]});
- } else {
- Function *FMA = CGF.CGM.getIntrinsic(Intrinsic::fma, Ops[0]->getType());
- Res = CGF.Builder.CreateCall(FMA, Ops.slice(0, 3));
- }
- // If we have more than 3 arguments, we need to do masking.
- if (Ops.size() > 3) {
- Value *PassThru = ZeroMask ? Constant::getNullValue(Res->getType())
- : Ops[PTIdx];
-
- // If we negated the accumulator and the its the PassThru value we need to
- // bypass the negate. Conveniently Upper should be the same thing in this
- // case.
- if (NegAcc && PTIdx == 2)
- PassThru = CGF.Builder.CreateExtractElement(Upper, (uint64_t)0);
-
- Res = EmitX86ScalarSelect(CGF, Ops[3], Res, PassThru);
- }
- return CGF.Builder.CreateInsertElement(Upper, Res, (uint64_t)0);
-}
-
-static Value *EmitX86Muldq(CodeGenFunction &CGF, bool IsSigned,
- ArrayRef<Value *> Ops) {
- llvm::Type *Ty = Ops[0]->getType();
- // Arguments have a vXi32 type so cast to vXi64.
- Ty = llvm::VectorType::get(CGF.Int64Ty,
- Ty->getPrimitiveSizeInBits() / 64);
- Value *LHS = CGF.Builder.CreateBitCast(Ops[0], Ty);
- Value *RHS = CGF.Builder.CreateBitCast(Ops[1], Ty);
-
- if (IsSigned) {
- // Shift left then arithmetic shift right.
- Constant *ShiftAmt = ConstantInt::get(Ty, 32);
- LHS = CGF.Builder.CreateShl(LHS, ShiftAmt);
- LHS = CGF.Builder.CreateAShr(LHS, ShiftAmt);
- RHS = CGF.Builder.CreateShl(RHS, ShiftAmt);
- RHS = CGF.Builder.CreateAShr(RHS, ShiftAmt);
- } else {
- // Clear the upper bits.
- Constant *Mask = ConstantInt::get(Ty, 0xffffffff);
- LHS = CGF.Builder.CreateAnd(LHS, Mask);
- RHS = CGF.Builder.CreateAnd(RHS, Mask);
- }
-
- return CGF.Builder.CreateMul(LHS, RHS);
-}
-
-// Emit a masked pternlog intrinsic. This only exists because the header has to
-// use a macro and we aren't able to pass the input argument to a pternlog
-// builtin and a select builtin without evaluating it twice.
-static Value *EmitX86Ternlog(CodeGenFunction &CGF, bool ZeroMask,
- ArrayRef<Value *> Ops) {
- llvm::Type *Ty = Ops[0]->getType();
-
- unsigned VecWidth = Ty->getPrimitiveSizeInBits();
- unsigned EltWidth = Ty->getScalarSizeInBits();
- Intrinsic::ID IID;
- if (VecWidth == 128 && EltWidth == 32)
- IID = Intrinsic::x86_avx512_pternlog_d_128;
- else if (VecWidth == 256 && EltWidth == 32)
- IID = Intrinsic::x86_avx512_pternlog_d_256;
- else if (VecWidth == 512 && EltWidth == 32)
- IID = Intrinsic::x86_avx512_pternlog_d_512;
- else if (VecWidth == 128 && EltWidth == 64)
- IID = Intrinsic::x86_avx512_pternlog_q_128;
- else if (VecWidth == 256 && EltWidth == 64)
- IID = Intrinsic::x86_avx512_pternlog_q_256;
- else if (VecWidth == 512 && EltWidth == 64)
- IID = Intrinsic::x86_avx512_pternlog_q_512;
- else
- llvm_unreachable("Unexpected intrinsic");
-
- Value *Ternlog = CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(IID),
- Ops.drop_back());
- Value *PassThru = ZeroMask ? ConstantAggregateZero::get(Ty) : Ops[0];
- return EmitX86Select(CGF, Ops[4], Ternlog, PassThru);
-}
-
-static Value *EmitX86SExtMask(CodeGenFunction &CGF, Value *Op,
- llvm::Type *DstTy) {
- unsigned NumberOfElements = DstTy->getVectorNumElements();
- Value *Mask = getMaskVecValue(CGF, Op, NumberOfElements);
- return CGF.Builder.CreateSExt(Mask, DstTy, "vpmovm2");
-}
-
-// Emit addition or subtraction with signed/unsigned saturation.
-static Value *EmitX86AddSubSatExpr(CodeGenFunction &CGF,
- ArrayRef<Value *> Ops, bool IsSigned,
- bool IsAddition) {
- Intrinsic::ID IID =
- IsSigned ? (IsAddition ? Intrinsic::sadd_sat : Intrinsic::ssub_sat)
- : (IsAddition ? Intrinsic::uadd_sat : Intrinsic::usub_sat);
- llvm::Function *F = CGF.CGM.getIntrinsic(IID, Ops[0]->getType());
- return CGF.Builder.CreateCall(F, {Ops[0], Ops[1]});
-}
-
-Value *CodeGenFunction::EmitX86CpuIs(const CallExpr *E) {
- const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
- StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
- return EmitX86CpuIs(CPUStr);
-}
-
-Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) {
-
- llvm::Type *Int32Ty = Builder.getInt32Ty();
-
- // Matching the struct layout from the compiler-rt/libgcc structure that is
- // filled in:
- // unsigned int __cpu_vendor;
- // unsigned int __cpu_type;
- // unsigned int __cpu_subtype;
- // unsigned int __cpu_features[1];
- llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty,
- llvm::ArrayType::get(Int32Ty, 1));
-
- // Grab the global __cpu_model.
- llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model");
- cast<llvm::GlobalValue>(CpuModel)->setDSOLocal(true);
-
- // Calculate the index needed to access the correct field based on the
- // range. Also adjust the expected value.
- unsigned Index;
- unsigned Value;
- std::tie(Index, Value) = StringSwitch<std::pair<unsigned, unsigned>>(CPUStr)
-#define X86_VENDOR(ENUM, STRING) \
- .Case(STRING, {0u, static_cast<unsigned>(llvm::X86::ENUM)})
-#define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) \
- .Cases(STR, ALIAS, {1u, static_cast<unsigned>(llvm::X86::ENUM)})
-#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) \
- .Case(STR, {1u, static_cast<unsigned>(llvm::X86::ENUM)})
-#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) \
- .Case(STR, {2u, static_cast<unsigned>(llvm::X86::ENUM)})
-#include "llvm/Support/X86TargetParser.def"
- .Default({0, 0});
- assert(Value != 0 && "Invalid CPUStr passed to CpuIs");
-
- // Grab the appropriate field from __cpu_model.
- llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0),
- ConstantInt::get(Int32Ty, Index)};
- llvm::Value *CpuValue = Builder.CreateGEP(STy, CpuModel, Idxs);
- CpuValue = Builder.CreateAlignedLoad(CpuValue, CharUnits::fromQuantity(4));
-
- // Check the value of the field against the requested value.
- return Builder.CreateICmpEQ(CpuValue,
- llvm::ConstantInt::get(Int32Ty, Value));
-}
-
-Value *CodeGenFunction::EmitX86CpuSupports(const CallExpr *E) {
- const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
- StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
- return EmitX86CpuSupports(FeatureStr);
-}
-
-uint64_t
-CodeGenFunction::GetX86CpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
- // Processor features and mapping to processor feature value.
- uint64_t FeaturesMask = 0;
- for (const StringRef &FeatureStr : FeatureStrs) {
- unsigned Feature =
- StringSwitch<unsigned>(FeatureStr)
-#define X86_FEATURE_COMPAT(VAL, ENUM, STR) .Case(STR, VAL)
-#include "llvm/Support/X86TargetParser.def"
- ;
- FeaturesMask |= (1ULL << Feature);
- }
- return FeaturesMask;
-}
-
-Value *CodeGenFunction::EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs) {
- return EmitX86CpuSupports(GetX86CpuSupportsMask(FeatureStrs));
-}
-
-llvm::Value *CodeGenFunction::EmitX86CpuSupports(uint64_t FeaturesMask) {
- uint32_t Features1 = Lo_32(FeaturesMask);
- uint32_t Features2 = Hi_32(FeaturesMask);
-
- Value *Result = Builder.getTrue();
-
- if (Features1 != 0) {
- // Matching the struct layout from the compiler-rt/libgcc structure that is
- // filled in:
- // unsigned int __cpu_vendor;
- // unsigned int __cpu_type;
- // unsigned int __cpu_subtype;
- // unsigned int __cpu_features[1];
- llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty,
- llvm::ArrayType::get(Int32Ty, 1));
-
- // Grab the global __cpu_model.
- llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model");
- cast<llvm::GlobalValue>(CpuModel)->setDSOLocal(true);
-
- // Grab the first (0th) element from the field __cpu_features off of the
- // global in the struct STy.
- Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(3),
- Builder.getInt32(0)};
- Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs);
- Value *Features =
- Builder.CreateAlignedLoad(CpuFeatures, CharUnits::fromQuantity(4));
-
- // Check the value of the bit corresponding to the feature requested.
- Value *Mask = Builder.getInt32(Features1);
- Value *Bitset = Builder.CreateAnd(Features, Mask);
- Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
- Result = Builder.CreateAnd(Result, Cmp);
- }
-
- if (Features2 != 0) {
- llvm::Constant *CpuFeatures2 = CGM.CreateRuntimeVariable(Int32Ty,
- "__cpu_features2");
- cast<llvm::GlobalValue>(CpuFeatures2)->setDSOLocal(true);
-
- Value *Features =
- Builder.CreateAlignedLoad(CpuFeatures2, CharUnits::fromQuantity(4));
-
- // Check the value of the bit corresponding to the feature requested.
- Value *Mask = Builder.getInt32(Features2);
- Value *Bitset = Builder.CreateAnd(Features, Mask);
- Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
- Result = Builder.CreateAnd(Result, Cmp);
- }
-
- return Result;
-}
-
-Value *CodeGenFunction::EmitX86CpuInit() {
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
- /*Variadic*/ false);
- llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, "__cpu_indicator_init");
- cast<llvm::GlobalValue>(Func)->setDSOLocal(true);
- cast<llvm::GlobalValue>(Func)->setDLLStorageClass(
- llvm::GlobalValue::DefaultStorageClass);
- return Builder.CreateCall(Func);
-}
-
-Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- if (BuiltinID == X86::BI__builtin_cpu_is)
- return EmitX86CpuIs(E);
- if (BuiltinID == X86::BI__builtin_cpu_supports)
- return EmitX86CpuSupports(E);
- if (BuiltinID == X86::BI__builtin_cpu_init)
- return EmitX86CpuInit();
-
- SmallVector<Value*, 4> Ops;
-
- // Find out if any arguments are required to be integer constant expressions.
- unsigned ICEArguments = 0;
- ASTContext::GetBuiltinTypeError Error;
- getContext().GetBuiltinType(BuiltinID, Error, &ICEArguments);
- assert(Error == ASTContext::GE_None && "Should not codegen an error");
-
- for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
- // If this is a normal argument, just emit it as a scalar.
- if ((ICEArguments & (1 << i)) == 0) {
- Ops.push_back(EmitScalarExpr(E->getArg(i)));
- continue;
- }
-
- // If this is required to be a constant, constant fold it so that we know
- // that the generated intrinsic gets a ConstantInt.
- llvm::APSInt Result;
- bool IsConst = E->getArg(i)->isIntegerConstantExpr(Result, getContext());
- assert(IsConst && "Constant arg isn't actually constant?"); (void)IsConst;
- Ops.push_back(llvm::ConstantInt::get(getLLVMContext(), Result));
- }
-
- // These exist so that the builtin that takes an immediate can be bounds
- // checked by clang to avoid passing bad immediates to the backend. Since
- // AVX has a larger immediate than SSE we would need separate builtins to
- // do the different bounds checking. Rather than create a clang specific
- // SSE only builtin, this implements eight separate builtins to match gcc
- // implementation.
- auto getCmpIntrinsicCall = [this, &Ops](Intrinsic::ID ID, unsigned Imm) {
- Ops.push_back(llvm::ConstantInt::get(Int8Ty, Imm));
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops);
- };
-
- // For the vector forms of FP comparisons, translate the builtins directly to
- // IR.
- // TODO: The builtins could be removed if the SSE header files used vector
- // extension comparisons directly (vector ordered/unordered may need
- // additional support via __builtin_isnan()).
- auto getVectorFCmpIR = [this, &Ops](CmpInst::Predicate Pred) {
- Value *Cmp = Builder.CreateFCmp(Pred, Ops[0], Ops[1]);
- llvm::VectorType *FPVecTy = cast<llvm::VectorType>(Ops[0]->getType());
- llvm::VectorType *IntVecTy = llvm::VectorType::getInteger(FPVecTy);
- Value *Sext = Builder.CreateSExt(Cmp, IntVecTy);
- return Builder.CreateBitCast(Sext, FPVecTy);
- };
-
- switch (BuiltinID) {
- default: return nullptr;
- case X86::BI_mm_prefetch: {
- Value *Address = Ops[0];
- ConstantInt *C = cast<ConstantInt>(Ops[1]);
- Value *RW = ConstantInt::get(Int32Ty, (C->getZExtValue() >> 2) & 0x1);
- Value *Locality = ConstantInt::get(Int32Ty, C->getZExtValue() & 0x3);
- Value *Data = ConstantInt::get(Int32Ty, 1);
- Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
- return Builder.CreateCall(F, {Address, RW, Locality, Data});
- }
- case X86::BI_mm_clflush: {
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse2_clflush),
- Ops[0]);
- }
- case X86::BI_mm_lfence: {
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse2_lfence));
- }
- case X86::BI_mm_mfence: {
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse2_mfence));
- }
- case X86::BI_mm_sfence: {
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_sfence));
- }
- case X86::BI_mm_pause: {
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse2_pause));
- }
- case X86::BI__rdtsc: {
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_rdtsc));
- }
- case X86::BI__builtin_ia32_rdtscp: {
- Value *Call = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_rdtscp));
- Builder.CreateDefaultAlignedStore(Builder.CreateExtractValue(Call, 1),
- Ops[0]);
- return Builder.CreateExtractValue(Call, 0);
- }
- case X86::BI__builtin_ia32_lzcnt_u16:
- case X86::BI__builtin_ia32_lzcnt_u32:
- case X86::BI__builtin_ia32_lzcnt_u64: {
- Value *F = CGM.getIntrinsic(Intrinsic::ctlz, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
- }
- case X86::BI__builtin_ia32_tzcnt_u16:
- case X86::BI__builtin_ia32_tzcnt_u32:
- case X86::BI__builtin_ia32_tzcnt_u64: {
- Value *F = CGM.getIntrinsic(Intrinsic::cttz, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
- }
- case X86::BI__builtin_ia32_undef128:
- case X86::BI__builtin_ia32_undef256:
- case X86::BI__builtin_ia32_undef512:
- // The x86 definition of "undef" is not the same as the LLVM definition
- // (PR32176). We leave optimizing away an unnecessary zero constant to the
- // IR optimizer and backend.
- // TODO: If we had a "freeze" IR instruction to generate a fixed undef
- // value, we should use that here instead of a zero.
- return llvm::Constant::getNullValue(ConvertType(E->getType()));
- case X86::BI__builtin_ia32_vec_init_v8qi:
- case X86::BI__builtin_ia32_vec_init_v4hi:
- case X86::BI__builtin_ia32_vec_init_v2si:
- return Builder.CreateBitCast(BuildVector(Ops),
- llvm::Type::getX86_MMXTy(getLLVMContext()));
- case X86::BI__builtin_ia32_vec_ext_v2si:
- case X86::BI__builtin_ia32_vec_ext_v16qi:
- case X86::BI__builtin_ia32_vec_ext_v8hi:
- case X86::BI__builtin_ia32_vec_ext_v4si:
- case X86::BI__builtin_ia32_vec_ext_v4sf:
- case X86::BI__builtin_ia32_vec_ext_v2di:
- case X86::BI__builtin_ia32_vec_ext_v32qi:
- case X86::BI__builtin_ia32_vec_ext_v16hi:
- case X86::BI__builtin_ia32_vec_ext_v8si:
- case X86::BI__builtin_ia32_vec_ext_v4di: {
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- uint64_t Index = cast<ConstantInt>(Ops[1])->getZExtValue();
- Index &= NumElts - 1;
- // These builtins exist so we can ensure the index is an ICE and in range.
- // Otherwise we could just do this in the header file.
- return Builder.CreateExtractElement(Ops[0], Index);
- }
- case X86::BI__builtin_ia32_vec_set_v16qi:
- case X86::BI__builtin_ia32_vec_set_v8hi:
- case X86::BI__builtin_ia32_vec_set_v4si:
- case X86::BI__builtin_ia32_vec_set_v2di:
- case X86::BI__builtin_ia32_vec_set_v32qi:
- case X86::BI__builtin_ia32_vec_set_v16hi:
- case X86::BI__builtin_ia32_vec_set_v8si:
- case X86::BI__builtin_ia32_vec_set_v4di: {
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- unsigned Index = cast<ConstantInt>(Ops[2])->getZExtValue();
- Index &= NumElts - 1;
- // These builtins exist so we can ensure the index is an ICE and in range.
- // Otherwise we could just do this in the header file.
- return Builder.CreateInsertElement(Ops[0], Ops[1], Index);
- }
- case X86::BI_mm_setcsr:
- case X86::BI__builtin_ia32_ldmxcsr: {
- Address Tmp = CreateMemTemp(E->getArg(0)->getType());
- Builder.CreateStore(Ops[0], Tmp);
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr),
- Builder.CreateBitCast(Tmp.getPointer(), Int8PtrTy));
- }
- case X86::BI_mm_getcsr:
- case X86::BI__builtin_ia32_stmxcsr: {
- Address Tmp = CreateMemTemp(E->getType());
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr),
- Builder.CreateBitCast(Tmp.getPointer(), Int8PtrTy));
- return Builder.CreateLoad(Tmp, "stmxcsr");
- }
- case X86::BI__builtin_ia32_xsave:
- case X86::BI__builtin_ia32_xsave64:
- case X86::BI__builtin_ia32_xrstor:
- case X86::BI__builtin_ia32_xrstor64:
- case X86::BI__builtin_ia32_xsaveopt:
- case X86::BI__builtin_ia32_xsaveopt64:
- case X86::BI__builtin_ia32_xrstors:
- case X86::BI__builtin_ia32_xrstors64:
- case X86::BI__builtin_ia32_xsavec:
- case X86::BI__builtin_ia32_xsavec64:
- case X86::BI__builtin_ia32_xsaves:
- case X86::BI__builtin_ia32_xsaves64: {
- Intrinsic::ID ID;
-#define INTRINSIC_X86_XSAVE_ID(NAME) \
- case X86::BI__builtin_ia32_##NAME: \
- ID = Intrinsic::x86_##NAME; \
- break
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- INTRINSIC_X86_XSAVE_ID(xsave);
- INTRINSIC_X86_XSAVE_ID(xsave64);
- INTRINSIC_X86_XSAVE_ID(xrstor);
- INTRINSIC_X86_XSAVE_ID(xrstor64);
- INTRINSIC_X86_XSAVE_ID(xsaveopt);
- INTRINSIC_X86_XSAVE_ID(xsaveopt64);
- INTRINSIC_X86_XSAVE_ID(xrstors);
- INTRINSIC_X86_XSAVE_ID(xrstors64);
- INTRINSIC_X86_XSAVE_ID(xsavec);
- INTRINSIC_X86_XSAVE_ID(xsavec64);
- INTRINSIC_X86_XSAVE_ID(xsaves);
- INTRINSIC_X86_XSAVE_ID(xsaves64);
- }
-#undef INTRINSIC_X86_XSAVE_ID
- Value *Mhi = Builder.CreateTrunc(
- Builder.CreateLShr(Ops[1], ConstantInt::get(Int64Ty, 32)), Int32Ty);
- Value *Mlo = Builder.CreateTrunc(Ops[1], Int32Ty);
- Ops[1] = Mhi;
- Ops.push_back(Mlo);
- return Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
- }
- case X86::BI__builtin_ia32_storedqudi128_mask:
- case X86::BI__builtin_ia32_storedqusi128_mask:
- case X86::BI__builtin_ia32_storedquhi128_mask:
- case X86::BI__builtin_ia32_storedquqi128_mask:
- case X86::BI__builtin_ia32_storeupd128_mask:
- case X86::BI__builtin_ia32_storeups128_mask:
- case X86::BI__builtin_ia32_storedqudi256_mask:
- case X86::BI__builtin_ia32_storedqusi256_mask:
- case X86::BI__builtin_ia32_storedquhi256_mask:
- case X86::BI__builtin_ia32_storedquqi256_mask:
- case X86::BI__builtin_ia32_storeupd256_mask:
- case X86::BI__builtin_ia32_storeups256_mask:
- case X86::BI__builtin_ia32_storedqudi512_mask:
- case X86::BI__builtin_ia32_storedqusi512_mask:
- case X86::BI__builtin_ia32_storedquhi512_mask:
- case X86::BI__builtin_ia32_storedquqi512_mask:
- case X86::BI__builtin_ia32_storeupd512_mask:
- case X86::BI__builtin_ia32_storeups512_mask:
- return EmitX86MaskedStore(*this, Ops, 1);
-
- case X86::BI__builtin_ia32_storess128_mask:
- case X86::BI__builtin_ia32_storesd128_mask: {
- return EmitX86MaskedStore(*this, Ops, 1);
- }
- case X86::BI__builtin_ia32_vpopcntb_128:
- case X86::BI__builtin_ia32_vpopcntd_128:
- case X86::BI__builtin_ia32_vpopcntq_128:
- case X86::BI__builtin_ia32_vpopcntw_128:
- case X86::BI__builtin_ia32_vpopcntb_256:
- case X86::BI__builtin_ia32_vpopcntd_256:
- case X86::BI__builtin_ia32_vpopcntq_256:
- case X86::BI__builtin_ia32_vpopcntw_256:
- case X86::BI__builtin_ia32_vpopcntb_512:
- case X86::BI__builtin_ia32_vpopcntd_512:
- case X86::BI__builtin_ia32_vpopcntq_512:
- case X86::BI__builtin_ia32_vpopcntw_512: {
- llvm::Type *ResultType = ConvertType(E->getType());
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ResultType);
- return Builder.CreateCall(F, Ops);
- }
- case X86::BI__builtin_ia32_cvtmask2b128:
- case X86::BI__builtin_ia32_cvtmask2b256:
- case X86::BI__builtin_ia32_cvtmask2b512:
- case X86::BI__builtin_ia32_cvtmask2w128:
- case X86::BI__builtin_ia32_cvtmask2w256:
- case X86::BI__builtin_ia32_cvtmask2w512:
- case X86::BI__builtin_ia32_cvtmask2d128:
- case X86::BI__builtin_ia32_cvtmask2d256:
- case X86::BI__builtin_ia32_cvtmask2d512:
- case X86::BI__builtin_ia32_cvtmask2q128:
- case X86::BI__builtin_ia32_cvtmask2q256:
- case X86::BI__builtin_ia32_cvtmask2q512:
- return EmitX86SExtMask(*this, Ops[0], ConvertType(E->getType()));
-
- case X86::BI__builtin_ia32_cvtb2mask128:
- case X86::BI__builtin_ia32_cvtb2mask256:
- case X86::BI__builtin_ia32_cvtb2mask512:
- case X86::BI__builtin_ia32_cvtw2mask128:
- case X86::BI__builtin_ia32_cvtw2mask256:
- case X86::BI__builtin_ia32_cvtw2mask512:
- case X86::BI__builtin_ia32_cvtd2mask128:
- case X86::BI__builtin_ia32_cvtd2mask256:
- case X86::BI__builtin_ia32_cvtd2mask512:
- case X86::BI__builtin_ia32_cvtq2mask128:
- case X86::BI__builtin_ia32_cvtq2mask256:
- case X86::BI__builtin_ia32_cvtq2mask512:
- return EmitX86ConvertToMask(*this, Ops[0]);
-
- case X86::BI__builtin_ia32_vfmaddss3:
- case X86::BI__builtin_ia32_vfmaddsd3:
- case X86::BI__builtin_ia32_vfmaddss3_mask:
- case X86::BI__builtin_ia32_vfmaddsd3_mask:
- return EmitScalarFMAExpr(*this, Ops, Ops[0]);
- case X86::BI__builtin_ia32_vfmaddss:
- case X86::BI__builtin_ia32_vfmaddsd:
- return EmitScalarFMAExpr(*this, Ops,
- Constant::getNullValue(Ops[0]->getType()));
- case X86::BI__builtin_ia32_vfmaddss3_maskz:
- case X86::BI__builtin_ia32_vfmaddsd3_maskz:
- return EmitScalarFMAExpr(*this, Ops, Ops[0], /*ZeroMask*/true);
- case X86::BI__builtin_ia32_vfmaddss3_mask3:
- case X86::BI__builtin_ia32_vfmaddsd3_mask3:
- return EmitScalarFMAExpr(*this, Ops, Ops[2], /*ZeroMask*/false, 2);
- case X86::BI__builtin_ia32_vfmsubss3_mask3:
- case X86::BI__builtin_ia32_vfmsubsd3_mask3:
- return EmitScalarFMAExpr(*this, Ops, Ops[2], /*ZeroMask*/false, 2,
- /*NegAcc*/true);
- case X86::BI__builtin_ia32_vfmaddps:
- case X86::BI__builtin_ia32_vfmaddpd:
- case X86::BI__builtin_ia32_vfmaddps256:
- case X86::BI__builtin_ia32_vfmaddpd256:
- case X86::BI__builtin_ia32_vfmaddps512_mask:
- case X86::BI__builtin_ia32_vfmaddps512_maskz:
- case X86::BI__builtin_ia32_vfmaddps512_mask3:
- case X86::BI__builtin_ia32_vfmsubps512_mask3:
- case X86::BI__builtin_ia32_vfmaddpd512_mask:
- case X86::BI__builtin_ia32_vfmaddpd512_maskz:
- case X86::BI__builtin_ia32_vfmaddpd512_mask3:
- case X86::BI__builtin_ia32_vfmsubpd512_mask3:
- return EmitX86FMAExpr(*this, Ops, BuiltinID, /*IsAddSub*/false);
- case X86::BI__builtin_ia32_vfmaddsubps:
- case X86::BI__builtin_ia32_vfmaddsubpd:
- case X86::BI__builtin_ia32_vfmaddsubps256:
- case X86::BI__builtin_ia32_vfmaddsubpd256:
- case X86::BI__builtin_ia32_vfmaddsubps512_mask:
- case X86::BI__builtin_ia32_vfmaddsubps512_maskz:
- case X86::BI__builtin_ia32_vfmaddsubps512_mask3:
- case X86::BI__builtin_ia32_vfmsubaddps512_mask3:
- case X86::BI__builtin_ia32_vfmaddsubpd512_mask:
- case X86::BI__builtin_ia32_vfmaddsubpd512_maskz:
- case X86::BI__builtin_ia32_vfmaddsubpd512_mask3:
- case X86::BI__builtin_ia32_vfmsubaddpd512_mask3:
- return EmitX86FMAExpr(*this, Ops, BuiltinID, /*IsAddSub*/true);
-
- case X86::BI__builtin_ia32_movdqa32store128_mask:
- case X86::BI__builtin_ia32_movdqa64store128_mask:
- case X86::BI__builtin_ia32_storeaps128_mask:
- case X86::BI__builtin_ia32_storeapd128_mask:
- case X86::BI__builtin_ia32_movdqa32store256_mask:
- case X86::BI__builtin_ia32_movdqa64store256_mask:
- case X86::BI__builtin_ia32_storeaps256_mask:
- case X86::BI__builtin_ia32_storeapd256_mask:
- case X86::BI__builtin_ia32_movdqa32store512_mask:
- case X86::BI__builtin_ia32_movdqa64store512_mask:
- case X86::BI__builtin_ia32_storeaps512_mask:
- case X86::BI__builtin_ia32_storeapd512_mask: {
- unsigned Align =
- getContext().getTypeAlignInChars(E->getArg(1)->getType()).getQuantity();
- return EmitX86MaskedStore(*this, Ops, Align);
- }
- case X86::BI__builtin_ia32_loadups128_mask:
- case X86::BI__builtin_ia32_loadups256_mask:
- case X86::BI__builtin_ia32_loadups512_mask:
- case X86::BI__builtin_ia32_loadupd128_mask:
- case X86::BI__builtin_ia32_loadupd256_mask:
- case X86::BI__builtin_ia32_loadupd512_mask:
- case X86::BI__builtin_ia32_loaddquqi128_mask:
- case X86::BI__builtin_ia32_loaddquqi256_mask:
- case X86::BI__builtin_ia32_loaddquqi512_mask:
- case X86::BI__builtin_ia32_loaddquhi128_mask:
- case X86::BI__builtin_ia32_loaddquhi256_mask:
- case X86::BI__builtin_ia32_loaddquhi512_mask:
- case X86::BI__builtin_ia32_loaddqusi128_mask:
- case X86::BI__builtin_ia32_loaddqusi256_mask:
- case X86::BI__builtin_ia32_loaddqusi512_mask:
- case X86::BI__builtin_ia32_loaddqudi128_mask:
- case X86::BI__builtin_ia32_loaddqudi256_mask:
- case X86::BI__builtin_ia32_loaddqudi512_mask:
- return EmitX86MaskedLoad(*this, Ops, 1);
-
- case X86::BI__builtin_ia32_loadss128_mask:
- case X86::BI__builtin_ia32_loadsd128_mask:
- return EmitX86MaskedLoad(*this, Ops, 1);
-
- case X86::BI__builtin_ia32_loadaps128_mask:
- case X86::BI__builtin_ia32_loadaps256_mask:
- case X86::BI__builtin_ia32_loadaps512_mask:
- case X86::BI__builtin_ia32_loadapd128_mask:
- case X86::BI__builtin_ia32_loadapd256_mask:
- case X86::BI__builtin_ia32_loadapd512_mask:
- case X86::BI__builtin_ia32_movdqa32load128_mask:
- case X86::BI__builtin_ia32_movdqa32load256_mask:
- case X86::BI__builtin_ia32_movdqa32load512_mask:
- case X86::BI__builtin_ia32_movdqa64load128_mask:
- case X86::BI__builtin_ia32_movdqa64load256_mask:
- case X86::BI__builtin_ia32_movdqa64load512_mask: {
- unsigned Align =
- getContext().getTypeAlignInChars(E->getArg(1)->getType()).getQuantity();
- return EmitX86MaskedLoad(*this, Ops, Align);
- }
-
- case X86::BI__builtin_ia32_expandloaddf128_mask:
- case X86::BI__builtin_ia32_expandloaddf256_mask:
- case X86::BI__builtin_ia32_expandloaddf512_mask:
- case X86::BI__builtin_ia32_expandloadsf128_mask:
- case X86::BI__builtin_ia32_expandloadsf256_mask:
- case X86::BI__builtin_ia32_expandloadsf512_mask:
- case X86::BI__builtin_ia32_expandloaddi128_mask:
- case X86::BI__builtin_ia32_expandloaddi256_mask:
- case X86::BI__builtin_ia32_expandloaddi512_mask:
- case X86::BI__builtin_ia32_expandloadsi128_mask:
- case X86::BI__builtin_ia32_expandloadsi256_mask:
- case X86::BI__builtin_ia32_expandloadsi512_mask:
- case X86::BI__builtin_ia32_expandloadhi128_mask:
- case X86::BI__builtin_ia32_expandloadhi256_mask:
- case X86::BI__builtin_ia32_expandloadhi512_mask:
- case X86::BI__builtin_ia32_expandloadqi128_mask:
- case X86::BI__builtin_ia32_expandloadqi256_mask:
- case X86::BI__builtin_ia32_expandloadqi512_mask:
- return EmitX86ExpandLoad(*this, Ops);
-
- case X86::BI__builtin_ia32_compressstoredf128_mask:
- case X86::BI__builtin_ia32_compressstoredf256_mask:
- case X86::BI__builtin_ia32_compressstoredf512_mask:
- case X86::BI__builtin_ia32_compressstoresf128_mask:
- case X86::BI__builtin_ia32_compressstoresf256_mask:
- case X86::BI__builtin_ia32_compressstoresf512_mask:
- case X86::BI__builtin_ia32_compressstoredi128_mask:
- case X86::BI__builtin_ia32_compressstoredi256_mask:
- case X86::BI__builtin_ia32_compressstoredi512_mask:
- case X86::BI__builtin_ia32_compressstoresi128_mask:
- case X86::BI__builtin_ia32_compressstoresi256_mask:
- case X86::BI__builtin_ia32_compressstoresi512_mask:
- case X86::BI__builtin_ia32_compressstorehi128_mask:
- case X86::BI__builtin_ia32_compressstorehi256_mask:
- case X86::BI__builtin_ia32_compressstorehi512_mask:
- case X86::BI__builtin_ia32_compressstoreqi128_mask:
- case X86::BI__builtin_ia32_compressstoreqi256_mask:
- case X86::BI__builtin_ia32_compressstoreqi512_mask:
- return EmitX86CompressStore(*this, Ops);
-
- case X86::BI__builtin_ia32_storehps:
- case X86::BI__builtin_ia32_storelps: {
- llvm::Type *PtrTy = llvm::PointerType::getUnqual(Int64Ty);
- llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2);
-
- // cast val v2i64
- Ops[1] = Builder.CreateBitCast(Ops[1], VecTy, "cast");
-
- // extract (0, 1)
- unsigned Index = BuiltinID == X86::BI__builtin_ia32_storelps ? 0 : 1;
- Ops[1] = Builder.CreateExtractElement(Ops[1], Index, "extract");
-
- // cast pointer to i64 & store
- Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy);
- return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
- }
- case X86::BI__builtin_ia32_vextractf128_pd256:
- case X86::BI__builtin_ia32_vextractf128_ps256:
- case X86::BI__builtin_ia32_vextractf128_si256:
- case X86::BI__builtin_ia32_extract128i256:
- case X86::BI__builtin_ia32_extractf64x4_mask:
- case X86::BI__builtin_ia32_extractf32x4_mask:
- case X86::BI__builtin_ia32_extracti64x4_mask:
- case X86::BI__builtin_ia32_extracti32x4_mask:
- case X86::BI__builtin_ia32_extractf32x8_mask:
- case X86::BI__builtin_ia32_extracti32x8_mask:
- case X86::BI__builtin_ia32_extractf32x4_256_mask:
- case X86::BI__builtin_ia32_extracti32x4_256_mask:
- case X86::BI__builtin_ia32_extractf64x2_256_mask:
- case X86::BI__builtin_ia32_extracti64x2_256_mask:
- case X86::BI__builtin_ia32_extractf64x2_512_mask:
- case X86::BI__builtin_ia32_extracti64x2_512_mask: {
- llvm::Type *DstTy = ConvertType(E->getType());
- unsigned NumElts = DstTy->getVectorNumElements();
- unsigned SrcNumElts = Ops[0]->getType()->getVectorNumElements();
- unsigned SubVectors = SrcNumElts / NumElts;
- unsigned Index = cast<ConstantInt>(Ops[1])->getZExtValue();
- assert(llvm::isPowerOf2_32(SubVectors) && "Expected power of 2 subvectors");
- Index &= SubVectors - 1; // Remove any extra bits.
- Index *= NumElts;
-
- uint32_t Indices[16];
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = i + Index;
-
- Value *Res = Builder.CreateShuffleVector(Ops[0],
- UndefValue::get(Ops[0]->getType()),
- makeArrayRef(Indices, NumElts),
- "extract");
-
- if (Ops.size() == 4)
- Res = EmitX86Select(*this, Ops[3], Res, Ops[2]);
-
- return Res;
- }
- case X86::BI__builtin_ia32_vinsertf128_pd256:
- case X86::BI__builtin_ia32_vinsertf128_ps256:
- case X86::BI__builtin_ia32_vinsertf128_si256:
- case X86::BI__builtin_ia32_insert128i256:
- case X86::BI__builtin_ia32_insertf64x4:
- case X86::BI__builtin_ia32_insertf32x4:
- case X86::BI__builtin_ia32_inserti64x4:
- case X86::BI__builtin_ia32_inserti32x4:
- case X86::BI__builtin_ia32_insertf32x8:
- case X86::BI__builtin_ia32_inserti32x8:
- case X86::BI__builtin_ia32_insertf32x4_256:
- case X86::BI__builtin_ia32_inserti32x4_256:
- case X86::BI__builtin_ia32_insertf64x2_256:
- case X86::BI__builtin_ia32_inserti64x2_256:
- case X86::BI__builtin_ia32_insertf64x2_512:
- case X86::BI__builtin_ia32_inserti64x2_512: {
- unsigned DstNumElts = Ops[0]->getType()->getVectorNumElements();
- unsigned SrcNumElts = Ops[1]->getType()->getVectorNumElements();
- unsigned SubVectors = DstNumElts / SrcNumElts;
- unsigned Index = cast<ConstantInt>(Ops[2])->getZExtValue();
- assert(llvm::isPowerOf2_32(SubVectors) && "Expected power of 2 subvectors");
- Index &= SubVectors - 1; // Remove any extra bits.
- Index *= SrcNumElts;
-
- uint32_t Indices[16];
- for (unsigned i = 0; i != DstNumElts; ++i)
- Indices[i] = (i >= SrcNumElts) ? SrcNumElts + (i % SrcNumElts) : i;
-
- Value *Op1 = Builder.CreateShuffleVector(Ops[1],
- UndefValue::get(Ops[1]->getType()),
- makeArrayRef(Indices, DstNumElts),
- "widen");
-
- for (unsigned i = 0; i != DstNumElts; ++i) {
- if (i >= Index && i < (Index + SrcNumElts))
- Indices[i] = (i - Index) + DstNumElts;
- else
- Indices[i] = i;
- }
-
- return Builder.CreateShuffleVector(Ops[0], Op1,
- makeArrayRef(Indices, DstNumElts),
- "insert");
- }
- case X86::BI__builtin_ia32_pmovqd512_mask:
- case X86::BI__builtin_ia32_pmovwb512_mask: {
- Value *Res = Builder.CreateTrunc(Ops[0], Ops[1]->getType());
- return EmitX86Select(*this, Ops[2], Res, Ops[1]);
- }
- case X86::BI__builtin_ia32_pmovdb512_mask:
- case X86::BI__builtin_ia32_pmovdw512_mask:
- case X86::BI__builtin_ia32_pmovqw512_mask: {
- if (const auto *C = dyn_cast<Constant>(Ops[2]))
- if (C->isAllOnesValue())
- return Builder.CreateTrunc(Ops[0], Ops[1]->getType());
-
- Intrinsic::ID IID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_pmovdb512_mask:
- IID = Intrinsic::x86_avx512_mask_pmov_db_512;
- break;
- case X86::BI__builtin_ia32_pmovdw512_mask:
- IID = Intrinsic::x86_avx512_mask_pmov_dw_512;
- break;
- case X86::BI__builtin_ia32_pmovqw512_mask:
- IID = Intrinsic::x86_avx512_mask_pmov_qw_512;
- break;
- }
-
- Function *Intr = CGM.getIntrinsic(IID);
- return Builder.CreateCall(Intr, Ops);
- }
- case X86::BI__builtin_ia32_pblendw128:
- case X86::BI__builtin_ia32_blendpd:
- case X86::BI__builtin_ia32_blendps:
- case X86::BI__builtin_ia32_blendpd256:
- case X86::BI__builtin_ia32_blendps256:
- case X86::BI__builtin_ia32_pblendw256:
- case X86::BI__builtin_ia32_pblendd128:
- case X86::BI__builtin_ia32_pblendd256: {
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- unsigned Imm = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
-
- uint32_t Indices[16];
- // If there are more than 8 elements, the immediate is used twice so make
- // sure we handle that.
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = ((Imm >> (i % 8)) & 0x1) ? NumElts + i : i;
-
- return Builder.CreateShuffleVector(Ops[0], Ops[1],
- makeArrayRef(Indices, NumElts),
- "blend");
- }
- case X86::BI__builtin_ia32_pshuflw:
- case X86::BI__builtin_ia32_pshuflw256:
- case X86::BI__builtin_ia32_pshuflw512: {
- uint32_t Imm = cast<llvm::ConstantInt>(Ops[1])->getZExtValue();
- llvm::Type *Ty = Ops[0]->getType();
- unsigned NumElts = Ty->getVectorNumElements();
-
- // Splat the 8-bits of immediate 4 times to help the loop wrap around.
- Imm = (Imm & 0xff) * 0x01010101;
-
- uint32_t Indices[32];
- for (unsigned l = 0; l != NumElts; l += 8) {
- for (unsigned i = 0; i != 4; ++i) {
- Indices[l + i] = l + (Imm & 3);
- Imm >>= 2;
- }
- for (unsigned i = 4; i != 8; ++i)
- Indices[l + i] = l + i;
- }
-
- return Builder.CreateShuffleVector(Ops[0], UndefValue::get(Ty),
- makeArrayRef(Indices, NumElts),
- "pshuflw");
- }
- case X86::BI__builtin_ia32_pshufhw:
- case X86::BI__builtin_ia32_pshufhw256:
- case X86::BI__builtin_ia32_pshufhw512: {
- uint32_t Imm = cast<llvm::ConstantInt>(Ops[1])->getZExtValue();
- llvm::Type *Ty = Ops[0]->getType();
- unsigned NumElts = Ty->getVectorNumElements();
-
- // Splat the 8-bits of immediate 4 times to help the loop wrap around.
- Imm = (Imm & 0xff) * 0x01010101;
-
- uint32_t Indices[32];
- for (unsigned l = 0; l != NumElts; l += 8) {
- for (unsigned i = 0; i != 4; ++i)
- Indices[l + i] = l + i;
- for (unsigned i = 4; i != 8; ++i) {
- Indices[l + i] = l + 4 + (Imm & 3);
- Imm >>= 2;
- }
- }
-
- return Builder.CreateShuffleVector(Ops[0], UndefValue::get(Ty),
- makeArrayRef(Indices, NumElts),
- "pshufhw");
- }
- case X86::BI__builtin_ia32_pshufd:
- case X86::BI__builtin_ia32_pshufd256:
- case X86::BI__builtin_ia32_pshufd512:
- case X86::BI__builtin_ia32_vpermilpd:
- case X86::BI__builtin_ia32_vpermilps:
- case X86::BI__builtin_ia32_vpermilpd256:
- case X86::BI__builtin_ia32_vpermilps256:
- case X86::BI__builtin_ia32_vpermilpd512:
- case X86::BI__builtin_ia32_vpermilps512: {
- uint32_t Imm = cast<llvm::ConstantInt>(Ops[1])->getZExtValue();
- llvm::Type *Ty = Ops[0]->getType();
- unsigned NumElts = Ty->getVectorNumElements();
- unsigned NumLanes = Ty->getPrimitiveSizeInBits() / 128;
- unsigned NumLaneElts = NumElts / NumLanes;
-
- // Splat the 8-bits of immediate 4 times to help the loop wrap around.
- Imm = (Imm & 0xff) * 0x01010101;
-
- uint32_t Indices[16];
- for (unsigned l = 0; l != NumElts; l += NumLaneElts) {
- for (unsigned i = 0; i != NumLaneElts; ++i) {
- Indices[i + l] = (Imm % NumLaneElts) + l;
- Imm /= NumLaneElts;
- }
- }
-
- return Builder.CreateShuffleVector(Ops[0], UndefValue::get(Ty),
- makeArrayRef(Indices, NumElts),
- "permil");
- }
- case X86::BI__builtin_ia32_shufpd:
- case X86::BI__builtin_ia32_shufpd256:
- case X86::BI__builtin_ia32_shufpd512:
- case X86::BI__builtin_ia32_shufps:
- case X86::BI__builtin_ia32_shufps256:
- case X86::BI__builtin_ia32_shufps512: {
- uint32_t Imm = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
- llvm::Type *Ty = Ops[0]->getType();
- unsigned NumElts = Ty->getVectorNumElements();
- unsigned NumLanes = Ty->getPrimitiveSizeInBits() / 128;
- unsigned NumLaneElts = NumElts / NumLanes;
-
- // Splat the 8-bits of immediate 4 times to help the loop wrap around.
- Imm = (Imm & 0xff) * 0x01010101;
-
- uint32_t Indices[16];
- for (unsigned l = 0; l != NumElts; l += NumLaneElts) {
- for (unsigned i = 0; i != NumLaneElts; ++i) {
- unsigned Index = Imm % NumLaneElts;
- Imm /= NumLaneElts;
- if (i >= (NumLaneElts / 2))
- Index += NumElts;
- Indices[l + i] = l + Index;
- }
- }
-
- return Builder.CreateShuffleVector(Ops[0], Ops[1],
- makeArrayRef(Indices, NumElts),
- "shufp");
- }
- case X86::BI__builtin_ia32_permdi256:
- case X86::BI__builtin_ia32_permdf256:
- case X86::BI__builtin_ia32_permdi512:
- case X86::BI__builtin_ia32_permdf512: {
- unsigned Imm = cast<llvm::ConstantInt>(Ops[1])->getZExtValue();
- llvm::Type *Ty = Ops[0]->getType();
- unsigned NumElts = Ty->getVectorNumElements();
-
- // These intrinsics operate on 256-bit lanes of four 64-bit elements.
- uint32_t Indices[8];
- for (unsigned l = 0; l != NumElts; l += 4)
- for (unsigned i = 0; i != 4; ++i)
- Indices[l + i] = l + ((Imm >> (2 * i)) & 0x3);
-
- return Builder.CreateShuffleVector(Ops[0], UndefValue::get(Ty),
- makeArrayRef(Indices, NumElts),
- "perm");
- }
- case X86::BI__builtin_ia32_palignr128:
- case X86::BI__builtin_ia32_palignr256:
- case X86::BI__builtin_ia32_palignr512: {
- unsigned ShiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue() & 0xff;
-
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- assert(NumElts % 16 == 0);
-
- // If palignr is shifting the pair of vectors more than the size of two
- // lanes, emit zero.
- if (ShiftVal >= 32)
- return llvm::Constant::getNullValue(ConvertType(E->getType()));
-
- // If palignr is shifting the pair of input vectors more than one lane,
- // but less than two lanes, convert to shifting in zeroes.
- if (ShiftVal > 16) {
- ShiftVal -= 16;
- Ops[1] = Ops[0];
- Ops[0] = llvm::Constant::getNullValue(Ops[0]->getType());
- }
-
- uint32_t Indices[64];
- // 256-bit palignr operates on 128-bit lanes so we need to handle that
- for (unsigned l = 0; l != NumElts; l += 16) {
- for (unsigned i = 0; i != 16; ++i) {
- unsigned Idx = ShiftVal + i;
- if (Idx >= 16)
- Idx += NumElts - 16; // End of lane, switch operand.
- Indices[l + i] = Idx + l;
- }
- }
-
- return Builder.CreateShuffleVector(Ops[1], Ops[0],
- makeArrayRef(Indices, NumElts),
- "palignr");
- }
- case X86::BI__builtin_ia32_alignd128:
- case X86::BI__builtin_ia32_alignd256:
- case X86::BI__builtin_ia32_alignd512:
- case X86::BI__builtin_ia32_alignq128:
- case X86::BI__builtin_ia32_alignq256:
- case X86::BI__builtin_ia32_alignq512: {
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- unsigned ShiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue() & 0xff;
-
- // Mask the shift amount to width of two vectors.
- ShiftVal &= (2 * NumElts) - 1;
-
- uint32_t Indices[16];
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = i + ShiftVal;
-
- return Builder.CreateShuffleVector(Ops[1], Ops[0],
- makeArrayRef(Indices, NumElts),
- "valign");
- }
- case X86::BI__builtin_ia32_shuf_f32x4_256:
- case X86::BI__builtin_ia32_shuf_f64x2_256:
- case X86::BI__builtin_ia32_shuf_i32x4_256:
- case X86::BI__builtin_ia32_shuf_i64x2_256:
- case X86::BI__builtin_ia32_shuf_f32x4:
- case X86::BI__builtin_ia32_shuf_f64x2:
- case X86::BI__builtin_ia32_shuf_i32x4:
- case X86::BI__builtin_ia32_shuf_i64x2: {
- unsigned Imm = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
- llvm::Type *Ty = Ops[0]->getType();
- unsigned NumElts = Ty->getVectorNumElements();
- unsigned NumLanes = Ty->getPrimitiveSizeInBits() == 512 ? 4 : 2;
- unsigned NumLaneElts = NumElts / NumLanes;
-
- uint32_t Indices[16];
- for (unsigned l = 0; l != NumElts; l += NumLaneElts) {
- unsigned Index = (Imm % NumLanes) * NumLaneElts;
- Imm /= NumLanes; // Discard the bits we just used.
- if (l >= (NumElts / 2))
- Index += NumElts; // Switch to other source.
- for (unsigned i = 0; i != NumLaneElts; ++i) {
- Indices[l + i] = Index + i;
- }
- }
-
- return Builder.CreateShuffleVector(Ops[0], Ops[1],
- makeArrayRef(Indices, NumElts),
- "shuf");
- }
-
- case X86::BI__builtin_ia32_vperm2f128_pd256:
- case X86::BI__builtin_ia32_vperm2f128_ps256:
- case X86::BI__builtin_ia32_vperm2f128_si256:
- case X86::BI__builtin_ia32_permti256: {
- unsigned Imm = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
-
- // This takes a very simple approach since there are two lanes and a
- // shuffle can have 2 inputs. So we reserve the first input for the first
- // lane and the second input for the second lane. This may result in
- // duplicate sources, but this can be dealt with in the backend.
-
- Value *OutOps[2];
- uint32_t Indices[8];
- for (unsigned l = 0; l != 2; ++l) {
- // Determine the source for this lane.
- if (Imm & (1 << ((l * 4) + 3)))
- OutOps[l] = llvm::ConstantAggregateZero::get(Ops[0]->getType());
- else if (Imm & (1 << ((l * 4) + 1)))
- OutOps[l] = Ops[1];
- else
- OutOps[l] = Ops[0];
-
- for (unsigned i = 0; i != NumElts/2; ++i) {
- // Start with ith element of the source for this lane.
- unsigned Idx = (l * NumElts) + i;
- // If bit 0 of the immediate half is set, switch to the high half of
- // the source.
- if (Imm & (1 << (l * 4)))
- Idx += NumElts/2;
- Indices[(l * (NumElts/2)) + i] = Idx;
- }
- }
-
- return Builder.CreateShuffleVector(OutOps[0], OutOps[1],
- makeArrayRef(Indices, NumElts),
- "vperm");
- }
-
- case X86::BI__builtin_ia32_pslldqi128_byteshift:
- case X86::BI__builtin_ia32_pslldqi256_byteshift:
- case X86::BI__builtin_ia32_pslldqi512_byteshift: {
- unsigned ShiftVal = cast<llvm::ConstantInt>(Ops[1])->getZExtValue() & 0xff;
- llvm::Type *ResultType = Ops[0]->getType();
- // Builtin type is vXi64 so multiply by 8 to get bytes.
- unsigned NumElts = ResultType->getVectorNumElements() * 8;
-
- // If pslldq is shifting the vector more than 15 bytes, emit zero.
- if (ShiftVal >= 16)
- return llvm::Constant::getNullValue(ResultType);
-
- uint32_t Indices[64];
- // 256/512-bit pslldq operates on 128-bit lanes so we need to handle that
- for (unsigned l = 0; l != NumElts; l += 16) {
- for (unsigned i = 0; i != 16; ++i) {
- unsigned Idx = NumElts + i - ShiftVal;
- if (Idx < NumElts) Idx -= NumElts - 16; // end of lane, switch operand.
- Indices[l + i] = Idx + l;
- }
- }
-
- llvm::Type *VecTy = llvm::VectorType::get(Int8Ty, NumElts);
- Value *Cast = Builder.CreateBitCast(Ops[0], VecTy, "cast");
- Value *Zero = llvm::Constant::getNullValue(VecTy);
- Value *SV = Builder.CreateShuffleVector(Zero, Cast,
- makeArrayRef(Indices, NumElts),
- "pslldq");
- return Builder.CreateBitCast(SV, Ops[0]->getType(), "cast");
- }
- case X86::BI__builtin_ia32_psrldqi128_byteshift:
- case X86::BI__builtin_ia32_psrldqi256_byteshift:
- case X86::BI__builtin_ia32_psrldqi512_byteshift: {
- unsigned ShiftVal = cast<llvm::ConstantInt>(Ops[1])->getZExtValue() & 0xff;
- llvm::Type *ResultType = Ops[0]->getType();
- // Builtin type is vXi64 so multiply by 8 to get bytes.
- unsigned NumElts = ResultType->getVectorNumElements() * 8;
-
- // If psrldq is shifting the vector more than 15 bytes, emit zero.
- if (ShiftVal >= 16)
- return llvm::Constant::getNullValue(ResultType);
-
- uint32_t Indices[64];
- // 256/512-bit psrldq operates on 128-bit lanes so we need to handle that
- for (unsigned l = 0; l != NumElts; l += 16) {
- for (unsigned i = 0; i != 16; ++i) {
- unsigned Idx = i + ShiftVal;
- if (Idx >= 16) Idx += NumElts - 16; // end of lane, switch operand.
- Indices[l + i] = Idx + l;
- }
- }
-
- llvm::Type *VecTy = llvm::VectorType::get(Int8Ty, NumElts);
- Value *Cast = Builder.CreateBitCast(Ops[0], VecTy, "cast");
- Value *Zero = llvm::Constant::getNullValue(VecTy);
- Value *SV = Builder.CreateShuffleVector(Cast, Zero,
- makeArrayRef(Indices, NumElts),
- "psrldq");
- return Builder.CreateBitCast(SV, ResultType, "cast");
- }
- case X86::BI__builtin_ia32_kshiftliqi:
- case X86::BI__builtin_ia32_kshiftlihi:
- case X86::BI__builtin_ia32_kshiftlisi:
- case X86::BI__builtin_ia32_kshiftlidi: {
- unsigned ShiftVal = cast<llvm::ConstantInt>(Ops[1])->getZExtValue() & 0xff;
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
-
- if (ShiftVal >= NumElts)
- return llvm::Constant::getNullValue(Ops[0]->getType());
-
- Value *In = getMaskVecValue(*this, Ops[0], NumElts);
-
- uint32_t Indices[64];
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = NumElts + i - ShiftVal;
-
- Value *Zero = llvm::Constant::getNullValue(In->getType());
- Value *SV = Builder.CreateShuffleVector(Zero, In,
- makeArrayRef(Indices, NumElts),
- "kshiftl");
- return Builder.CreateBitCast(SV, Ops[0]->getType());
- }
- case X86::BI__builtin_ia32_kshiftriqi:
- case X86::BI__builtin_ia32_kshiftrihi:
- case X86::BI__builtin_ia32_kshiftrisi:
- case X86::BI__builtin_ia32_kshiftridi: {
- unsigned ShiftVal = cast<llvm::ConstantInt>(Ops[1])->getZExtValue() & 0xff;
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
-
- if (ShiftVal >= NumElts)
- return llvm::Constant::getNullValue(Ops[0]->getType());
-
- Value *In = getMaskVecValue(*this, Ops[0], NumElts);
-
- uint32_t Indices[64];
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = i + ShiftVal;
-
- Value *Zero = llvm::Constant::getNullValue(In->getType());
- Value *SV = Builder.CreateShuffleVector(In, Zero,
- makeArrayRef(Indices, NumElts),
- "kshiftr");
- return Builder.CreateBitCast(SV, Ops[0]->getType());
- }
- case X86::BI__builtin_ia32_movnti:
- case X86::BI__builtin_ia32_movnti64:
- case X86::BI__builtin_ia32_movntsd:
- case X86::BI__builtin_ia32_movntss: {
- llvm::MDNode *Node = llvm::MDNode::get(
- getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
-
- Value *Ptr = Ops[0];
- Value *Src = Ops[1];
-
- // Extract the 0'th element of the source vector.
- if (BuiltinID == X86::BI__builtin_ia32_movntsd ||
- BuiltinID == X86::BI__builtin_ia32_movntss)
- Src = Builder.CreateExtractElement(Src, (uint64_t)0, "extract");
-
- // Convert the type of the pointer to a pointer to the stored type.
- Value *BC = Builder.CreateBitCast(
- Ptr, llvm::PointerType::getUnqual(Src->getType()), "cast");
-
- // Unaligned nontemporal store of the scalar value.
- StoreInst *SI = Builder.CreateDefaultAlignedStore(Src, BC);
- SI->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
- SI->setAlignment(1);
- return SI;
- }
- // Rotate is a special case of funnel shift - 1st 2 args are the same.
- case X86::BI__builtin_ia32_vprotb:
- case X86::BI__builtin_ia32_vprotw:
- case X86::BI__builtin_ia32_vprotd:
- case X86::BI__builtin_ia32_vprotq:
- case X86::BI__builtin_ia32_vprotbi:
- case X86::BI__builtin_ia32_vprotwi:
- case X86::BI__builtin_ia32_vprotdi:
- case X86::BI__builtin_ia32_vprotqi:
- case X86::BI__builtin_ia32_prold128:
- case X86::BI__builtin_ia32_prold256:
- case X86::BI__builtin_ia32_prold512:
- case X86::BI__builtin_ia32_prolq128:
- case X86::BI__builtin_ia32_prolq256:
- case X86::BI__builtin_ia32_prolq512:
- case X86::BI__builtin_ia32_prolvd128:
- case X86::BI__builtin_ia32_prolvd256:
- case X86::BI__builtin_ia32_prolvd512:
- case X86::BI__builtin_ia32_prolvq128:
- case X86::BI__builtin_ia32_prolvq256:
- case X86::BI__builtin_ia32_prolvq512:
- return EmitX86FunnelShift(*this, Ops[0], Ops[0], Ops[1], false);
- case X86::BI__builtin_ia32_prord128:
- case X86::BI__builtin_ia32_prord256:
- case X86::BI__builtin_ia32_prord512:
- case X86::BI__builtin_ia32_prorq128:
- case X86::BI__builtin_ia32_prorq256:
- case X86::BI__builtin_ia32_prorq512:
- case X86::BI__builtin_ia32_prorvd128:
- case X86::BI__builtin_ia32_prorvd256:
- case X86::BI__builtin_ia32_prorvd512:
- case X86::BI__builtin_ia32_prorvq128:
- case X86::BI__builtin_ia32_prorvq256:
- case X86::BI__builtin_ia32_prorvq512:
- return EmitX86FunnelShift(*this, Ops[0], Ops[0], Ops[1], true);
- case X86::BI__builtin_ia32_selectb_128:
- case X86::BI__builtin_ia32_selectb_256:
- case X86::BI__builtin_ia32_selectb_512:
- case X86::BI__builtin_ia32_selectw_128:
- case X86::BI__builtin_ia32_selectw_256:
- case X86::BI__builtin_ia32_selectw_512:
- case X86::BI__builtin_ia32_selectd_128:
- case X86::BI__builtin_ia32_selectd_256:
- case X86::BI__builtin_ia32_selectd_512:
- case X86::BI__builtin_ia32_selectq_128:
- case X86::BI__builtin_ia32_selectq_256:
- case X86::BI__builtin_ia32_selectq_512:
- case X86::BI__builtin_ia32_selectps_128:
- case X86::BI__builtin_ia32_selectps_256:
- case X86::BI__builtin_ia32_selectps_512:
- case X86::BI__builtin_ia32_selectpd_128:
- case X86::BI__builtin_ia32_selectpd_256:
- case X86::BI__builtin_ia32_selectpd_512:
- return EmitX86Select(*this, Ops[0], Ops[1], Ops[2]);
- case X86::BI__builtin_ia32_selectss_128:
- case X86::BI__builtin_ia32_selectsd_128: {
- Value *A = Builder.CreateExtractElement(Ops[1], (uint64_t)0);
- Value *B = Builder.CreateExtractElement(Ops[2], (uint64_t)0);
- A = EmitX86ScalarSelect(*this, Ops[0], A, B);
- return Builder.CreateInsertElement(Ops[1], A, (uint64_t)0);
- }
- case X86::BI__builtin_ia32_cmpb128_mask:
- case X86::BI__builtin_ia32_cmpb256_mask:
- case X86::BI__builtin_ia32_cmpb512_mask:
- case X86::BI__builtin_ia32_cmpw128_mask:
- case X86::BI__builtin_ia32_cmpw256_mask:
- case X86::BI__builtin_ia32_cmpw512_mask:
- case X86::BI__builtin_ia32_cmpd128_mask:
- case X86::BI__builtin_ia32_cmpd256_mask:
- case X86::BI__builtin_ia32_cmpd512_mask:
- case X86::BI__builtin_ia32_cmpq128_mask:
- case X86::BI__builtin_ia32_cmpq256_mask:
- case X86::BI__builtin_ia32_cmpq512_mask: {
- unsigned CC = cast<llvm::ConstantInt>(Ops[2])->getZExtValue() & 0x7;
- return EmitX86MaskedCompare(*this, CC, true, Ops);
- }
- case X86::BI__builtin_ia32_ucmpb128_mask:
- case X86::BI__builtin_ia32_ucmpb256_mask:
- case X86::BI__builtin_ia32_ucmpb512_mask:
- case X86::BI__builtin_ia32_ucmpw128_mask:
- case X86::BI__builtin_ia32_ucmpw256_mask:
- case X86::BI__builtin_ia32_ucmpw512_mask:
- case X86::BI__builtin_ia32_ucmpd128_mask:
- case X86::BI__builtin_ia32_ucmpd256_mask:
- case X86::BI__builtin_ia32_ucmpd512_mask:
- case X86::BI__builtin_ia32_ucmpq128_mask:
- case X86::BI__builtin_ia32_ucmpq256_mask:
- case X86::BI__builtin_ia32_ucmpq512_mask: {
- unsigned CC = cast<llvm::ConstantInt>(Ops[2])->getZExtValue() & 0x7;
- return EmitX86MaskedCompare(*this, CC, false, Ops);
- }
-
- case X86::BI__builtin_ia32_kortestcqi:
- case X86::BI__builtin_ia32_kortestchi:
- case X86::BI__builtin_ia32_kortestcsi:
- case X86::BI__builtin_ia32_kortestcdi: {
- Value *Or = EmitX86MaskLogic(*this, Instruction::Or, Ops);
- Value *C = llvm::Constant::getAllOnesValue(Ops[0]->getType());
- Value *Cmp = Builder.CreateICmpEQ(Or, C);
- return Builder.CreateZExt(Cmp, ConvertType(E->getType()));
- }
- case X86::BI__builtin_ia32_kortestzqi:
- case X86::BI__builtin_ia32_kortestzhi:
- case X86::BI__builtin_ia32_kortestzsi:
- case X86::BI__builtin_ia32_kortestzdi: {
- Value *Or = EmitX86MaskLogic(*this, Instruction::Or, Ops);
- Value *C = llvm::Constant::getNullValue(Ops[0]->getType());
- Value *Cmp = Builder.CreateICmpEQ(Or, C);
- return Builder.CreateZExt(Cmp, ConvertType(E->getType()));
- }
-
- case X86::BI__builtin_ia32_ktestcqi:
- case X86::BI__builtin_ia32_ktestzqi:
- case X86::BI__builtin_ia32_ktestchi:
- case X86::BI__builtin_ia32_ktestzhi:
- case X86::BI__builtin_ia32_ktestcsi:
- case X86::BI__builtin_ia32_ktestzsi:
- case X86::BI__builtin_ia32_ktestcdi:
- case X86::BI__builtin_ia32_ktestzdi: {
- Intrinsic::ID IID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_ktestcqi:
- IID = Intrinsic::x86_avx512_ktestc_b;
- break;
- case X86::BI__builtin_ia32_ktestzqi:
- IID = Intrinsic::x86_avx512_ktestz_b;
- break;
- case X86::BI__builtin_ia32_ktestchi:
- IID = Intrinsic::x86_avx512_ktestc_w;
- break;
- case X86::BI__builtin_ia32_ktestzhi:
- IID = Intrinsic::x86_avx512_ktestz_w;
- break;
- case X86::BI__builtin_ia32_ktestcsi:
- IID = Intrinsic::x86_avx512_ktestc_d;
- break;
- case X86::BI__builtin_ia32_ktestzsi:
- IID = Intrinsic::x86_avx512_ktestz_d;
- break;
- case X86::BI__builtin_ia32_ktestcdi:
- IID = Intrinsic::x86_avx512_ktestc_q;
- break;
- case X86::BI__builtin_ia32_ktestzdi:
- IID = Intrinsic::x86_avx512_ktestz_q;
- break;
- }
-
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
- Value *LHS = getMaskVecValue(*this, Ops[0], NumElts);
- Value *RHS = getMaskVecValue(*this, Ops[1], NumElts);
- Function *Intr = CGM.getIntrinsic(IID);
- return Builder.CreateCall(Intr, {LHS, RHS});
- }
-
- case X86::BI__builtin_ia32_kaddqi:
- case X86::BI__builtin_ia32_kaddhi:
- case X86::BI__builtin_ia32_kaddsi:
- case X86::BI__builtin_ia32_kadddi: {
- Intrinsic::ID IID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_kaddqi:
- IID = Intrinsic::x86_avx512_kadd_b;
- break;
- case X86::BI__builtin_ia32_kaddhi:
- IID = Intrinsic::x86_avx512_kadd_w;
- break;
- case X86::BI__builtin_ia32_kaddsi:
- IID = Intrinsic::x86_avx512_kadd_d;
- break;
- case X86::BI__builtin_ia32_kadddi:
- IID = Intrinsic::x86_avx512_kadd_q;
- break;
- }
-
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
- Value *LHS = getMaskVecValue(*this, Ops[0], NumElts);
- Value *RHS = getMaskVecValue(*this, Ops[1], NumElts);
- Function *Intr = CGM.getIntrinsic(IID);
- Value *Res = Builder.CreateCall(Intr, {LHS, RHS});
- return Builder.CreateBitCast(Res, Ops[0]->getType());
- }
- case X86::BI__builtin_ia32_kandqi:
- case X86::BI__builtin_ia32_kandhi:
- case X86::BI__builtin_ia32_kandsi:
- case X86::BI__builtin_ia32_kanddi:
- return EmitX86MaskLogic(*this, Instruction::And, Ops);
- case X86::BI__builtin_ia32_kandnqi:
- case X86::BI__builtin_ia32_kandnhi:
- case X86::BI__builtin_ia32_kandnsi:
- case X86::BI__builtin_ia32_kandndi:
- return EmitX86MaskLogic(*this, Instruction::And, Ops, true);
- case X86::BI__builtin_ia32_korqi:
- case X86::BI__builtin_ia32_korhi:
- case X86::BI__builtin_ia32_korsi:
- case X86::BI__builtin_ia32_kordi:
- return EmitX86MaskLogic(*this, Instruction::Or, Ops);
- case X86::BI__builtin_ia32_kxnorqi:
- case X86::BI__builtin_ia32_kxnorhi:
- case X86::BI__builtin_ia32_kxnorsi:
- case X86::BI__builtin_ia32_kxnordi:
- return EmitX86MaskLogic(*this, Instruction::Xor, Ops, true);
- case X86::BI__builtin_ia32_kxorqi:
- case X86::BI__builtin_ia32_kxorhi:
- case X86::BI__builtin_ia32_kxorsi:
- case X86::BI__builtin_ia32_kxordi:
- return EmitX86MaskLogic(*this, Instruction::Xor, Ops);
- case X86::BI__builtin_ia32_knotqi:
- case X86::BI__builtin_ia32_knothi:
- case X86::BI__builtin_ia32_knotsi:
- case X86::BI__builtin_ia32_knotdi: {
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
- Value *Res = getMaskVecValue(*this, Ops[0], NumElts);
- return Builder.CreateBitCast(Builder.CreateNot(Res),
- Ops[0]->getType());
- }
- case X86::BI__builtin_ia32_kmovb:
- case X86::BI__builtin_ia32_kmovw:
- case X86::BI__builtin_ia32_kmovd:
- case X86::BI__builtin_ia32_kmovq: {
- // Bitcast to vXi1 type and then back to integer. This gets the mask
- // register type into the IR, but might be optimized out depending on
- // what's around it.
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
- Value *Res = getMaskVecValue(*this, Ops[0], NumElts);
- return Builder.CreateBitCast(Res, Ops[0]->getType());
- }
-
- case X86::BI__builtin_ia32_kunpckdi:
- case X86::BI__builtin_ia32_kunpcksi:
- case X86::BI__builtin_ia32_kunpckhi: {
- unsigned NumElts = Ops[0]->getType()->getIntegerBitWidth();
- Value *LHS = getMaskVecValue(*this, Ops[0], NumElts);
- Value *RHS = getMaskVecValue(*this, Ops[1], NumElts);
- uint32_t Indices[64];
- for (unsigned i = 0; i != NumElts; ++i)
- Indices[i] = i;
-
- // First extract half of each vector. This gives better codegen than
- // doing it in a single shuffle.
- LHS = Builder.CreateShuffleVector(LHS, LHS,
- makeArrayRef(Indices, NumElts / 2));
- RHS = Builder.CreateShuffleVector(RHS, RHS,
- makeArrayRef(Indices, NumElts / 2));
- // Concat the vectors.
- // NOTE: Operands are swapped to match the intrinsic definition.
- Value *Res = Builder.CreateShuffleVector(RHS, LHS,
- makeArrayRef(Indices, NumElts));
- return Builder.CreateBitCast(Res, Ops[0]->getType());
- }
-
- case X86::BI__builtin_ia32_vplzcntd_128:
- case X86::BI__builtin_ia32_vplzcntd_256:
- case X86::BI__builtin_ia32_vplzcntd_512:
- case X86::BI__builtin_ia32_vplzcntq_128:
- case X86::BI__builtin_ia32_vplzcntq_256:
- case X86::BI__builtin_ia32_vplzcntq_512: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ops[0]->getType());
- return Builder.CreateCall(F, {Ops[0],Builder.getInt1(false)});
- }
- case X86::BI__builtin_ia32_sqrtss:
- case X86::BI__builtin_ia32_sqrtsd: {
- Value *A = Builder.CreateExtractElement(Ops[0], (uint64_t)0);
- Function *F = CGM.getIntrinsic(Intrinsic::sqrt, A->getType());
- A = Builder.CreateCall(F, {A});
- return Builder.CreateInsertElement(Ops[0], A, (uint64_t)0);
- }
- case X86::BI__builtin_ia32_sqrtsd_round_mask:
- case X86::BI__builtin_ia32_sqrtss_round_mask: {
- unsigned CC = cast<llvm::ConstantInt>(Ops[4])->getZExtValue();
- // Support only if the rounding mode is 4 (AKA CUR_DIRECTION),
- // otherwise keep the intrinsic.
- if (CC != 4) {
- Intrinsic::ID IID = BuiltinID == X86::BI__builtin_ia32_sqrtsd_round_mask ?
- Intrinsic::x86_avx512_mask_sqrt_sd :
- Intrinsic::x86_avx512_mask_sqrt_ss;
- return Builder.CreateCall(CGM.getIntrinsic(IID), Ops);
- }
- Value *A = Builder.CreateExtractElement(Ops[1], (uint64_t)0);
- Function *F = CGM.getIntrinsic(Intrinsic::sqrt, A->getType());
- A = Builder.CreateCall(F, A);
- Value *Src = Builder.CreateExtractElement(Ops[2], (uint64_t)0);
- A = EmitX86ScalarSelect(*this, Ops[3], A, Src);
- return Builder.CreateInsertElement(Ops[0], A, (uint64_t)0);
- }
- case X86::BI__builtin_ia32_sqrtpd256:
- case X86::BI__builtin_ia32_sqrtpd:
- case X86::BI__builtin_ia32_sqrtps256:
- case X86::BI__builtin_ia32_sqrtps:
- case X86::BI__builtin_ia32_sqrtps512:
- case X86::BI__builtin_ia32_sqrtpd512: {
- if (Ops.size() == 2) {
- unsigned CC = cast<llvm::ConstantInt>(Ops[1])->getZExtValue();
- // Support only if the rounding mode is 4 (AKA CUR_DIRECTION),
- // otherwise keep the intrinsic.
- if (CC != 4) {
- Intrinsic::ID IID = BuiltinID == X86::BI__builtin_ia32_sqrtps512 ?
- Intrinsic::x86_avx512_sqrt_ps_512 :
- Intrinsic::x86_avx512_sqrt_pd_512;
- return Builder.CreateCall(CGM.getIntrinsic(IID), Ops);
- }
- }
- Function *F = CGM.getIntrinsic(Intrinsic::sqrt, Ops[0]->getType());
- return Builder.CreateCall(F, Ops[0]);
- }
- case X86::BI__builtin_ia32_pabsb128:
- case X86::BI__builtin_ia32_pabsw128:
- case X86::BI__builtin_ia32_pabsd128:
- case X86::BI__builtin_ia32_pabsb256:
- case X86::BI__builtin_ia32_pabsw256:
- case X86::BI__builtin_ia32_pabsd256:
- case X86::BI__builtin_ia32_pabsq128:
- case X86::BI__builtin_ia32_pabsq256:
- case X86::BI__builtin_ia32_pabsb512:
- case X86::BI__builtin_ia32_pabsw512:
- case X86::BI__builtin_ia32_pabsd512:
- case X86::BI__builtin_ia32_pabsq512:
- return EmitX86Abs(*this, Ops);
-
- case X86::BI__builtin_ia32_pmaxsb128:
- case X86::BI__builtin_ia32_pmaxsw128:
- case X86::BI__builtin_ia32_pmaxsd128:
- case X86::BI__builtin_ia32_pmaxsq128:
- case X86::BI__builtin_ia32_pmaxsb256:
- case X86::BI__builtin_ia32_pmaxsw256:
- case X86::BI__builtin_ia32_pmaxsd256:
- case X86::BI__builtin_ia32_pmaxsq256:
- case X86::BI__builtin_ia32_pmaxsb512:
- case X86::BI__builtin_ia32_pmaxsw512:
- case X86::BI__builtin_ia32_pmaxsd512:
- case X86::BI__builtin_ia32_pmaxsq512:
- return EmitX86MinMax(*this, ICmpInst::ICMP_SGT, Ops);
- case X86::BI__builtin_ia32_pmaxub128:
- case X86::BI__builtin_ia32_pmaxuw128:
- case X86::BI__builtin_ia32_pmaxud128:
- case X86::BI__builtin_ia32_pmaxuq128:
- case X86::BI__builtin_ia32_pmaxub256:
- case X86::BI__builtin_ia32_pmaxuw256:
- case X86::BI__builtin_ia32_pmaxud256:
- case X86::BI__builtin_ia32_pmaxuq256:
- case X86::BI__builtin_ia32_pmaxub512:
- case X86::BI__builtin_ia32_pmaxuw512:
- case X86::BI__builtin_ia32_pmaxud512:
- case X86::BI__builtin_ia32_pmaxuq512:
- return EmitX86MinMax(*this, ICmpInst::ICMP_UGT, Ops);
- case X86::BI__builtin_ia32_pminsb128:
- case X86::BI__builtin_ia32_pminsw128:
- case X86::BI__builtin_ia32_pminsd128:
- case X86::BI__builtin_ia32_pminsq128:
- case X86::BI__builtin_ia32_pminsb256:
- case X86::BI__builtin_ia32_pminsw256:
- case X86::BI__builtin_ia32_pminsd256:
- case X86::BI__builtin_ia32_pminsq256:
- case X86::BI__builtin_ia32_pminsb512:
- case X86::BI__builtin_ia32_pminsw512:
- case X86::BI__builtin_ia32_pminsd512:
- case X86::BI__builtin_ia32_pminsq512:
- return EmitX86MinMax(*this, ICmpInst::ICMP_SLT, Ops);
- case X86::BI__builtin_ia32_pminub128:
- case X86::BI__builtin_ia32_pminuw128:
- case X86::BI__builtin_ia32_pminud128:
- case X86::BI__builtin_ia32_pminuq128:
- case X86::BI__builtin_ia32_pminub256:
- case X86::BI__builtin_ia32_pminuw256:
- case X86::BI__builtin_ia32_pminud256:
- case X86::BI__builtin_ia32_pminuq256:
- case X86::BI__builtin_ia32_pminub512:
- case X86::BI__builtin_ia32_pminuw512:
- case X86::BI__builtin_ia32_pminud512:
- case X86::BI__builtin_ia32_pminuq512:
- return EmitX86MinMax(*this, ICmpInst::ICMP_ULT, Ops);
-
- case X86::BI__builtin_ia32_pmuludq128:
- case X86::BI__builtin_ia32_pmuludq256:
- case X86::BI__builtin_ia32_pmuludq512:
- return EmitX86Muldq(*this, /*IsSigned*/false, Ops);
-
- case X86::BI__builtin_ia32_pmuldq128:
- case X86::BI__builtin_ia32_pmuldq256:
- case X86::BI__builtin_ia32_pmuldq512:
- return EmitX86Muldq(*this, /*IsSigned*/true, Ops);
-
- case X86::BI__builtin_ia32_pternlogd512_mask:
- case X86::BI__builtin_ia32_pternlogq512_mask:
- case X86::BI__builtin_ia32_pternlogd128_mask:
- case X86::BI__builtin_ia32_pternlogd256_mask:
- case X86::BI__builtin_ia32_pternlogq128_mask:
- case X86::BI__builtin_ia32_pternlogq256_mask:
- return EmitX86Ternlog(*this, /*ZeroMask*/false, Ops);
-
- case X86::BI__builtin_ia32_pternlogd512_maskz:
- case X86::BI__builtin_ia32_pternlogq512_maskz:
- case X86::BI__builtin_ia32_pternlogd128_maskz:
- case X86::BI__builtin_ia32_pternlogd256_maskz:
- case X86::BI__builtin_ia32_pternlogq128_maskz:
- case X86::BI__builtin_ia32_pternlogq256_maskz:
- return EmitX86Ternlog(*this, /*ZeroMask*/true, Ops);
-
- case X86::BI__builtin_ia32_vpshldd128:
- case X86::BI__builtin_ia32_vpshldd256:
- case X86::BI__builtin_ia32_vpshldd512:
- case X86::BI__builtin_ia32_vpshldq128:
- case X86::BI__builtin_ia32_vpshldq256:
- case X86::BI__builtin_ia32_vpshldq512:
- case X86::BI__builtin_ia32_vpshldw128:
- case X86::BI__builtin_ia32_vpshldw256:
- case X86::BI__builtin_ia32_vpshldw512:
- return EmitX86FunnelShift(*this, Ops[0], Ops[1], Ops[2], false);
-
- case X86::BI__builtin_ia32_vpshrdd128:
- case X86::BI__builtin_ia32_vpshrdd256:
- case X86::BI__builtin_ia32_vpshrdd512:
- case X86::BI__builtin_ia32_vpshrdq128:
- case X86::BI__builtin_ia32_vpshrdq256:
- case X86::BI__builtin_ia32_vpshrdq512:
- case X86::BI__builtin_ia32_vpshrdw128:
- case X86::BI__builtin_ia32_vpshrdw256:
- case X86::BI__builtin_ia32_vpshrdw512:
- // Ops 0 and 1 are swapped.
- return EmitX86FunnelShift(*this, Ops[1], Ops[0], Ops[2], true);
-
- case X86::BI__builtin_ia32_vpshldvd128:
- case X86::BI__builtin_ia32_vpshldvd256:
- case X86::BI__builtin_ia32_vpshldvd512:
- case X86::BI__builtin_ia32_vpshldvq128:
- case X86::BI__builtin_ia32_vpshldvq256:
- case X86::BI__builtin_ia32_vpshldvq512:
- case X86::BI__builtin_ia32_vpshldvw128:
- case X86::BI__builtin_ia32_vpshldvw256:
- case X86::BI__builtin_ia32_vpshldvw512:
- return EmitX86FunnelShift(*this, Ops[0], Ops[1], Ops[2], false);
-
- case X86::BI__builtin_ia32_vpshrdvd128:
- case X86::BI__builtin_ia32_vpshrdvd256:
- case X86::BI__builtin_ia32_vpshrdvd512:
- case X86::BI__builtin_ia32_vpshrdvq128:
- case X86::BI__builtin_ia32_vpshrdvq256:
- case X86::BI__builtin_ia32_vpshrdvq512:
- case X86::BI__builtin_ia32_vpshrdvw128:
- case X86::BI__builtin_ia32_vpshrdvw256:
- case X86::BI__builtin_ia32_vpshrdvw512:
- // Ops 0 and 1 are swapped.
- return EmitX86FunnelShift(*this, Ops[1], Ops[0], Ops[2], true);
-
- // 3DNow!
- case X86::BI__builtin_ia32_pswapdsf:
- case X86::BI__builtin_ia32_pswapdsi: {
- llvm::Type *MMXTy = llvm::Type::getX86_MMXTy(getLLVMContext());
- Ops[0] = Builder.CreateBitCast(Ops[0], MMXTy, "cast");
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_3dnowa_pswapd);
- return Builder.CreateCall(F, Ops, "pswapd");
- }
- case X86::BI__builtin_ia32_rdrand16_step:
- case X86::BI__builtin_ia32_rdrand32_step:
- case X86::BI__builtin_ia32_rdrand64_step:
- case X86::BI__builtin_ia32_rdseed16_step:
- case X86::BI__builtin_ia32_rdseed32_step:
- case X86::BI__builtin_ia32_rdseed64_step: {
- Intrinsic::ID ID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_rdrand16_step:
- ID = Intrinsic::x86_rdrand_16;
- break;
- case X86::BI__builtin_ia32_rdrand32_step:
- ID = Intrinsic::x86_rdrand_32;
- break;
- case X86::BI__builtin_ia32_rdrand64_step:
- ID = Intrinsic::x86_rdrand_64;
- break;
- case X86::BI__builtin_ia32_rdseed16_step:
- ID = Intrinsic::x86_rdseed_16;
- break;
- case X86::BI__builtin_ia32_rdseed32_step:
- ID = Intrinsic::x86_rdseed_32;
- break;
- case X86::BI__builtin_ia32_rdseed64_step:
- ID = Intrinsic::x86_rdseed_64;
- break;
- }
-
- Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID));
- Builder.CreateDefaultAlignedStore(Builder.CreateExtractValue(Call, 0),
- Ops[0]);
- return Builder.CreateExtractValue(Call, 1);
- }
- case X86::BI__builtin_ia32_addcarryx_u32:
- case X86::BI__builtin_ia32_addcarryx_u64:
- case X86::BI__builtin_ia32_subborrow_u32:
- case X86::BI__builtin_ia32_subborrow_u64: {
- Intrinsic::ID IID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_addcarryx_u32:
- IID = Intrinsic::x86_addcarry_32;
- break;
- case X86::BI__builtin_ia32_addcarryx_u64:
- IID = Intrinsic::x86_addcarry_64;
- break;
- case X86::BI__builtin_ia32_subborrow_u32:
- IID = Intrinsic::x86_subborrow_32;
- break;
- case X86::BI__builtin_ia32_subborrow_u64:
- IID = Intrinsic::x86_subborrow_64;
- break;
- }
-
- Value *Call = Builder.CreateCall(CGM.getIntrinsic(IID),
- { Ops[0], Ops[1], Ops[2] });
- Builder.CreateDefaultAlignedStore(Builder.CreateExtractValue(Call, 1),
- Ops[3]);
- return Builder.CreateExtractValue(Call, 0);
- }
-
- case X86::BI__builtin_ia32_fpclassps128_mask:
- case X86::BI__builtin_ia32_fpclassps256_mask:
- case X86::BI__builtin_ia32_fpclassps512_mask:
- case X86::BI__builtin_ia32_fpclasspd128_mask:
- case X86::BI__builtin_ia32_fpclasspd256_mask:
- case X86::BI__builtin_ia32_fpclasspd512_mask: {
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- Value *MaskIn = Ops[2];
- Ops.erase(&Ops[2]);
-
- Intrinsic::ID ID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_fpclassps128_mask:
- ID = Intrinsic::x86_avx512_fpclass_ps_128;
- break;
- case X86::BI__builtin_ia32_fpclassps256_mask:
- ID = Intrinsic::x86_avx512_fpclass_ps_256;
- break;
- case X86::BI__builtin_ia32_fpclassps512_mask:
- ID = Intrinsic::x86_avx512_fpclass_ps_512;
- break;
- case X86::BI__builtin_ia32_fpclasspd128_mask:
- ID = Intrinsic::x86_avx512_fpclass_pd_128;
- break;
- case X86::BI__builtin_ia32_fpclasspd256_mask:
- ID = Intrinsic::x86_avx512_fpclass_pd_256;
- break;
- case X86::BI__builtin_ia32_fpclasspd512_mask:
- ID = Intrinsic::x86_avx512_fpclass_pd_512;
- break;
- }
-
- Value *Fpclass = Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
- return EmitX86MaskedCompareResult(*this, Fpclass, NumElts, MaskIn);
- }
-
- case X86::BI__builtin_ia32_vpmultishiftqb128:
- case X86::BI__builtin_ia32_vpmultishiftqb256:
- case X86::BI__builtin_ia32_vpmultishiftqb512: {
- Intrinsic::ID ID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_vpmultishiftqb128:
- ID = Intrinsic::x86_avx512_pmultishift_qb_128;
- break;
- case X86::BI__builtin_ia32_vpmultishiftqb256:
- ID = Intrinsic::x86_avx512_pmultishift_qb_256;
- break;
- case X86::BI__builtin_ia32_vpmultishiftqb512:
- ID = Intrinsic::x86_avx512_pmultishift_qb_512;
- break;
- }
-
- return Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
- }
-
- case X86::BI__builtin_ia32_vpshufbitqmb128_mask:
- case X86::BI__builtin_ia32_vpshufbitqmb256_mask:
- case X86::BI__builtin_ia32_vpshufbitqmb512_mask: {
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- Value *MaskIn = Ops[2];
- Ops.erase(&Ops[2]);
-
- Intrinsic::ID ID;
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported intrinsic!");
- case X86::BI__builtin_ia32_vpshufbitqmb128_mask:
- ID = Intrinsic::x86_avx512_vpshufbitqmb_128;
- break;
- case X86::BI__builtin_ia32_vpshufbitqmb256_mask:
- ID = Intrinsic::x86_avx512_vpshufbitqmb_256;
- break;
- case X86::BI__builtin_ia32_vpshufbitqmb512_mask:
- ID = Intrinsic::x86_avx512_vpshufbitqmb_512;
- break;
- }
-
- Value *Shufbit = Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
- return EmitX86MaskedCompareResult(*this, Shufbit, NumElts, MaskIn);
- }
-
- // packed comparison intrinsics
- case X86::BI__builtin_ia32_cmpeqps:
- case X86::BI__builtin_ia32_cmpeqpd:
- return getVectorFCmpIR(CmpInst::FCMP_OEQ);
- case X86::BI__builtin_ia32_cmpltps:
- case X86::BI__builtin_ia32_cmpltpd:
- return getVectorFCmpIR(CmpInst::FCMP_OLT);
- case X86::BI__builtin_ia32_cmpleps:
- case X86::BI__builtin_ia32_cmplepd:
- return getVectorFCmpIR(CmpInst::FCMP_OLE);
- case X86::BI__builtin_ia32_cmpunordps:
- case X86::BI__builtin_ia32_cmpunordpd:
- return getVectorFCmpIR(CmpInst::FCMP_UNO);
- case X86::BI__builtin_ia32_cmpneqps:
- case X86::BI__builtin_ia32_cmpneqpd:
- return getVectorFCmpIR(CmpInst::FCMP_UNE);
- case X86::BI__builtin_ia32_cmpnltps:
- case X86::BI__builtin_ia32_cmpnltpd:
- return getVectorFCmpIR(CmpInst::FCMP_UGE);
- case X86::BI__builtin_ia32_cmpnleps:
- case X86::BI__builtin_ia32_cmpnlepd:
- return getVectorFCmpIR(CmpInst::FCMP_UGT);
- case X86::BI__builtin_ia32_cmpordps:
- case X86::BI__builtin_ia32_cmpordpd:
- return getVectorFCmpIR(CmpInst::FCMP_ORD);
- case X86::BI__builtin_ia32_cmpps:
- case X86::BI__builtin_ia32_cmpps256:
- case X86::BI__builtin_ia32_cmppd:
- case X86::BI__builtin_ia32_cmppd256:
- case X86::BI__builtin_ia32_cmpps128_mask:
- case X86::BI__builtin_ia32_cmpps256_mask:
- case X86::BI__builtin_ia32_cmpps512_mask:
- case X86::BI__builtin_ia32_cmppd128_mask:
- case X86::BI__builtin_ia32_cmppd256_mask:
- case X86::BI__builtin_ia32_cmppd512_mask: {
- // Lowering vector comparisons to fcmp instructions, while
- // ignoring signalling behaviour requested
- // ignoring rounding mode requested
- // This is is only possible as long as FENV_ACCESS is not implemented.
- // See also: https://reviews.llvm.org/D45616
-
- // The third argument is the comparison condition, and integer in the
- // range [0, 31]
- unsigned CC = cast<llvm::ConstantInt>(Ops[2])->getZExtValue() & 0x1f;
-
- // Lowering to IR fcmp instruction.
- // Ignoring requested signaling behaviour,
- // e.g. both _CMP_GT_OS & _CMP_GT_OQ are translated to FCMP_OGT.
- FCmpInst::Predicate Pred;
- switch (CC) {
- case 0x00: Pred = FCmpInst::FCMP_OEQ; break;
- case 0x01: Pred = FCmpInst::FCMP_OLT; break;
- case 0x02: Pred = FCmpInst::FCMP_OLE; break;
- case 0x03: Pred = FCmpInst::FCMP_UNO; break;
- case 0x04: Pred = FCmpInst::FCMP_UNE; break;
- case 0x05: Pred = FCmpInst::FCMP_UGE; break;
- case 0x06: Pred = FCmpInst::FCMP_UGT; break;
- case 0x07: Pred = FCmpInst::FCMP_ORD; break;
- case 0x08: Pred = FCmpInst::FCMP_UEQ; break;
- case 0x09: Pred = FCmpInst::FCMP_ULT; break;
- case 0x0a: Pred = FCmpInst::FCMP_ULE; break;
- case 0x0b: Pred = FCmpInst::FCMP_FALSE; break;
- case 0x0c: Pred = FCmpInst::FCMP_ONE; break;
- case 0x0d: Pred = FCmpInst::FCMP_OGE; break;
- case 0x0e: Pred = FCmpInst::FCMP_OGT; break;
- case 0x0f: Pred = FCmpInst::FCMP_TRUE; break;
- case 0x10: Pred = FCmpInst::FCMP_OEQ; break;
- case 0x11: Pred = FCmpInst::FCMP_OLT; break;
- case 0x12: Pred = FCmpInst::FCMP_OLE; break;
- case 0x13: Pred = FCmpInst::FCMP_UNO; break;
- case 0x14: Pred = FCmpInst::FCMP_UNE; break;
- case 0x15: Pred = FCmpInst::FCMP_UGE; break;
- case 0x16: Pred = FCmpInst::FCMP_UGT; break;
- case 0x17: Pred = FCmpInst::FCMP_ORD; break;
- case 0x18: Pred = FCmpInst::FCMP_UEQ; break;
- case 0x19: Pred = FCmpInst::FCMP_ULT; break;
- case 0x1a: Pred = FCmpInst::FCMP_ULE; break;
- case 0x1b: Pred = FCmpInst::FCMP_FALSE; break;
- case 0x1c: Pred = FCmpInst::FCMP_ONE; break;
- case 0x1d: Pred = FCmpInst::FCMP_OGE; break;
- case 0x1e: Pred = FCmpInst::FCMP_OGT; break;
- case 0x1f: Pred = FCmpInst::FCMP_TRUE; break;
- default: llvm_unreachable("Unhandled CC");
- }
-
- // Builtins without the _mask suffix return a vector of integers
- // of the same width as the input vectors
- switch (BuiltinID) {
- case X86::BI__builtin_ia32_cmpps512_mask:
- case X86::BI__builtin_ia32_cmppd512_mask:
- case X86::BI__builtin_ia32_cmpps128_mask:
- case X86::BI__builtin_ia32_cmpps256_mask:
- case X86::BI__builtin_ia32_cmppd128_mask:
- case X86::BI__builtin_ia32_cmppd256_mask: {
- unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
- Value *Cmp = Builder.CreateFCmp(Pred, Ops[0], Ops[1]);
- return EmitX86MaskedCompareResult(*this, Cmp, NumElts, Ops[3]);
- }
- default:
- return getVectorFCmpIR(Pred);
- }
- }
-
- // SSE scalar comparison intrinsics
- case X86::BI__builtin_ia32_cmpeqss:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 0);
- case X86::BI__builtin_ia32_cmpltss:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 1);
- case X86::BI__builtin_ia32_cmpless:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 2);
- case X86::BI__builtin_ia32_cmpunordss:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 3);
- case X86::BI__builtin_ia32_cmpneqss:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 4);
- case X86::BI__builtin_ia32_cmpnltss:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 5);
- case X86::BI__builtin_ia32_cmpnless:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 6);
- case X86::BI__builtin_ia32_cmpordss:
- return getCmpIntrinsicCall(Intrinsic::x86_sse_cmp_ss, 7);
- case X86::BI__builtin_ia32_cmpeqsd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 0);
- case X86::BI__builtin_ia32_cmpltsd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 1);
- case X86::BI__builtin_ia32_cmplesd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 2);
- case X86::BI__builtin_ia32_cmpunordsd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 3);
- case X86::BI__builtin_ia32_cmpneqsd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 4);
- case X86::BI__builtin_ia32_cmpnltsd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 5);
- case X86::BI__builtin_ia32_cmpnlesd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 6);
- case X86::BI__builtin_ia32_cmpordsd:
- return getCmpIntrinsicCall(Intrinsic::x86_sse2_cmp_sd, 7);
-
- case X86::BI__emul:
- case X86::BI__emulu: {
- llvm::Type *Int64Ty = llvm::IntegerType::get(getLLVMContext(), 64);
- bool isSigned = (BuiltinID == X86::BI__emul);
- Value *LHS = Builder.CreateIntCast(Ops[0], Int64Ty, isSigned);
- Value *RHS = Builder.CreateIntCast(Ops[1], Int64Ty, isSigned);
- return Builder.CreateMul(LHS, RHS, "", !isSigned, isSigned);
- }
- case X86::BI__mulh:
- case X86::BI__umulh:
- case X86::BI_mul128:
- case X86::BI_umul128: {
- llvm::Type *ResType = ConvertType(E->getType());
- llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128);
-
- bool IsSigned = (BuiltinID == X86::BI__mulh || BuiltinID == X86::BI_mul128);
- Value *LHS = Builder.CreateIntCast(Ops[0], Int128Ty, IsSigned);
- Value *RHS = Builder.CreateIntCast(Ops[1], Int128Ty, IsSigned);
-
- Value *MulResult, *HigherBits;
- if (IsSigned) {
- MulResult = Builder.CreateNSWMul(LHS, RHS);
- HigherBits = Builder.CreateAShr(MulResult, 64);
- } else {
- MulResult = Builder.CreateNUWMul(LHS, RHS);
- HigherBits = Builder.CreateLShr(MulResult, 64);
- }
- HigherBits = Builder.CreateIntCast(HigherBits, ResType, IsSigned);
-
- if (BuiltinID == X86::BI__mulh || BuiltinID == X86::BI__umulh)
- return HigherBits;
-
- Address HighBitsAddress = EmitPointerWithAlignment(E->getArg(2));
- Builder.CreateStore(HigherBits, HighBitsAddress);
- return Builder.CreateIntCast(MulResult, ResType, IsSigned);
- }
-
- case X86::BI__faststorefence: {
- return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::SyncScope::System);
- }
- case X86::BI__shiftleft128:
- case X86::BI__shiftright128: {
- // FIXME: Once fshl/fshr no longer add an unneeded and and cmov, do this:
- // llvm::Function *F = CGM.getIntrinsic(
- // BuiltinID == X86::BI__shiftleft128 ? Intrinsic::fshl : Intrinsic::fshr,
- // Int64Ty);
- // Ops[2] = Builder.CreateZExt(Ops[2], Int64Ty);
- // return Builder.CreateCall(F, Ops);
- llvm::Type *Int128Ty = Builder.getInt128Ty();
- Value *Val = Builder.CreateOr(
- Builder.CreateShl(Builder.CreateZExt(Ops[1], Int128Ty), 64),
- Builder.CreateZExt(Ops[0], Int128Ty));
- Value *Amt = Builder.CreateAnd(Builder.CreateZExt(Ops[2], Int128Ty),
- llvm::ConstantInt::get(Int128Ty, 0x3f));
- Value *Res;
- if (BuiltinID == X86::BI__shiftleft128)
- Res = Builder.CreateLShr(Builder.CreateShl(Val, Amt), 64);
- else
- Res = Builder.CreateLShr(Val, Amt);
- return Builder.CreateTrunc(Res, Int64Ty);
- }
- case X86::BI_ReadWriteBarrier:
- case X86::BI_ReadBarrier:
- case X86::BI_WriteBarrier: {
- return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::SyncScope::SingleThread);
- }
- case X86::BI_BitScanForward:
- case X86::BI_BitScanForward64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E);
- case X86::BI_BitScanReverse:
- case X86::BI_BitScanReverse64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E);
-
- case X86::BI_InterlockedAnd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E);
- case X86::BI_InterlockedExchange64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E);
- case X86::BI_InterlockedExchangeAdd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E);
- case X86::BI_InterlockedExchangeSub64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E);
- case X86::BI_InterlockedOr64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E);
- case X86::BI_InterlockedXor64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E);
- case X86::BI_InterlockedDecrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E);
- case X86::BI_InterlockedIncrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E);
- case X86::BI_InterlockedCompareExchange128: {
- // InterlockedCompareExchange128 doesn't directly refer to 128bit ints,
- // instead it takes pointers to 64bit ints for Destination and
- // ComparandResult, and exchange is taken as two 64bit ints (high & low).
- // The previous value is written to ComparandResult, and success is
- // returned.
-
- llvm::Type *Int128Ty = Builder.getInt128Ty();
- llvm::Type *Int128PtrTy = Int128Ty->getPointerTo();
-
- Value *Destination =
- Builder.CreateBitCast(Ops[0], Int128PtrTy);
- Value *ExchangeHigh128 = Builder.CreateZExt(Ops[1], Int128Ty);
- Value *ExchangeLow128 = Builder.CreateZExt(Ops[2], Int128Ty);
- Address ComparandResult(Builder.CreateBitCast(Ops[3], Int128PtrTy),
- getContext().toCharUnitsFromBits(128));
-
- Value *Exchange = Builder.CreateOr(
- Builder.CreateShl(ExchangeHigh128, 64, "", false, false),
- ExchangeLow128);
-
- Value *Comparand = Builder.CreateLoad(ComparandResult);
-
- AtomicCmpXchgInst *CXI =
- Builder.CreateAtomicCmpXchg(Destination, Comparand, Exchange,
- AtomicOrdering::SequentiallyConsistent,
- AtomicOrdering::SequentiallyConsistent);
- CXI->setVolatile(true);
-
- // Write the result back to the inout pointer.
- Builder.CreateStore(Builder.CreateExtractValue(CXI, 0), ComparandResult);
-
- // Get the success boolean and zero extend it to i8.
- Value *Success = Builder.CreateExtractValue(CXI, 1);
- return Builder.CreateZExt(Success, ConvertType(E->getType()));
- }
-
- case X86::BI_AddressOfReturnAddress: {
- Value *F = CGM.getIntrinsic(Intrinsic::addressofreturnaddress);
- return Builder.CreateCall(F);
- }
- case X86::BI__stosb: {
- // We treat __stosb as a volatile memset - it may not generate "rep stosb"
- // instruction, but it will create a memset that won't be optimized away.
- return Builder.CreateMemSet(Ops[0], Ops[1], Ops[2], 1, true);
- }
- case X86::BI__ud2:
- // llvm.trap makes a ud2a instruction on x86.
- return EmitTrapCall(Intrinsic::trap);
- case X86::BI__int2c: {
- // This syscall signals a driver assertion failure in x86 NT kernels.
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, "int $$0x2c", "", /*SideEffects=*/true);
- llvm::AttributeList NoReturnAttr = llvm::AttributeList::get(
- getLLVMContext(), llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoReturn);
- CallSite CS = Builder.CreateCall(IA);
- CS.setAttributes(NoReturnAttr);
- return CS.getInstruction();
- }
- case X86::BI__readfsbyte:
- case X86::BI__readfsword:
- case X86::BI__readfsdword:
- case X86::BI__readfsqword: {
- llvm::Type *IntTy = ConvertType(E->getType());
- Value *Ptr =
- Builder.CreateIntToPtr(Ops[0], llvm::PointerType::get(IntTy, 257));
- LoadInst *Load = Builder.CreateAlignedLoad(
- IntTy, Ptr, getContext().getTypeAlignInChars(E->getType()));
- Load->setVolatile(true);
- return Load;
- }
- case X86::BI__readgsbyte:
- case X86::BI__readgsword:
- case X86::BI__readgsdword:
- case X86::BI__readgsqword: {
- llvm::Type *IntTy = ConvertType(E->getType());
- Value *Ptr =
- Builder.CreateIntToPtr(Ops[0], llvm::PointerType::get(IntTy, 256));
- LoadInst *Load = Builder.CreateAlignedLoad(
- IntTy, Ptr, getContext().getTypeAlignInChars(E->getType()));
- Load->setVolatile(true);
- return Load;
- }
- case X86::BI__builtin_ia32_paddsb512:
- case X86::BI__builtin_ia32_paddsw512:
- case X86::BI__builtin_ia32_paddsb256:
- case X86::BI__builtin_ia32_paddsw256:
- case X86::BI__builtin_ia32_paddsb128:
- case X86::BI__builtin_ia32_paddsw128:
- return EmitX86AddSubSatExpr(*this, Ops, true, true);
- case X86::BI__builtin_ia32_paddusb512:
- case X86::BI__builtin_ia32_paddusw512:
- case X86::BI__builtin_ia32_paddusb256:
- case X86::BI__builtin_ia32_paddusw256:
- case X86::BI__builtin_ia32_paddusb128:
- case X86::BI__builtin_ia32_paddusw128:
- return EmitX86AddSubSatExpr(*this, Ops, false, true);
- case X86::BI__builtin_ia32_psubsb512:
- case X86::BI__builtin_ia32_psubsw512:
- case X86::BI__builtin_ia32_psubsb256:
- case X86::BI__builtin_ia32_psubsw256:
- case X86::BI__builtin_ia32_psubsb128:
- case X86::BI__builtin_ia32_psubsw128:
- return EmitX86AddSubSatExpr(*this, Ops, true, false);
- case X86::BI__builtin_ia32_psubusb512:
- case X86::BI__builtin_ia32_psubusw512:
- case X86::BI__builtin_ia32_psubusb256:
- case X86::BI__builtin_ia32_psubusw256:
- case X86::BI__builtin_ia32_psubusb128:
- case X86::BI__builtin_ia32_psubusw128:
- return EmitX86AddSubSatExpr(*this, Ops, false, false);
- }
-}
-
-Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- SmallVector<Value*, 4> Ops;
-
- for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
- Ops.push_back(EmitScalarExpr(E->getArg(i)));
-
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
-
- switch (BuiltinID) {
- default: return nullptr;
-
- // __builtin_ppc_get_timebase is GCC 4.8+'s PowerPC-specific name for what we
- // call __builtin_readcyclecounter.
- case PPC::BI__builtin_ppc_get_timebase:
- return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::readcyclecounter));
-
- // vec_ld, vec_xl_be, vec_lvsl, vec_lvsr
- case PPC::BI__builtin_altivec_lvx:
- case PPC::BI__builtin_altivec_lvxl:
- case PPC::BI__builtin_altivec_lvebx:
- case PPC::BI__builtin_altivec_lvehx:
- case PPC::BI__builtin_altivec_lvewx:
- case PPC::BI__builtin_altivec_lvsl:
- case PPC::BI__builtin_altivec_lvsr:
- case PPC::BI__builtin_vsx_lxvd2x:
- case PPC::BI__builtin_vsx_lxvw4x:
- case PPC::BI__builtin_vsx_lxvd2x_be:
- case PPC::BI__builtin_vsx_lxvw4x_be:
- case PPC::BI__builtin_vsx_lxvl:
- case PPC::BI__builtin_vsx_lxvll:
- {
- if(BuiltinID == PPC::BI__builtin_vsx_lxvl ||
- BuiltinID == PPC::BI__builtin_vsx_lxvll){
- Ops[0] = Builder.CreateBitCast(Ops[0], Int8PtrTy);
- }else {
- Ops[1] = Builder.CreateBitCast(Ops[1], Int8PtrTy);
- Ops[0] = Builder.CreateGEP(Ops[1], Ops[0]);
- Ops.pop_back();
- }
-
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported ld/lvsl/lvsr intrinsic!");
- case PPC::BI__builtin_altivec_lvx:
- ID = Intrinsic::ppc_altivec_lvx;
- break;
- case PPC::BI__builtin_altivec_lvxl:
- ID = Intrinsic::ppc_altivec_lvxl;
- break;
- case PPC::BI__builtin_altivec_lvebx:
- ID = Intrinsic::ppc_altivec_lvebx;
- break;
- case PPC::BI__builtin_altivec_lvehx:
- ID = Intrinsic::ppc_altivec_lvehx;
- break;
- case PPC::BI__builtin_altivec_lvewx:
- ID = Intrinsic::ppc_altivec_lvewx;
- break;
- case PPC::BI__builtin_altivec_lvsl:
- ID = Intrinsic::ppc_altivec_lvsl;
- break;
- case PPC::BI__builtin_altivec_lvsr:
- ID = Intrinsic::ppc_altivec_lvsr;
- break;
- case PPC::BI__builtin_vsx_lxvd2x:
- ID = Intrinsic::ppc_vsx_lxvd2x;
- break;
- case PPC::BI__builtin_vsx_lxvw4x:
- ID = Intrinsic::ppc_vsx_lxvw4x;
- break;
- case PPC::BI__builtin_vsx_lxvd2x_be:
- ID = Intrinsic::ppc_vsx_lxvd2x_be;
- break;
- case PPC::BI__builtin_vsx_lxvw4x_be:
- ID = Intrinsic::ppc_vsx_lxvw4x_be;
- break;
- case PPC::BI__builtin_vsx_lxvl:
- ID = Intrinsic::ppc_vsx_lxvl;
- break;
- case PPC::BI__builtin_vsx_lxvll:
- ID = Intrinsic::ppc_vsx_lxvll;
- break;
- }
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, "");
- }
-
- // vec_st, vec_xst_be
- case PPC::BI__builtin_altivec_stvx:
- case PPC::BI__builtin_altivec_stvxl:
- case PPC::BI__builtin_altivec_stvebx:
- case PPC::BI__builtin_altivec_stvehx:
- case PPC::BI__builtin_altivec_stvewx:
- case PPC::BI__builtin_vsx_stxvd2x:
- case PPC::BI__builtin_vsx_stxvw4x:
- case PPC::BI__builtin_vsx_stxvd2x_be:
- case PPC::BI__builtin_vsx_stxvw4x_be:
- case PPC::BI__builtin_vsx_stxvl:
- case PPC::BI__builtin_vsx_stxvll:
- {
- if(BuiltinID == PPC::BI__builtin_vsx_stxvl ||
- BuiltinID == PPC::BI__builtin_vsx_stxvll ){
- Ops[1] = Builder.CreateBitCast(Ops[1], Int8PtrTy);
- }else {
- Ops[2] = Builder.CreateBitCast(Ops[2], Int8PtrTy);
- Ops[1] = Builder.CreateGEP(Ops[2], Ops[1]);
- Ops.pop_back();
- }
-
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported st intrinsic!");
- case PPC::BI__builtin_altivec_stvx:
- ID = Intrinsic::ppc_altivec_stvx;
- break;
- case PPC::BI__builtin_altivec_stvxl:
- ID = Intrinsic::ppc_altivec_stvxl;
- break;
- case PPC::BI__builtin_altivec_stvebx:
- ID = Intrinsic::ppc_altivec_stvebx;
- break;
- case PPC::BI__builtin_altivec_stvehx:
- ID = Intrinsic::ppc_altivec_stvehx;
- break;
- case PPC::BI__builtin_altivec_stvewx:
- ID = Intrinsic::ppc_altivec_stvewx;
- break;
- case PPC::BI__builtin_vsx_stxvd2x:
- ID = Intrinsic::ppc_vsx_stxvd2x;
- break;
- case PPC::BI__builtin_vsx_stxvw4x:
- ID = Intrinsic::ppc_vsx_stxvw4x;
- break;
- case PPC::BI__builtin_vsx_stxvd2x_be:
- ID = Intrinsic::ppc_vsx_stxvd2x_be;
- break;
- case PPC::BI__builtin_vsx_stxvw4x_be:
- ID = Intrinsic::ppc_vsx_stxvw4x_be;
- break;
- case PPC::BI__builtin_vsx_stxvl:
- ID = Intrinsic::ppc_vsx_stxvl;
- break;
- case PPC::BI__builtin_vsx_stxvll:
- ID = Intrinsic::ppc_vsx_stxvll;
- break;
- }
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, "");
- }
- // Square root
- case PPC::BI__builtin_vsx_xvsqrtsp:
- case PPC::BI__builtin_vsx_xvsqrtdp: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- ID = Intrinsic::sqrt;
- llvm::Function *F = CGM.getIntrinsic(ID, ResultType);
- return Builder.CreateCall(F, X);
- }
- // Count leading zeros
- case PPC::BI__builtin_altivec_vclzb:
- case PPC::BI__builtin_altivec_vclzh:
- case PPC::BI__builtin_altivec_vclzw:
- case PPC::BI__builtin_altivec_vclzd: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false);
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType);
- return Builder.CreateCall(F, {X, Undef});
- }
- case PPC::BI__builtin_altivec_vctzb:
- case PPC::BI__builtin_altivec_vctzh:
- case PPC::BI__builtin_altivec_vctzw:
- case PPC::BI__builtin_altivec_vctzd: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false);
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ResultType);
- return Builder.CreateCall(F, {X, Undef});
- }
- case PPC::BI__builtin_altivec_vpopcntb:
- case PPC::BI__builtin_altivec_vpopcnth:
- case PPC::BI__builtin_altivec_vpopcntw:
- case PPC::BI__builtin_altivec_vpopcntd: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ResultType);
- return Builder.CreateCall(F, X);
- }
- // Copy sign
- case PPC::BI__builtin_vsx_xvcpsgnsp:
- case PPC::BI__builtin_vsx_xvcpsgndp: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- ID = Intrinsic::copysign;
- llvm::Function *F = CGM.getIntrinsic(ID, ResultType);
- return Builder.CreateCall(F, {X, Y});
- }
- // Rounding/truncation
- case PPC::BI__builtin_vsx_xvrspip:
- case PPC::BI__builtin_vsx_xvrdpip:
- case PPC::BI__builtin_vsx_xvrdpim:
- case PPC::BI__builtin_vsx_xvrspim:
- case PPC::BI__builtin_vsx_xvrdpi:
- case PPC::BI__builtin_vsx_xvrspi:
- case PPC::BI__builtin_vsx_xvrdpic:
- case PPC::BI__builtin_vsx_xvrspic:
- case PPC::BI__builtin_vsx_xvrdpiz:
- case PPC::BI__builtin_vsx_xvrspiz: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- if (BuiltinID == PPC::BI__builtin_vsx_xvrdpim ||
- BuiltinID == PPC::BI__builtin_vsx_xvrspim)
- ID = Intrinsic::floor;
- else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpi ||
- BuiltinID == PPC::BI__builtin_vsx_xvrspi)
- ID = Intrinsic::round;
- else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpic ||
- BuiltinID == PPC::BI__builtin_vsx_xvrspic)
- ID = Intrinsic::nearbyint;
- else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpip ||
- BuiltinID == PPC::BI__builtin_vsx_xvrspip)
- ID = Intrinsic::ceil;
- else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpiz ||
- BuiltinID == PPC::BI__builtin_vsx_xvrspiz)
- ID = Intrinsic::trunc;
- llvm::Function *F = CGM.getIntrinsic(ID, ResultType);
- return Builder.CreateCall(F, X);
- }
-
- // Absolute value
- case PPC::BI__builtin_vsx_xvabsdp:
- case PPC::BI__builtin_vsx_xvabssp: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
- return Builder.CreateCall(F, X);
- }
-
- // FMA variations
- case PPC::BI__builtin_vsx_xvmaddadp:
- case PPC::BI__builtin_vsx_xvmaddasp:
- case PPC::BI__builtin_vsx_xvnmaddadp:
- case PPC::BI__builtin_vsx_xvnmaddasp:
- case PPC::BI__builtin_vsx_xvmsubadp:
- case PPC::BI__builtin_vsx_xvmsubasp:
- case PPC::BI__builtin_vsx_xvnmsubadp:
- case PPC::BI__builtin_vsx_xvnmsubasp: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- Value *Z = EmitScalarExpr(E->getArg(2));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- switch (BuiltinID) {
- case PPC::BI__builtin_vsx_xvmaddadp:
- case PPC::BI__builtin_vsx_xvmaddasp:
- return Builder.CreateCall(F, {X, Y, Z});
- case PPC::BI__builtin_vsx_xvnmaddadp:
- case PPC::BI__builtin_vsx_xvnmaddasp:
- return Builder.CreateFSub(Zero,
- Builder.CreateCall(F, {X, Y, Z}), "sub");
- case PPC::BI__builtin_vsx_xvmsubadp:
- case PPC::BI__builtin_vsx_xvmsubasp:
- return Builder.CreateCall(F,
- {X, Y, Builder.CreateFSub(Zero, Z, "sub")});
- case PPC::BI__builtin_vsx_xvnmsubadp:
- case PPC::BI__builtin_vsx_xvnmsubasp:
- Value *FsubRes =
- Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")});
- return Builder.CreateFSub(Zero, FsubRes, "sub");
- }
- llvm_unreachable("Unknown FMA operation");
- return nullptr; // Suppress no-return warning
- }
-
- case PPC::BI__builtin_vsx_insertword: {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_vsx_xxinsertw);
-
- // Third argument is a compile time constant int. It must be clamped to
- // to the range [0, 12].
- ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
- assert(ArgCI &&
- "Third arg to xxinsertw intrinsic must be constant integer");
- const int64_t MaxIndex = 12;
- int64_t Index = clamp(ArgCI->getSExtValue(), 0, MaxIndex);
-
- // The builtin semantics don't exactly match the xxinsertw instructions
- // semantics (which ppc_vsx_xxinsertw follows). The builtin extracts the
- // word from the first argument, and inserts it in the second argument. The
- // instruction extracts the word from its second input register and inserts
- // it into its first input register, so swap the first and second arguments.
- std::swap(Ops[0], Ops[1]);
-
- // Need to cast the second argument from a vector of unsigned int to a
- // vector of long long.
- Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int64Ty, 2));
-
- if (getTarget().isLittleEndian()) {
- // Create a shuffle mask of (1, 0)
- Constant *ShuffleElts[2] = { ConstantInt::get(Int32Ty, 1),
- ConstantInt::get(Int32Ty, 0)
- };
- Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
-
- // Reverse the double words in the vector we will extract from.
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2));
- Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], ShuffleMask);
-
- // Reverse the index.
- Index = MaxIndex - Index;
- }
-
- // Intrinsic expects the first arg to be a vector of int.
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 4));
- Ops[2] = ConstantInt::getSigned(Int32Ty, Index);
- return Builder.CreateCall(F, Ops);
- }
-
- case PPC::BI__builtin_vsx_extractuword: {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_vsx_xxextractuw);
-
- // Intrinsic expects the first argument to be a vector of doublewords.
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2));
-
- // The second argument is a compile time constant int that needs to
- // be clamped to the range [0, 12].
- ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[1]);
- assert(ArgCI &&
- "Second Arg to xxextractuw intrinsic must be a constant integer!");
- const int64_t MaxIndex = 12;
- int64_t Index = clamp(ArgCI->getSExtValue(), 0, MaxIndex);
-
- if (getTarget().isLittleEndian()) {
- // Reverse the index.
- Index = MaxIndex - Index;
- Ops[1] = ConstantInt::getSigned(Int32Ty, Index);
-
- // Emit the call, then reverse the double words of the results vector.
- Value *Call = Builder.CreateCall(F, Ops);
-
- // Create a shuffle mask of (1, 0)
- Constant *ShuffleElts[2] = { ConstantInt::get(Int32Ty, 1),
- ConstantInt::get(Int32Ty, 0)
- };
- Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
-
- Value *ShuffleCall = Builder.CreateShuffleVector(Call, Call, ShuffleMask);
- return ShuffleCall;
- } else {
- Ops[1] = ConstantInt::getSigned(Int32Ty, Index);
- return Builder.CreateCall(F, Ops);
- }
- }
-
- case PPC::BI__builtin_vsx_xxpermdi: {
- ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
- assert(ArgCI && "Third arg must be constant integer!");
-
- unsigned Index = ArgCI->getZExtValue();
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2));
- Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int64Ty, 2));
-
- // Account for endianness by treating this as just a shuffle. So we use the
- // same indices for both LE and BE in order to produce expected results in
- // both cases.
- unsigned ElemIdx0 = (Index & 2) >> 1;
- unsigned ElemIdx1 = 2 + (Index & 1);
-
- Constant *ShuffleElts[2] = {ConstantInt::get(Int32Ty, ElemIdx0),
- ConstantInt::get(Int32Ty, ElemIdx1)};
- Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
-
- Value *ShuffleCall =
- Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
- QualType BIRetType = E->getType();
- auto RetTy = ConvertType(BIRetType);
- return Builder.CreateBitCast(ShuffleCall, RetTy);
- }
-
- case PPC::BI__builtin_vsx_xxsldwi: {
- ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
- assert(ArgCI && "Third argument must be a compile time constant");
- unsigned Index = ArgCI->getZExtValue() & 0x3;
- Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 4));
- Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int32Ty, 4));
-
- // Create a shuffle mask
- unsigned ElemIdx0;
- unsigned ElemIdx1;
- unsigned ElemIdx2;
- unsigned ElemIdx3;
- if (getTarget().isLittleEndian()) {
- // Little endian element N comes from element 8+N-Index of the
- // concatenated wide vector (of course, using modulo arithmetic on
- // the total number of elements).
- ElemIdx0 = (8 - Index) % 8;
- ElemIdx1 = (9 - Index) % 8;
- ElemIdx2 = (10 - Index) % 8;
- ElemIdx3 = (11 - Index) % 8;
- } else {
- // Big endian ElemIdx<N> = Index + N
- ElemIdx0 = Index;
- ElemIdx1 = Index + 1;
- ElemIdx2 = Index + 2;
- ElemIdx3 = Index + 3;
- }
-
- Constant *ShuffleElts[4] = {ConstantInt::get(Int32Ty, ElemIdx0),
- ConstantInt::get(Int32Ty, ElemIdx1),
- ConstantInt::get(Int32Ty, ElemIdx2),
- ConstantInt::get(Int32Ty, ElemIdx3)};
-
- Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
- Value *ShuffleCall =
- Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
- QualType BIRetType = E->getType();
- auto RetTy = ConvertType(BIRetType);
- return Builder.CreateBitCast(ShuffleCall, RetTy);
- }
-
- case PPC::BI__builtin_pack_vector_int128: {
- bool isLittleEndian = getTarget().isLittleEndian();
- Value *UndefValue =
- llvm::UndefValue::get(llvm::VectorType::get(Ops[0]->getType(), 2));
- Value *Res = Builder.CreateInsertElement(
- UndefValue, Ops[0], (uint64_t)(isLittleEndian ? 1 : 0));
- Res = Builder.CreateInsertElement(Res, Ops[1],
- (uint64_t)(isLittleEndian ? 0 : 1));
- return Builder.CreateBitCast(Res, ConvertType(E->getType()));
- }
-
- case PPC::BI__builtin_unpack_vector_int128: {
- ConstantInt *Index = cast<ConstantInt>(Ops[1]);
- Value *Unpacked = Builder.CreateBitCast(
- Ops[0], llvm::VectorType::get(ConvertType(E->getType()), 2));
-
- if (getTarget().isLittleEndian())
- Index = ConstantInt::get(Index->getType(), 1 - Index->getZExtValue());
-
- return Builder.CreateExtractElement(Unpacked, Index);
- }
- }
-}
-
-Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- switch (BuiltinID) {
- case AMDGPU::BI__builtin_amdgcn_div_scale:
- case AMDGPU::BI__builtin_amdgcn_div_scalef: {
- // Translate from the intrinsics's struct return to the builtin's out
- // argument.
-
- Address FlagOutPtr = EmitPointerWithAlignment(E->getArg(3));
-
- llvm::Value *X = EmitScalarExpr(E->getArg(0));
- llvm::Value *Y = EmitScalarExpr(E->getArg(1));
- llvm::Value *Z = EmitScalarExpr(E->getArg(2));
-
- llvm::Value *Callee = CGM.getIntrinsic(Intrinsic::amdgcn_div_scale,
- X->getType());
-
- llvm::Value *Tmp = Builder.CreateCall(Callee, {X, Y, Z});
-
- llvm::Value *Result = Builder.CreateExtractValue(Tmp, 0);
- llvm::Value *Flag = Builder.CreateExtractValue(Tmp, 1);
-
- llvm::Type *RealFlagType
- = FlagOutPtr.getPointer()->getType()->getPointerElementType();
-
- llvm::Value *FlagExt = Builder.CreateZExt(Flag, RealFlagType);
- Builder.CreateStore(FlagExt, FlagOutPtr);
- return Result;
- }
- case AMDGPU::BI__builtin_amdgcn_div_fmas:
- case AMDGPU::BI__builtin_amdgcn_div_fmasf: {
- llvm::Value *Src0 = EmitScalarExpr(E->getArg(0));
- llvm::Value *Src1 = EmitScalarExpr(E->getArg(1));
- llvm::Value *Src2 = EmitScalarExpr(E->getArg(2));
- llvm::Value *Src3 = EmitScalarExpr(E->getArg(3));
-
- llvm::Value *F = CGM.getIntrinsic(Intrinsic::amdgcn_div_fmas,
- Src0->getType());
- llvm::Value *Src3ToBool = Builder.CreateIsNotNull(Src3);
- return Builder.CreateCall(F, {Src0, Src1, Src2, Src3ToBool});
- }
-
- case AMDGPU::BI__builtin_amdgcn_ds_swizzle:
- return emitBinaryBuiltin(*this, E, Intrinsic::amdgcn_ds_swizzle);
- case AMDGPU::BI__builtin_amdgcn_mov_dpp:
- case AMDGPU::BI__builtin_amdgcn_update_dpp: {
- llvm::SmallVector<llvm::Value *, 6> Args;
- for (unsigned I = 0; I != E->getNumArgs(); ++I)
- Args.push_back(EmitScalarExpr(E->getArg(I)));
- assert(Args.size() == 5 || Args.size() == 6);
- if (Args.size() == 5)
- Args.insert(Args.begin(), llvm::UndefValue::get(Args[0]->getType()));
- Value *F =
- CGM.getIntrinsic(Intrinsic::amdgcn_update_dpp, Args[0]->getType());
- return Builder.CreateCall(F, Args);
- }
- case AMDGPU::BI__builtin_amdgcn_div_fixup:
- case AMDGPU::BI__builtin_amdgcn_div_fixupf:
- case AMDGPU::BI__builtin_amdgcn_div_fixuph:
- return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_div_fixup);
- case AMDGPU::BI__builtin_amdgcn_trig_preop:
- case AMDGPU::BI__builtin_amdgcn_trig_preopf:
- return emitFPIntBuiltin(*this, E, Intrinsic::amdgcn_trig_preop);
- case AMDGPU::BI__builtin_amdgcn_rcp:
- case AMDGPU::BI__builtin_amdgcn_rcpf:
- case AMDGPU::BI__builtin_amdgcn_rcph:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_rcp);
- case AMDGPU::BI__builtin_amdgcn_rsq:
- case AMDGPU::BI__builtin_amdgcn_rsqf:
- case AMDGPU::BI__builtin_amdgcn_rsqh:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_rsq);
- case AMDGPU::BI__builtin_amdgcn_rsq_clamp:
- case AMDGPU::BI__builtin_amdgcn_rsq_clampf:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_rsq_clamp);
- case AMDGPU::BI__builtin_amdgcn_sinf:
- case AMDGPU::BI__builtin_amdgcn_sinh:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_sin);
- case AMDGPU::BI__builtin_amdgcn_cosf:
- case AMDGPU::BI__builtin_amdgcn_cosh:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_cos);
- case AMDGPU::BI__builtin_amdgcn_log_clampf:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_log_clamp);
- case AMDGPU::BI__builtin_amdgcn_ldexp:
- case AMDGPU::BI__builtin_amdgcn_ldexpf:
- case AMDGPU::BI__builtin_amdgcn_ldexph:
- return emitFPIntBuiltin(*this, E, Intrinsic::amdgcn_ldexp);
- case AMDGPU::BI__builtin_amdgcn_frexp_mant:
- case AMDGPU::BI__builtin_amdgcn_frexp_mantf:
- case AMDGPU::BI__builtin_amdgcn_frexp_manth:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_frexp_mant);
- case AMDGPU::BI__builtin_amdgcn_frexp_exp:
- case AMDGPU::BI__builtin_amdgcn_frexp_expf: {
- Value *Src0 = EmitScalarExpr(E->getArg(0));
- Value *F = CGM.getIntrinsic(Intrinsic::amdgcn_frexp_exp,
- { Builder.getInt32Ty(), Src0->getType() });
- return Builder.CreateCall(F, Src0);
- }
- case AMDGPU::BI__builtin_amdgcn_frexp_exph: {
- Value *Src0 = EmitScalarExpr(E->getArg(0));
- Value *F = CGM.getIntrinsic(Intrinsic::amdgcn_frexp_exp,
- { Builder.getInt16Ty(), Src0->getType() });
- return Builder.CreateCall(F, Src0);
- }
- case AMDGPU::BI__builtin_amdgcn_fract:
- case AMDGPU::BI__builtin_amdgcn_fractf:
- case AMDGPU::BI__builtin_amdgcn_fracth:
- return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_fract);
- case AMDGPU::BI__builtin_amdgcn_lerp:
- return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_lerp);
- case AMDGPU::BI__builtin_amdgcn_uicmp:
- case AMDGPU::BI__builtin_amdgcn_uicmpl:
- case AMDGPU::BI__builtin_amdgcn_sicmp:
- case AMDGPU::BI__builtin_amdgcn_sicmpl:
- return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_icmp);
- case AMDGPU::BI__builtin_amdgcn_fcmp:
- case AMDGPU::BI__builtin_amdgcn_fcmpf:
- return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_fcmp);
- case AMDGPU::BI__builtin_amdgcn_class:
- case AMDGPU::BI__builtin_amdgcn_classf:
- case AMDGPU::BI__builtin_amdgcn_classh:
- return emitFPIntBuiltin(*this, E, Intrinsic::amdgcn_class);
- case AMDGPU::BI__builtin_amdgcn_fmed3f:
- case AMDGPU::BI__builtin_amdgcn_fmed3h:
- return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_fmed3);
- case AMDGPU::BI__builtin_amdgcn_read_exec: {
- CallInst *CI = cast<CallInst>(
- EmitSpecialRegisterBuiltin(*this, E, Int64Ty, Int64Ty, true, "exec"));
- CI->setConvergent();
- return CI;
- }
- case AMDGPU::BI__builtin_amdgcn_read_exec_lo:
- case AMDGPU::BI__builtin_amdgcn_read_exec_hi: {
- StringRef RegName = BuiltinID == AMDGPU::BI__builtin_amdgcn_read_exec_lo ?
- "exec_lo" : "exec_hi";
- CallInst *CI = cast<CallInst>(
- EmitSpecialRegisterBuiltin(*this, E, Int32Ty, Int32Ty, true, RegName));
- CI->setConvergent();
- return CI;
- }
- // amdgcn workitem
- case AMDGPU::BI__builtin_amdgcn_workitem_id_x:
- return emitRangedBuiltin(*this, Intrinsic::amdgcn_workitem_id_x, 0, 1024);
- case AMDGPU::BI__builtin_amdgcn_workitem_id_y:
- return emitRangedBuiltin(*this, Intrinsic::amdgcn_workitem_id_y, 0, 1024);
- case AMDGPU::BI__builtin_amdgcn_workitem_id_z:
- return emitRangedBuiltin(*this, Intrinsic::amdgcn_workitem_id_z, 0, 1024);
-
- // r600 intrinsics
- case AMDGPU::BI__builtin_r600_recipsqrt_ieee:
- case AMDGPU::BI__builtin_r600_recipsqrt_ieeef:
- return emitUnaryBuiltin(*this, E, Intrinsic::r600_recipsqrt_ieee);
- case AMDGPU::BI__builtin_r600_read_tidig_x:
- return emitRangedBuiltin(*this, Intrinsic::r600_read_tidig_x, 0, 1024);
- case AMDGPU::BI__builtin_r600_read_tidig_y:
- return emitRangedBuiltin(*this, Intrinsic::r600_read_tidig_y, 0, 1024);
- case AMDGPU::BI__builtin_r600_read_tidig_z:
- return emitRangedBuiltin(*this, Intrinsic::r600_read_tidig_z, 0, 1024);
- default:
- return nullptr;
- }
-}
-
-/// Handle a SystemZ function in which the final argument is a pointer
-/// to an int that receives the post-instruction CC value. At the LLVM level
-/// this is represented as a function that returns a {result, cc} pair.
-static Value *EmitSystemZIntrinsicWithCC(CodeGenFunction &CGF,
- unsigned IntrinsicID,
- const CallExpr *E) {
- unsigned NumArgs = E->getNumArgs() - 1;
- SmallVector<Value *, 8> Args(NumArgs);
- for (unsigned I = 0; I < NumArgs; ++I)
- Args[I] = CGF.EmitScalarExpr(E->getArg(I));
- Address CCPtr = CGF.EmitPointerWithAlignment(E->getArg(NumArgs));
- Value *F = CGF.CGM.getIntrinsic(IntrinsicID);
- Value *Call = CGF.Builder.CreateCall(F, Args);
- Value *CC = CGF.Builder.CreateExtractValue(Call, 1);
- CGF.Builder.CreateStore(CC, CCPtr);
- return CGF.Builder.CreateExtractValue(Call, 0);
-}
-
-Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- switch (BuiltinID) {
- case SystemZ::BI__builtin_tbegin: {
- Value *TDB = EmitScalarExpr(E->getArg(0));
- Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c);
- Value *F = CGM.getIntrinsic(Intrinsic::s390_tbegin);
- return Builder.CreateCall(F, {TDB, Control});
- }
- case SystemZ::BI__builtin_tbegin_nofloat: {
- Value *TDB = EmitScalarExpr(E->getArg(0));
- Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c);
- Value *F = CGM.getIntrinsic(Intrinsic::s390_tbegin_nofloat);
- return Builder.CreateCall(F, {TDB, Control});
- }
- case SystemZ::BI__builtin_tbeginc: {
- Value *TDB = llvm::ConstantPointerNull::get(Int8PtrTy);
- Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff08);
- Value *F = CGM.getIntrinsic(Intrinsic::s390_tbeginc);
- return Builder.CreateCall(F, {TDB, Control});
- }
- case SystemZ::BI__builtin_tabort: {
- Value *Data = EmitScalarExpr(E->getArg(0));
- Value *F = CGM.getIntrinsic(Intrinsic::s390_tabort);
- return Builder.CreateCall(F, Builder.CreateSExt(Data, Int64Ty, "tabort"));
- }
- case SystemZ::BI__builtin_non_tx_store: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *Data = EmitScalarExpr(E->getArg(1));
- Value *F = CGM.getIntrinsic(Intrinsic::s390_ntstg);
- return Builder.CreateCall(F, {Data, Address});
- }
-
- // Vector builtins. Note that most vector builtins are mapped automatically
- // to target-specific LLVM intrinsics. The ones handled specially here can
- // be represented via standard LLVM IR, which is preferable to enable common
- // LLVM optimizations.
-
- case SystemZ::BI__builtin_s390_vpopctb:
- case SystemZ::BI__builtin_s390_vpopcth:
- case SystemZ::BI__builtin_s390_vpopctf:
- case SystemZ::BI__builtin_s390_vpopctg: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ResultType);
- return Builder.CreateCall(F, X);
- }
-
- case SystemZ::BI__builtin_s390_vclzb:
- case SystemZ::BI__builtin_s390_vclzh:
- case SystemZ::BI__builtin_s390_vclzf:
- case SystemZ::BI__builtin_s390_vclzg: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false);
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType);
- return Builder.CreateCall(F, {X, Undef});
- }
-
- case SystemZ::BI__builtin_s390_vctzb:
- case SystemZ::BI__builtin_s390_vctzh:
- case SystemZ::BI__builtin_s390_vctzf:
- case SystemZ::BI__builtin_s390_vctzg: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false);
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ResultType);
- return Builder.CreateCall(F, {X, Undef});
- }
-
- case SystemZ::BI__builtin_s390_vfsqsb:
- case SystemZ::BI__builtin_s390_vfsqdb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Function *F = CGM.getIntrinsic(Intrinsic::sqrt, ResultType);
- return Builder.CreateCall(F, X);
- }
- case SystemZ::BI__builtin_s390_vfmasb:
- case SystemZ::BI__builtin_s390_vfmadb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- Value *Z = EmitScalarExpr(E->getArg(2));
- Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- return Builder.CreateCall(F, {X, Y, Z});
- }
- case SystemZ::BI__builtin_s390_vfmssb:
- case SystemZ::BI__builtin_s390_vfmsdb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- Value *Z = EmitScalarExpr(E->getArg(2));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
- Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- return Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")});
- }
- case SystemZ::BI__builtin_s390_vfnmasb:
- case SystemZ::BI__builtin_s390_vfnmadb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- Value *Z = EmitScalarExpr(E->getArg(2));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
- Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, Z}), "sub");
- }
- case SystemZ::BI__builtin_s390_vfnmssb:
- case SystemZ::BI__builtin_s390_vfnmsdb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- Value *Z = EmitScalarExpr(E->getArg(2));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
- Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
- Value *NegZ = Builder.CreateFSub(Zero, Z, "sub");
- return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, NegZ}));
- }
- case SystemZ::BI__builtin_s390_vflpsb:
- case SystemZ::BI__builtin_s390_vflpdb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
- return Builder.CreateCall(F, X);
- }
- case SystemZ::BI__builtin_s390_vflnsb:
- case SystemZ::BI__builtin_s390_vflndb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
- Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
- return Builder.CreateFSub(Zero, Builder.CreateCall(F, X), "sub");
- }
- case SystemZ::BI__builtin_s390_vfisb:
- case SystemZ::BI__builtin_s390_vfidb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- // Constant-fold the M4 and M5 mask arguments.
- llvm::APSInt M4, M5;
- bool IsConstM4 = E->getArg(1)->isIntegerConstantExpr(M4, getContext());
- bool IsConstM5 = E->getArg(2)->isIntegerConstantExpr(M5, getContext());
- assert(IsConstM4 && IsConstM5 && "Constant arg isn't actually constant?");
- (void)IsConstM4; (void)IsConstM5;
- // Check whether this instance can be represented via a LLVM standard
- // intrinsic. We only support some combinations of M4 and M5.
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
- switch (M4.getZExtValue()) {
- default: break;
- case 0: // IEEE-inexact exception allowed
- switch (M5.getZExtValue()) {
- default: break;
- case 0: ID = Intrinsic::rint; break;
- }
- break;
- case 4: // IEEE-inexact exception suppressed
- switch (M5.getZExtValue()) {
- default: break;
- case 0: ID = Intrinsic::nearbyint; break;
- case 1: ID = Intrinsic::round; break;
- case 5: ID = Intrinsic::trunc; break;
- case 6: ID = Intrinsic::ceil; break;
- case 7: ID = Intrinsic::floor; break;
- }
- break;
- }
- if (ID != Intrinsic::not_intrinsic) {
- Function *F = CGM.getIntrinsic(ID, ResultType);
- return Builder.CreateCall(F, X);
- }
- switch (BuiltinID) {
- case SystemZ::BI__builtin_s390_vfisb: ID = Intrinsic::s390_vfisb; break;
- case SystemZ::BI__builtin_s390_vfidb: ID = Intrinsic::s390_vfidb; break;
- default: llvm_unreachable("Unknown BuiltinID");
- }
- Function *F = CGM.getIntrinsic(ID);
- Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
- Value *M5Value = llvm::ConstantInt::get(getLLVMContext(), M5);
- return Builder.CreateCall(F, {X, M4Value, M5Value});
- }
- case SystemZ::BI__builtin_s390_vfmaxsb:
- case SystemZ::BI__builtin_s390_vfmaxdb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- // Constant-fold the M4 mask argument.
- llvm::APSInt M4;
- bool IsConstM4 = E->getArg(2)->isIntegerConstantExpr(M4, getContext());
- assert(IsConstM4 && "Constant arg isn't actually constant?");
- (void)IsConstM4;
- // Check whether this instance can be represented via a LLVM standard
- // intrinsic. We only support some values of M4.
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
- switch (M4.getZExtValue()) {
- default: break;
- case 4: ID = Intrinsic::maxnum; break;
- }
- if (ID != Intrinsic::not_intrinsic) {
- Function *F = CGM.getIntrinsic(ID, ResultType);
- return Builder.CreateCall(F, {X, Y});
- }
- switch (BuiltinID) {
- case SystemZ::BI__builtin_s390_vfmaxsb: ID = Intrinsic::s390_vfmaxsb; break;
- case SystemZ::BI__builtin_s390_vfmaxdb: ID = Intrinsic::s390_vfmaxdb; break;
- default: llvm_unreachable("Unknown BuiltinID");
- }
- Function *F = CGM.getIntrinsic(ID);
- Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
- return Builder.CreateCall(F, {X, Y, M4Value});
- }
- case SystemZ::BI__builtin_s390_vfminsb:
- case SystemZ::BI__builtin_s390_vfmindb: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *X = EmitScalarExpr(E->getArg(0));
- Value *Y = EmitScalarExpr(E->getArg(1));
- // Constant-fold the M4 mask argument.
- llvm::APSInt M4;
- bool IsConstM4 = E->getArg(2)->isIntegerConstantExpr(M4, getContext());
- assert(IsConstM4 && "Constant arg isn't actually constant?");
- (void)IsConstM4;
- // Check whether this instance can be represented via a LLVM standard
- // intrinsic. We only support some values of M4.
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
- switch (M4.getZExtValue()) {
- default: break;
- case 4: ID = Intrinsic::minnum; break;
- }
- if (ID != Intrinsic::not_intrinsic) {
- Function *F = CGM.getIntrinsic(ID, ResultType);
- return Builder.CreateCall(F, {X, Y});
- }
- switch (BuiltinID) {
- case SystemZ::BI__builtin_s390_vfminsb: ID = Intrinsic::s390_vfminsb; break;
- case SystemZ::BI__builtin_s390_vfmindb: ID = Intrinsic::s390_vfmindb; break;
- default: llvm_unreachable("Unknown BuiltinID");
- }
- Function *F = CGM.getIntrinsic(ID);
- Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
- return Builder.CreateCall(F, {X, Y, M4Value});
- }
-
- // Vector intrinsics that output the post-instruction CC value.
-
-#define INTRINSIC_WITH_CC(NAME) \
- case SystemZ::BI__builtin_##NAME: \
- return EmitSystemZIntrinsicWithCC(*this, Intrinsic::NAME, E)
-
- INTRINSIC_WITH_CC(s390_vpkshs);
- INTRINSIC_WITH_CC(s390_vpksfs);
- INTRINSIC_WITH_CC(s390_vpksgs);
-
- INTRINSIC_WITH_CC(s390_vpklshs);
- INTRINSIC_WITH_CC(s390_vpklsfs);
- INTRINSIC_WITH_CC(s390_vpklsgs);
-
- INTRINSIC_WITH_CC(s390_vceqbs);
- INTRINSIC_WITH_CC(s390_vceqhs);
- INTRINSIC_WITH_CC(s390_vceqfs);
- INTRINSIC_WITH_CC(s390_vceqgs);
-
- INTRINSIC_WITH_CC(s390_vchbs);
- INTRINSIC_WITH_CC(s390_vchhs);
- INTRINSIC_WITH_CC(s390_vchfs);
- INTRINSIC_WITH_CC(s390_vchgs);
-
- INTRINSIC_WITH_CC(s390_vchlbs);
- INTRINSIC_WITH_CC(s390_vchlhs);
- INTRINSIC_WITH_CC(s390_vchlfs);
- INTRINSIC_WITH_CC(s390_vchlgs);
-
- INTRINSIC_WITH_CC(s390_vfaebs);
- INTRINSIC_WITH_CC(s390_vfaehs);
- INTRINSIC_WITH_CC(s390_vfaefs);
-
- INTRINSIC_WITH_CC(s390_vfaezbs);
- INTRINSIC_WITH_CC(s390_vfaezhs);
- INTRINSIC_WITH_CC(s390_vfaezfs);
-
- INTRINSIC_WITH_CC(s390_vfeebs);
- INTRINSIC_WITH_CC(s390_vfeehs);
- INTRINSIC_WITH_CC(s390_vfeefs);
-
- INTRINSIC_WITH_CC(s390_vfeezbs);
- INTRINSIC_WITH_CC(s390_vfeezhs);
- INTRINSIC_WITH_CC(s390_vfeezfs);
-
- INTRINSIC_WITH_CC(s390_vfenebs);
- INTRINSIC_WITH_CC(s390_vfenehs);
- INTRINSIC_WITH_CC(s390_vfenefs);
-
- INTRINSIC_WITH_CC(s390_vfenezbs);
- INTRINSIC_WITH_CC(s390_vfenezhs);
- INTRINSIC_WITH_CC(s390_vfenezfs);
-
- INTRINSIC_WITH_CC(s390_vistrbs);
- INTRINSIC_WITH_CC(s390_vistrhs);
- INTRINSIC_WITH_CC(s390_vistrfs);
-
- INTRINSIC_WITH_CC(s390_vstrcbs);
- INTRINSIC_WITH_CC(s390_vstrchs);
- INTRINSIC_WITH_CC(s390_vstrcfs);
-
- INTRINSIC_WITH_CC(s390_vstrczbs);
- INTRINSIC_WITH_CC(s390_vstrczhs);
- INTRINSIC_WITH_CC(s390_vstrczfs);
-
- INTRINSIC_WITH_CC(s390_vfcesbs);
- INTRINSIC_WITH_CC(s390_vfcedbs);
- INTRINSIC_WITH_CC(s390_vfchsbs);
- INTRINSIC_WITH_CC(s390_vfchdbs);
- INTRINSIC_WITH_CC(s390_vfchesbs);
- INTRINSIC_WITH_CC(s390_vfchedbs);
-
- INTRINSIC_WITH_CC(s390_vftcisb);
- INTRINSIC_WITH_CC(s390_vftcidb);
-
-#undef INTRINSIC_WITH_CC
-
- default:
- return nullptr;
- }
-}
-
-Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- auto MakeLdg = [&](unsigned IntrinsicID) {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- clang::CharUnits Align =
- getNaturalPointeeTypeAlignment(E->getArg(0)->getType());
- return Builder.CreateCall(
- CGM.getIntrinsic(IntrinsicID, {Ptr->getType()->getPointerElementType(),
- Ptr->getType()}),
- {Ptr, ConstantInt::get(Builder.getInt32Ty(), Align.getQuantity())});
- };
- auto MakeScopedAtomic = [&](unsigned IntrinsicID) {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- return Builder.CreateCall(
- CGM.getIntrinsic(IntrinsicID, {Ptr->getType()->getPointerElementType(),
- Ptr->getType()}),
- {Ptr, EmitScalarExpr(E->getArg(1))});
- };
- switch (BuiltinID) {
- case NVPTX::BI__nvvm_atom_add_gen_i:
- case NVPTX::BI__nvvm_atom_add_gen_l:
- case NVPTX::BI__nvvm_atom_add_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::Add, E);
-
- case NVPTX::BI__nvvm_atom_sub_gen_i:
- case NVPTX::BI__nvvm_atom_sub_gen_l:
- case NVPTX::BI__nvvm_atom_sub_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::Sub, E);
-
- case NVPTX::BI__nvvm_atom_and_gen_i:
- case NVPTX::BI__nvvm_atom_and_gen_l:
- case NVPTX::BI__nvvm_atom_and_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::And, E);
-
- case NVPTX::BI__nvvm_atom_or_gen_i:
- case NVPTX::BI__nvvm_atom_or_gen_l:
- case NVPTX::BI__nvvm_atom_or_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::Or, E);
-
- case NVPTX::BI__nvvm_atom_xor_gen_i:
- case NVPTX::BI__nvvm_atom_xor_gen_l:
- case NVPTX::BI__nvvm_atom_xor_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::Xor, E);
-
- case NVPTX::BI__nvvm_atom_xchg_gen_i:
- case NVPTX::BI__nvvm_atom_xchg_gen_l:
- case NVPTX::BI__nvvm_atom_xchg_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::Xchg, E);
-
- case NVPTX::BI__nvvm_atom_max_gen_i:
- case NVPTX::BI__nvvm_atom_max_gen_l:
- case NVPTX::BI__nvvm_atom_max_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::Max, E);
-
- case NVPTX::BI__nvvm_atom_max_gen_ui:
- case NVPTX::BI__nvvm_atom_max_gen_ul:
- case NVPTX::BI__nvvm_atom_max_gen_ull:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::UMax, E);
-
- case NVPTX::BI__nvvm_atom_min_gen_i:
- case NVPTX::BI__nvvm_atom_min_gen_l:
- case NVPTX::BI__nvvm_atom_min_gen_ll:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::Min, E);
-
- case NVPTX::BI__nvvm_atom_min_gen_ui:
- case NVPTX::BI__nvvm_atom_min_gen_ul:
- case NVPTX::BI__nvvm_atom_min_gen_ull:
- return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::UMin, E);
-
- case NVPTX::BI__nvvm_atom_cas_gen_i:
- case NVPTX::BI__nvvm_atom_cas_gen_l:
- case NVPTX::BI__nvvm_atom_cas_gen_ll:
- // __nvvm_atom_cas_gen_* should return the old value rather than the
- // success flag.
- return MakeAtomicCmpXchgValue(*this, E, /*ReturnBool=*/false);
-
- case NVPTX::BI__nvvm_atom_add_gen_f: {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- Value *Val = EmitScalarExpr(E->getArg(1));
- // atomicrmw only deals with integer arguments so we need to use
- // LLVM's nvvm_atomic_load_add_f32 intrinsic for that.
- Value *FnALAF32 =
- CGM.getIntrinsic(Intrinsic::nvvm_atomic_load_add_f32, Ptr->getType());
- return Builder.CreateCall(FnALAF32, {Ptr, Val});
- }
-
- case NVPTX::BI__nvvm_atom_add_gen_d: {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- Value *Val = EmitScalarExpr(E->getArg(1));
- // atomicrmw only deals with integer arguments, so we need to use
- // LLVM's nvvm_atomic_load_add_f64 intrinsic.
- Value *FnALAF64 =
- CGM.getIntrinsic(Intrinsic::nvvm_atomic_load_add_f64, Ptr->getType());
- return Builder.CreateCall(FnALAF64, {Ptr, Val});
- }
-
- case NVPTX::BI__nvvm_atom_inc_gen_ui: {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- Value *Val = EmitScalarExpr(E->getArg(1));
- Value *FnALI32 =
- CGM.getIntrinsic(Intrinsic::nvvm_atomic_load_inc_32, Ptr->getType());
- return Builder.CreateCall(FnALI32, {Ptr, Val});
- }
-
- case NVPTX::BI__nvvm_atom_dec_gen_ui: {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- Value *Val = EmitScalarExpr(E->getArg(1));
- Value *FnALD32 =
- CGM.getIntrinsic(Intrinsic::nvvm_atomic_load_dec_32, Ptr->getType());
- return Builder.CreateCall(FnALD32, {Ptr, Val});
- }
-
- case NVPTX::BI__nvvm_ldg_c:
- case NVPTX::BI__nvvm_ldg_c2:
- case NVPTX::BI__nvvm_ldg_c4:
- case NVPTX::BI__nvvm_ldg_s:
- case NVPTX::BI__nvvm_ldg_s2:
- case NVPTX::BI__nvvm_ldg_s4:
- case NVPTX::BI__nvvm_ldg_i:
- case NVPTX::BI__nvvm_ldg_i2:
- case NVPTX::BI__nvvm_ldg_i4:
- case NVPTX::BI__nvvm_ldg_l:
- case NVPTX::BI__nvvm_ldg_ll:
- case NVPTX::BI__nvvm_ldg_ll2:
- case NVPTX::BI__nvvm_ldg_uc:
- case NVPTX::BI__nvvm_ldg_uc2:
- case NVPTX::BI__nvvm_ldg_uc4:
- case NVPTX::BI__nvvm_ldg_us:
- case NVPTX::BI__nvvm_ldg_us2:
- case NVPTX::BI__nvvm_ldg_us4:
- case NVPTX::BI__nvvm_ldg_ui:
- case NVPTX::BI__nvvm_ldg_ui2:
- case NVPTX::BI__nvvm_ldg_ui4:
- case NVPTX::BI__nvvm_ldg_ul:
- case NVPTX::BI__nvvm_ldg_ull:
- case NVPTX::BI__nvvm_ldg_ull2:
- // PTX Interoperability section 2.2: "For a vector with an even number of
- // elements, its alignment is set to number of elements times the alignment
- // of its member: n*alignof(t)."
- return MakeLdg(Intrinsic::nvvm_ldg_global_i);
- case NVPTX::BI__nvvm_ldg_f:
- case NVPTX::BI__nvvm_ldg_f2:
- case NVPTX::BI__nvvm_ldg_f4:
- case NVPTX::BI__nvvm_ldg_d:
- case NVPTX::BI__nvvm_ldg_d2:
- return MakeLdg(Intrinsic::nvvm_ldg_global_f);
-
- case NVPTX::BI__nvvm_atom_cta_add_gen_i:
- case NVPTX::BI__nvvm_atom_cta_add_gen_l:
- case NVPTX::BI__nvvm_atom_cta_add_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_add_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_add_gen_i:
- case NVPTX::BI__nvvm_atom_sys_add_gen_l:
- case NVPTX::BI__nvvm_atom_sys_add_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_add_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_add_gen_f:
- case NVPTX::BI__nvvm_atom_cta_add_gen_d:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_add_gen_f_cta);
- case NVPTX::BI__nvvm_atom_sys_add_gen_f:
- case NVPTX::BI__nvvm_atom_sys_add_gen_d:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_add_gen_f_sys);
- case NVPTX::BI__nvvm_atom_cta_xchg_gen_i:
- case NVPTX::BI__nvvm_atom_cta_xchg_gen_l:
- case NVPTX::BI__nvvm_atom_cta_xchg_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_exch_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_xchg_gen_i:
- case NVPTX::BI__nvvm_atom_sys_xchg_gen_l:
- case NVPTX::BI__nvvm_atom_sys_xchg_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_exch_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_max_gen_i:
- case NVPTX::BI__nvvm_atom_cta_max_gen_ui:
- case NVPTX::BI__nvvm_atom_cta_max_gen_l:
- case NVPTX::BI__nvvm_atom_cta_max_gen_ul:
- case NVPTX::BI__nvvm_atom_cta_max_gen_ll:
- case NVPTX::BI__nvvm_atom_cta_max_gen_ull:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_max_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_max_gen_i:
- case NVPTX::BI__nvvm_atom_sys_max_gen_ui:
- case NVPTX::BI__nvvm_atom_sys_max_gen_l:
- case NVPTX::BI__nvvm_atom_sys_max_gen_ul:
- case NVPTX::BI__nvvm_atom_sys_max_gen_ll:
- case NVPTX::BI__nvvm_atom_sys_max_gen_ull:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_max_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_min_gen_i:
- case NVPTX::BI__nvvm_atom_cta_min_gen_ui:
- case NVPTX::BI__nvvm_atom_cta_min_gen_l:
- case NVPTX::BI__nvvm_atom_cta_min_gen_ul:
- case NVPTX::BI__nvvm_atom_cta_min_gen_ll:
- case NVPTX::BI__nvvm_atom_cta_min_gen_ull:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_min_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_min_gen_i:
- case NVPTX::BI__nvvm_atom_sys_min_gen_ui:
- case NVPTX::BI__nvvm_atom_sys_min_gen_l:
- case NVPTX::BI__nvvm_atom_sys_min_gen_ul:
- case NVPTX::BI__nvvm_atom_sys_min_gen_ll:
- case NVPTX::BI__nvvm_atom_sys_min_gen_ull:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_min_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_inc_gen_ui:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_inc_gen_i_cta);
- case NVPTX::BI__nvvm_atom_cta_dec_gen_ui:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_dec_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_inc_gen_ui:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_inc_gen_i_sys);
- case NVPTX::BI__nvvm_atom_sys_dec_gen_ui:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_dec_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_and_gen_i:
- case NVPTX::BI__nvvm_atom_cta_and_gen_l:
- case NVPTX::BI__nvvm_atom_cta_and_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_and_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_and_gen_i:
- case NVPTX::BI__nvvm_atom_sys_and_gen_l:
- case NVPTX::BI__nvvm_atom_sys_and_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_and_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_or_gen_i:
- case NVPTX::BI__nvvm_atom_cta_or_gen_l:
- case NVPTX::BI__nvvm_atom_cta_or_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_or_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_or_gen_i:
- case NVPTX::BI__nvvm_atom_sys_or_gen_l:
- case NVPTX::BI__nvvm_atom_sys_or_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_or_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_xor_gen_i:
- case NVPTX::BI__nvvm_atom_cta_xor_gen_l:
- case NVPTX::BI__nvvm_atom_cta_xor_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_xor_gen_i_cta);
- case NVPTX::BI__nvvm_atom_sys_xor_gen_i:
- case NVPTX::BI__nvvm_atom_sys_xor_gen_l:
- case NVPTX::BI__nvvm_atom_sys_xor_gen_ll:
- return MakeScopedAtomic(Intrinsic::nvvm_atomic_xor_gen_i_sys);
- case NVPTX::BI__nvvm_atom_cta_cas_gen_i:
- case NVPTX::BI__nvvm_atom_cta_cas_gen_l:
- case NVPTX::BI__nvvm_atom_cta_cas_gen_ll: {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- return Builder.CreateCall(
- CGM.getIntrinsic(
- Intrinsic::nvvm_atomic_cas_gen_i_cta,
- {Ptr->getType()->getPointerElementType(), Ptr->getType()}),
- {Ptr, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2))});
- }
- case NVPTX::BI__nvvm_atom_sys_cas_gen_i:
- case NVPTX::BI__nvvm_atom_sys_cas_gen_l:
- case NVPTX::BI__nvvm_atom_sys_cas_gen_ll: {
- Value *Ptr = EmitScalarExpr(E->getArg(0));
- return Builder.CreateCall(
- CGM.getIntrinsic(
- Intrinsic::nvvm_atomic_cas_gen_i_sys,
- {Ptr->getType()->getPointerElementType(), Ptr->getType()}),
- {Ptr, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2))});
- }
- case NVPTX::BI__nvvm_match_all_sync_i32p:
- case NVPTX::BI__nvvm_match_all_sync_i64p: {
- Value *Mask = EmitScalarExpr(E->getArg(0));
- Value *Val = EmitScalarExpr(E->getArg(1));
- Address PredOutPtr = EmitPointerWithAlignment(E->getArg(2));
- Value *ResultPair = Builder.CreateCall(
- CGM.getIntrinsic(BuiltinID == NVPTX::BI__nvvm_match_all_sync_i32p
- ? Intrinsic::nvvm_match_all_sync_i32p
- : Intrinsic::nvvm_match_all_sync_i64p),
- {Mask, Val});
- Value *Pred = Builder.CreateZExt(Builder.CreateExtractValue(ResultPair, 1),
- PredOutPtr.getElementType());
- Builder.CreateStore(Pred, PredOutPtr);
- return Builder.CreateExtractValue(ResultPair, 0);
- }
- case NVPTX::BI__hmma_m16n16k16_ld_a:
- case NVPTX::BI__hmma_m16n16k16_ld_b:
- case NVPTX::BI__hmma_m16n16k16_ld_c_f16:
- case NVPTX::BI__hmma_m16n16k16_ld_c_f32:
- case NVPTX::BI__hmma_m32n8k16_ld_a:
- case NVPTX::BI__hmma_m32n8k16_ld_b:
- case NVPTX::BI__hmma_m32n8k16_ld_c_f16:
- case NVPTX::BI__hmma_m32n8k16_ld_c_f32:
- case NVPTX::BI__hmma_m8n32k16_ld_a:
- case NVPTX::BI__hmma_m8n32k16_ld_b:
- case NVPTX::BI__hmma_m8n32k16_ld_c_f16:
- case NVPTX::BI__hmma_m8n32k16_ld_c_f32: {
- Address Dst = EmitPointerWithAlignment(E->getArg(0));
- Value *Src = EmitScalarExpr(E->getArg(1));
- Value *Ldm = EmitScalarExpr(E->getArg(2));
- llvm::APSInt isColMajorArg;
- if (!E->getArg(3)->isIntegerConstantExpr(isColMajorArg, getContext()))
- return nullptr;
- bool isColMajor = isColMajorArg.getSExtValue();
- unsigned IID;
- unsigned NumResults;
- switch (BuiltinID) {
- case NVPTX::BI__hmma_m16n16k16_ld_a:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_col_stride
- : Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m16n16k16_ld_b:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_col_stride
- : Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m16n16k16_ld_c_f16:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_col_stride
- : Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_row_stride;
- NumResults = 4;
- break;
- case NVPTX::BI__hmma_m16n16k16_ld_c_f32:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_col_stride
- : Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m32n8k16_ld_a:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_col_stride
- : Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m32n8k16_ld_b:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_col_stride
- : Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m32n8k16_ld_c_f16:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_col_stride
- : Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_row_stride;
- NumResults = 4;
- break;
- case NVPTX::BI__hmma_m32n8k16_ld_c_f32:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_col_stride
- : Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m8n32k16_ld_a:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_col_stride
- : Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m8n32k16_ld_b:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_col_stride
- : Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_row_stride;
- NumResults = 8;
- break;
- case NVPTX::BI__hmma_m8n32k16_ld_c_f16:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_col_stride
- : Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_row_stride;
- NumResults = 4;
- break;
- case NVPTX::BI__hmma_m8n32k16_ld_c_f32:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_col_stride
- : Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_row_stride;
- NumResults = 8;
- break;
- default:
- llvm_unreachable("Unexpected builtin ID.");
- }
- Value *Result =
- Builder.CreateCall(CGM.getIntrinsic(IID, Src->getType()), {Src, Ldm});
-
- // Save returned values.
- for (unsigned i = 0; i < NumResults; ++i) {
- Builder.CreateAlignedStore(
- Builder.CreateBitCast(Builder.CreateExtractValue(Result, i),
- Dst.getElementType()),
- Builder.CreateGEP(Dst.getPointer(), llvm::ConstantInt::get(IntTy, i)),
- CharUnits::fromQuantity(4));
- }
- return Result;
- }
-
- case NVPTX::BI__hmma_m16n16k16_st_c_f16:
- case NVPTX::BI__hmma_m16n16k16_st_c_f32:
- case NVPTX::BI__hmma_m32n8k16_st_c_f16:
- case NVPTX::BI__hmma_m32n8k16_st_c_f32:
- case NVPTX::BI__hmma_m8n32k16_st_c_f16:
- case NVPTX::BI__hmma_m8n32k16_st_c_f32: {
- Value *Dst = EmitScalarExpr(E->getArg(0));
- Address Src = EmitPointerWithAlignment(E->getArg(1));
- Value *Ldm = EmitScalarExpr(E->getArg(2));
- llvm::APSInt isColMajorArg;
- if (!E->getArg(3)->isIntegerConstantExpr(isColMajorArg, getContext()))
- return nullptr;
- bool isColMajor = isColMajorArg.getSExtValue();
- unsigned IID;
- unsigned NumResults = 8;
- // PTX Instructions (and LLVM intrinsics) are defined for slice _d_, yet
- // for some reason nvcc builtins use _c_.
- switch (BuiltinID) {
- case NVPTX::BI__hmma_m16n16k16_st_c_f16:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_col_stride
- : Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_row_stride;
- NumResults = 4;
- break;
- case NVPTX::BI__hmma_m16n16k16_st_c_f32:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_col_stride
- : Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_row_stride;
- break;
- case NVPTX::BI__hmma_m32n8k16_st_c_f16:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_col_stride
- : Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_row_stride;
- NumResults = 4;
- break;
- case NVPTX::BI__hmma_m32n8k16_st_c_f32:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_col_stride
- : Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_row_stride;
- break;
- case NVPTX::BI__hmma_m8n32k16_st_c_f16:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_col_stride
- : Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_row_stride;
- NumResults = 4;
- break;
- case NVPTX::BI__hmma_m8n32k16_st_c_f32:
- IID = isColMajor ? Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_col_stride
- : Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_row_stride;
- break;
- default:
- llvm_unreachable("Unexpected builtin ID.");
- }
- Function *Intrinsic = CGM.getIntrinsic(IID, Dst->getType());
- llvm::Type *ParamType = Intrinsic->getFunctionType()->getParamType(1);
- SmallVector<Value *, 10> Values = {Dst};
- for (unsigned i = 0; i < NumResults; ++i) {
- Value *V = Builder.CreateAlignedLoad(
- Builder.CreateGEP(Src.getPointer(), llvm::ConstantInt::get(IntTy, i)),
- CharUnits::fromQuantity(4));
- Values.push_back(Builder.CreateBitCast(V, ParamType));
- }
- Values.push_back(Ldm);
- Value *Result = Builder.CreateCall(Intrinsic, Values);
- return Result;
- }
-
- // BI__hmma_m16n16k16_mma_<Dtype><CType>(d, a, b, c, layout, satf) -->
- // Intrinsic::nvvm_wmma_m16n16k16_mma_sync<layout A,B><DType><CType><Satf>
- case NVPTX::BI__hmma_m16n16k16_mma_f16f16:
- case NVPTX::BI__hmma_m16n16k16_mma_f32f16:
- case NVPTX::BI__hmma_m16n16k16_mma_f32f32:
- case NVPTX::BI__hmma_m16n16k16_mma_f16f32:
- case NVPTX::BI__hmma_m32n8k16_mma_f16f16:
- case NVPTX::BI__hmma_m32n8k16_mma_f32f16:
- case NVPTX::BI__hmma_m32n8k16_mma_f32f32:
- case NVPTX::BI__hmma_m32n8k16_mma_f16f32:
- case NVPTX::BI__hmma_m8n32k16_mma_f16f16:
- case NVPTX::BI__hmma_m8n32k16_mma_f32f16:
- case NVPTX::BI__hmma_m8n32k16_mma_f32f32:
- case NVPTX::BI__hmma_m8n32k16_mma_f16f32: {
- Address Dst = EmitPointerWithAlignment(E->getArg(0));
- Address SrcA = EmitPointerWithAlignment(E->getArg(1));
- Address SrcB = EmitPointerWithAlignment(E->getArg(2));
- Address SrcC = EmitPointerWithAlignment(E->getArg(3));
- llvm::APSInt LayoutArg;
- if (!E->getArg(4)->isIntegerConstantExpr(LayoutArg, getContext()))
- return nullptr;
- int Layout = LayoutArg.getSExtValue();
- if (Layout < 0 || Layout > 3)
- return nullptr;
- llvm::APSInt SatfArg;
- if (!E->getArg(5)->isIntegerConstantExpr(SatfArg, getContext()))
- return nullptr;
- bool Satf = SatfArg.getSExtValue();
-
- // clang-format off
-#define MMA_VARIANTS(geom, type) {{ \
- Intrinsic::nvvm_wmma_##geom##_mma_row_row_##type, \
- Intrinsic::nvvm_wmma_##geom##_mma_row_row_##type##_satfinite, \
- Intrinsic::nvvm_wmma_##geom##_mma_row_col_##type, \
- Intrinsic::nvvm_wmma_##geom##_mma_row_col_##type##_satfinite, \
- Intrinsic::nvvm_wmma_##geom##_mma_col_row_##type, \
- Intrinsic::nvvm_wmma_##geom##_mma_col_row_##type##_satfinite, \
- Intrinsic::nvvm_wmma_##geom##_mma_col_col_##type, \
- Intrinsic::nvvm_wmma_##geom##_mma_col_col_##type##_satfinite \
- }}
- // clang-format on
-
- auto getMMAIntrinsic = [Layout, Satf](std::array<unsigned, 8> Variants) {
- unsigned Index = Layout * 2 + Satf;
- assert(Index < 8);
- return Variants[Index];
- };
- unsigned IID;
- unsigned NumEltsC;
- unsigned NumEltsD;
- switch (BuiltinID) {
- case NVPTX::BI__hmma_m16n16k16_mma_f16f16:
- IID = getMMAIntrinsic(MMA_VARIANTS(m16n16k16, f16_f16));
- NumEltsC = 4;
- NumEltsD = 4;
- break;
- case NVPTX::BI__hmma_m16n16k16_mma_f32f16:
- IID = getMMAIntrinsic(MMA_VARIANTS(m16n16k16, f32_f16));
- NumEltsC = 4;
- NumEltsD = 8;
- break;
- case NVPTX::BI__hmma_m16n16k16_mma_f16f32:
- IID = getMMAIntrinsic(MMA_VARIANTS(m16n16k16, f16_f32));
- NumEltsC = 8;
- NumEltsD = 4;
- break;
- case NVPTX::BI__hmma_m16n16k16_mma_f32f32:
- IID = getMMAIntrinsic(MMA_VARIANTS(m16n16k16, f32_f32));
- NumEltsC = 8;
- NumEltsD = 8;
- break;
- case NVPTX::BI__hmma_m32n8k16_mma_f16f16:
- IID = getMMAIntrinsic(MMA_VARIANTS(m32n8k16, f16_f16));
- NumEltsC = 4;
- NumEltsD = 4;
- break;
- case NVPTX::BI__hmma_m32n8k16_mma_f32f16:
- IID = getMMAIntrinsic(MMA_VARIANTS(m32n8k16, f32_f16));
- NumEltsC = 4;
- NumEltsD = 8;
- break;
- case NVPTX::BI__hmma_m32n8k16_mma_f16f32:
- IID = getMMAIntrinsic(MMA_VARIANTS(m32n8k16, f16_f32));
- NumEltsC = 8;
- NumEltsD = 4;
- break;
- case NVPTX::BI__hmma_m32n8k16_mma_f32f32:
- IID = getMMAIntrinsic(MMA_VARIANTS(m32n8k16, f32_f32));
- NumEltsC = 8;
- NumEltsD = 8;
- break;
- case NVPTX::BI__hmma_m8n32k16_mma_f16f16:
- IID = getMMAIntrinsic(MMA_VARIANTS(m8n32k16, f16_f16));
- NumEltsC = 4;
- NumEltsD = 4;
- break;
- case NVPTX::BI__hmma_m8n32k16_mma_f32f16:
- IID = getMMAIntrinsic(MMA_VARIANTS(m8n32k16, f32_f16));
- NumEltsC = 4;
- NumEltsD = 8;
- break;
- case NVPTX::BI__hmma_m8n32k16_mma_f16f32:
- IID = getMMAIntrinsic(MMA_VARIANTS(m8n32k16, f16_f32));
- NumEltsC = 8;
- NumEltsD = 4;
- break;
- case NVPTX::BI__hmma_m8n32k16_mma_f32f32:
- IID = getMMAIntrinsic(MMA_VARIANTS(m8n32k16, f32_f32));
- NumEltsC = 8;
- NumEltsD = 8;
- break;
- default:
- llvm_unreachable("Unexpected builtin ID.");
- }
-#undef MMA_VARIANTS
-
- SmallVector<Value *, 24> Values;
- Function *Intrinsic = CGM.getIntrinsic(IID);
- llvm::Type *ABType = Intrinsic->getFunctionType()->getParamType(0);
- // Load A
- for (unsigned i = 0; i < 8; ++i) {
- Value *V = Builder.CreateAlignedLoad(
- Builder.CreateGEP(SrcA.getPointer(),
- llvm::ConstantInt::get(IntTy, i)),
- CharUnits::fromQuantity(4));
- Values.push_back(Builder.CreateBitCast(V, ABType));
- }
- // Load B
- for (unsigned i = 0; i < 8; ++i) {
- Value *V = Builder.CreateAlignedLoad(
- Builder.CreateGEP(SrcB.getPointer(),
- llvm::ConstantInt::get(IntTy, i)),
- CharUnits::fromQuantity(4));
- Values.push_back(Builder.CreateBitCast(V, ABType));
- }
- // Load C
- llvm::Type *CType = Intrinsic->getFunctionType()->getParamType(16);
- for (unsigned i = 0; i < NumEltsC; ++i) {
- Value *V = Builder.CreateAlignedLoad(
- Builder.CreateGEP(SrcC.getPointer(),
- llvm::ConstantInt::get(IntTy, i)),
- CharUnits::fromQuantity(4));
- Values.push_back(Builder.CreateBitCast(V, CType));
- }
- Value *Result = Builder.CreateCall(Intrinsic, Values);
- llvm::Type *DType = Dst.getElementType();
- for (unsigned i = 0; i < NumEltsD; ++i)
- Builder.CreateAlignedStore(
- Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), DType),
- Builder.CreateGEP(Dst.getPointer(), llvm::ConstantInt::get(IntTy, i)),
- CharUnits::fromQuantity(4));
- return Result;
- }
- default:
- return nullptr;
- }
-}
-
-Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- switch (BuiltinID) {
- case WebAssembly::BI__builtin_wasm_memory_size: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *I = EmitScalarExpr(E->getArg(0));
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_size, ResultType);
- return Builder.CreateCall(Callee, I);
- }
- case WebAssembly::BI__builtin_wasm_memory_grow: {
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Args[] = {
- EmitScalarExpr(E->getArg(0)),
- EmitScalarExpr(E->getArg(1))
- };
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_grow, ResultType);
- return Builder.CreateCall(Callee, Args);
- }
- case WebAssembly::BI__builtin_wasm_throw: {
- Value *Tag = EmitScalarExpr(E->getArg(0));
- Value *Obj = EmitScalarExpr(E->getArg(1));
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw);
- return Builder.CreateCall(Callee, {Tag, Obj});
- }
- case WebAssembly::BI__builtin_wasm_rethrow: {
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow);
- return Builder.CreateCall(Callee);
- }
- case WebAssembly::BI__builtin_wasm_atomic_wait_i32: {
- Value *Addr = EmitScalarExpr(E->getArg(0));
- Value *Expected = EmitScalarExpr(E->getArg(1));
- Value *Timeout = EmitScalarExpr(E->getArg(2));
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_atomic_wait_i32);
- return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
- }
- case WebAssembly::BI__builtin_wasm_atomic_wait_i64: {
- Value *Addr = EmitScalarExpr(E->getArg(0));
- Value *Expected = EmitScalarExpr(E->getArg(1));
- Value *Timeout = EmitScalarExpr(E->getArg(2));
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_atomic_wait_i64);
- return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
- }
- case WebAssembly::BI__builtin_wasm_atomic_notify: {
- Value *Addr = EmitScalarExpr(E->getArg(0));
- Value *Count = EmitScalarExpr(E->getArg(1));
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_atomic_notify);
- return Builder.CreateCall(Callee, {Addr, Count});
- }
- case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f64:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32x4_f32x4:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64x2_f64x2: {
- Value *Src = EmitScalarExpr(E->getArg(0));
- llvm::Type *ResT = ConvertType(E->getType());
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_saturate_signed,
- {ResT, Src->getType()});
- return Builder.CreateCall(Callee, {Src});
- }
- case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f32:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f64:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f32:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f64:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32x4_f32x4:
- case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64x2_f64x2: {
- Value *Src = EmitScalarExpr(E->getArg(0));
- llvm::Type *ResT = ConvertType(E->getType());
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_saturate_unsigned,
- {ResT, Src->getType()});
- return Builder.CreateCall(Callee, {Src});
- }
- case WebAssembly::BI__builtin_wasm_min_f32:
- case WebAssembly::BI__builtin_wasm_min_f64:
- case WebAssembly::BI__builtin_wasm_min_f32x4:
- case WebAssembly::BI__builtin_wasm_min_f64x2: {
- Value *LHS = EmitScalarExpr(E->getArg(0));
- Value *RHS = EmitScalarExpr(E->getArg(1));
- Value *Callee = CGM.getIntrinsic(Intrinsic::minimum,
- ConvertType(E->getType()));
- return Builder.CreateCall(Callee, {LHS, RHS});
- }
- case WebAssembly::BI__builtin_wasm_max_f32:
- case WebAssembly::BI__builtin_wasm_max_f64:
- case WebAssembly::BI__builtin_wasm_max_f32x4:
- case WebAssembly::BI__builtin_wasm_max_f64x2: {
- Value *LHS = EmitScalarExpr(E->getArg(0));
- Value *RHS = EmitScalarExpr(E->getArg(1));
- Value *Callee = CGM.getIntrinsic(Intrinsic::maximum,
- ConvertType(E->getType()));
- return Builder.CreateCall(Callee, {LHS, RHS});
- }
- case WebAssembly::BI__builtin_wasm_extract_lane_s_i8x16:
- case WebAssembly::BI__builtin_wasm_extract_lane_u_i8x16:
- case WebAssembly::BI__builtin_wasm_extract_lane_s_i16x8:
- case WebAssembly::BI__builtin_wasm_extract_lane_u_i16x8:
- case WebAssembly::BI__builtin_wasm_extract_lane_i32x4:
- case WebAssembly::BI__builtin_wasm_extract_lane_i64x2:
- case WebAssembly::BI__builtin_wasm_extract_lane_f32x4:
- case WebAssembly::BI__builtin_wasm_extract_lane_f64x2: {
- llvm::APSInt LaneConst;
- if (!E->getArg(1)->isIntegerConstantExpr(LaneConst, getContext()))
- llvm_unreachable("Constant arg isn't actually constant?");
- Value *Vec = EmitScalarExpr(E->getArg(0));
- Value *Lane = llvm::ConstantInt::get(getLLVMContext(), LaneConst);
- Value *Extract = Builder.CreateExtractElement(Vec, Lane);
- switch (BuiltinID) {
- case WebAssembly::BI__builtin_wasm_extract_lane_s_i8x16:
- case WebAssembly::BI__builtin_wasm_extract_lane_s_i16x8:
- return Builder.CreateSExt(Extract, ConvertType(E->getType()));
- case WebAssembly::BI__builtin_wasm_extract_lane_u_i8x16:
- case WebAssembly::BI__builtin_wasm_extract_lane_u_i16x8:
- return Builder.CreateZExt(Extract, ConvertType(E->getType()));
- case WebAssembly::BI__builtin_wasm_extract_lane_i32x4:
- case WebAssembly::BI__builtin_wasm_extract_lane_i64x2:
- case WebAssembly::BI__builtin_wasm_extract_lane_f32x4:
- case WebAssembly::BI__builtin_wasm_extract_lane_f64x2:
- return Extract;
- default:
- llvm_unreachable("unexpected builtin ID");
- }
- }
- case WebAssembly::BI__builtin_wasm_replace_lane_i8x16:
- case WebAssembly::BI__builtin_wasm_replace_lane_i16x8:
- case WebAssembly::BI__builtin_wasm_replace_lane_i32x4:
- case WebAssembly::BI__builtin_wasm_replace_lane_i64x2:
- case WebAssembly::BI__builtin_wasm_replace_lane_f32x4:
- case WebAssembly::BI__builtin_wasm_replace_lane_f64x2: {
- llvm::APSInt LaneConst;
- if (!E->getArg(1)->isIntegerConstantExpr(LaneConst, getContext()))
- llvm_unreachable("Constant arg isn't actually constant?");
- Value *Vec = EmitScalarExpr(E->getArg(0));
- Value *Lane = llvm::ConstantInt::get(getLLVMContext(), LaneConst);
- Value *Val = EmitScalarExpr(E->getArg(2));
- switch (BuiltinID) {
- case WebAssembly::BI__builtin_wasm_replace_lane_i8x16:
- case WebAssembly::BI__builtin_wasm_replace_lane_i16x8: {
- llvm::Type *ElemType = ConvertType(E->getType())->getVectorElementType();
- Value *Trunc = Builder.CreateTrunc(Val, ElemType);
- return Builder.CreateInsertElement(Vec, Trunc, Lane);
- }
- case WebAssembly::BI__builtin_wasm_replace_lane_i32x4:
- case WebAssembly::BI__builtin_wasm_replace_lane_i64x2:
- case WebAssembly::BI__builtin_wasm_replace_lane_f32x4:
- case WebAssembly::BI__builtin_wasm_replace_lane_f64x2:
- return Builder.CreateInsertElement(Vec, Val, Lane);
- default:
- llvm_unreachable("unexpected builtin ID");
- }
- }
- case WebAssembly::BI__builtin_wasm_add_saturate_s_i8x16:
- case WebAssembly::BI__builtin_wasm_add_saturate_u_i8x16:
- case WebAssembly::BI__builtin_wasm_add_saturate_s_i16x8:
- case WebAssembly::BI__builtin_wasm_add_saturate_u_i16x8:
- case WebAssembly::BI__builtin_wasm_sub_saturate_s_i8x16:
- case WebAssembly::BI__builtin_wasm_sub_saturate_u_i8x16:
- case WebAssembly::BI__builtin_wasm_sub_saturate_s_i16x8:
- case WebAssembly::BI__builtin_wasm_sub_saturate_u_i16x8: {
- unsigned IntNo;
- switch (BuiltinID) {
- case WebAssembly::BI__builtin_wasm_add_saturate_s_i8x16:
- case WebAssembly::BI__builtin_wasm_add_saturate_s_i16x8:
- IntNo = Intrinsic::sadd_sat;
- break;
- case WebAssembly::BI__builtin_wasm_add_saturate_u_i8x16:
- case WebAssembly::BI__builtin_wasm_add_saturate_u_i16x8:
- IntNo = Intrinsic::uadd_sat;
- break;
- case WebAssembly::BI__builtin_wasm_sub_saturate_s_i8x16:
- case WebAssembly::BI__builtin_wasm_sub_saturate_s_i16x8:
- IntNo = Intrinsic::wasm_sub_saturate_signed;
- break;
- case WebAssembly::BI__builtin_wasm_sub_saturate_u_i8x16:
- case WebAssembly::BI__builtin_wasm_sub_saturate_u_i16x8:
- IntNo = Intrinsic::wasm_sub_saturate_unsigned;
- break;
- default:
- llvm_unreachable("unexpected builtin ID");
- }
- Value *LHS = EmitScalarExpr(E->getArg(0));
- Value *RHS = EmitScalarExpr(E->getArg(1));
- Value *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
- return Builder.CreateCall(Callee, {LHS, RHS});
- }
- case WebAssembly::BI__builtin_wasm_bitselect: {
- Value *V1 = EmitScalarExpr(E->getArg(0));
- Value *V2 = EmitScalarExpr(E->getArg(1));
- Value *C = EmitScalarExpr(E->getArg(2));
- Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_bitselect,
- ConvertType(E->getType()));
- return Builder.CreateCall(Callee, {V1, V2, C});
- }
- case WebAssembly::BI__builtin_wasm_any_true_i8x16:
- case WebAssembly::BI__builtin_wasm_any_true_i16x8:
- case WebAssembly::BI__builtin_wasm_any_true_i32x4:
- case WebAssembly::BI__builtin_wasm_any_true_i64x2:
- case WebAssembly::BI__builtin_wasm_all_true_i8x16:
- case WebAssembly::BI__builtin_wasm_all_true_i16x8:
- case WebAssembly::BI__builtin_wasm_all_true_i32x4:
- case WebAssembly::BI__builtin_wasm_all_true_i64x2: {
- unsigned IntNo;
- switch (BuiltinID) {
- case WebAssembly::BI__builtin_wasm_any_true_i8x16:
- case WebAssembly::BI__builtin_wasm_any_true_i16x8:
- case WebAssembly::BI__builtin_wasm_any_true_i32x4:
- case WebAssembly::BI__builtin_wasm_any_true_i64x2:
- IntNo = Intrinsic::wasm_anytrue;
- break;
- case WebAssembly::BI__builtin_wasm_all_true_i8x16:
- case WebAssembly::BI__builtin_wasm_all_true_i16x8:
- case WebAssembly::BI__builtin_wasm_all_true_i32x4:
- case WebAssembly::BI__builtin_wasm_all_true_i64x2:
- IntNo = Intrinsic::wasm_alltrue;
- break;
- default:
- llvm_unreachable("unexpected builtin ID");
- }
- Value *Vec = EmitScalarExpr(E->getArg(0));
- Value *Callee = CGM.getIntrinsic(IntNo, Vec->getType());
- return Builder.CreateCall(Callee, {Vec});
- }
- case WebAssembly::BI__builtin_wasm_abs_f32x4:
- case WebAssembly::BI__builtin_wasm_abs_f64x2: {
- Value *Vec = EmitScalarExpr(E->getArg(0));
- Value *Callee = CGM.getIntrinsic(Intrinsic::fabs, Vec->getType());
- return Builder.CreateCall(Callee, {Vec});
- }
- case WebAssembly::BI__builtin_wasm_sqrt_f32x4:
- case WebAssembly::BI__builtin_wasm_sqrt_f64x2: {
- Value *Vec = EmitScalarExpr(E->getArg(0));
- Value *Callee = CGM.getIntrinsic(Intrinsic::sqrt, Vec->getType());
- return Builder.CreateCall(Callee, {Vec});
- }
-
- default:
- return nullptr;
- }
-}
-
-Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- SmallVector<llvm::Value *, 4> Ops;
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
-
- auto MakeCircLd = [&](unsigned IntID, bool HasImm) {
- // The base pointer is passed by address, so it needs to be loaded.
- Address BP = EmitPointerWithAlignment(E->getArg(0));
- BP = Address(Builder.CreateBitCast(BP.getPointer(), Int8PtrPtrTy),
- BP.getAlignment());
- llvm::Value *Base = Builder.CreateLoad(BP);
- // Operands are Base, Increment, Modifier, Start.
- if (HasImm)
- Ops = { Base, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)),
- EmitScalarExpr(E->getArg(3)) };
- else
- Ops = { Base, EmitScalarExpr(E->getArg(1)),
- EmitScalarExpr(E->getArg(2)) };
-
- llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(IntID), Ops);
- llvm::Value *NewBase = Builder.CreateExtractValue(Result, 1);
- llvm::Value *LV = Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)),
- NewBase->getType()->getPointerTo());
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- // The intrinsic generates two results. The new value for the base pointer
- // needs to be stored.
- Builder.CreateAlignedStore(NewBase, LV, Dest.getAlignment());
- return Builder.CreateExtractValue(Result, 0);
- };
-
- auto MakeCircSt = [&](unsigned IntID, bool HasImm) {
- // The base pointer is passed by address, so it needs to be loaded.
- Address BP = EmitPointerWithAlignment(E->getArg(0));
- BP = Address(Builder.CreateBitCast(BP.getPointer(), Int8PtrPtrTy),
- BP.getAlignment());
- llvm::Value *Base = Builder.CreateLoad(BP);
- // Operands are Base, Increment, Modifier, Value, Start.
- if (HasImm)
- Ops = { Base, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)),
- EmitScalarExpr(E->getArg(3)), EmitScalarExpr(E->getArg(4)) };
- else
- Ops = { Base, EmitScalarExpr(E->getArg(1)),
- EmitScalarExpr(E->getArg(2)), EmitScalarExpr(E->getArg(3)) };
-
- llvm::Value *NewBase = Builder.CreateCall(CGM.getIntrinsic(IntID), Ops);
- llvm::Value *LV = Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)),
- NewBase->getType()->getPointerTo());
- Address Dest = EmitPointerWithAlignment(E->getArg(0));
- // The intrinsic generates one result, which is the new value for the base
- // pointer. It needs to be stored.
- return Builder.CreateAlignedStore(NewBase, LV, Dest.getAlignment());
- };
-
- // Handle the conversion of bit-reverse load intrinsics to bit code.
- // The intrinsic call after this function only reads from memory and the
- // write to memory is dealt by the store instruction.
- auto MakeBrevLd = [&](unsigned IntID, llvm::Type *DestTy) {
- // The intrinsic generates one result, which is the new value for the base
- // pointer. It needs to be returned. The result of the load instruction is
- // passed to intrinsic by address, so the value needs to be stored.
- llvm::Value *BaseAddress =
- Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int8PtrTy);
-
- // Expressions like &(*pt++) will be incremented per evaluation.
- // EmitPointerWithAlignment and EmitScalarExpr evaluates the expression
- // per call.
- Address DestAddr = EmitPointerWithAlignment(E->getArg(1));
- DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), Int8PtrTy),
- DestAddr.getAlignment());
- llvm::Value *DestAddress = DestAddr.getPointer();
-
- // Operands are Base, Dest, Modifier.
- // The intrinsic format in LLVM IR is defined as
- // { ValueType, i8* } (i8*, i32).
- Ops = {BaseAddress, EmitScalarExpr(E->getArg(2))};
-
- llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(IntID), Ops);
- // The value needs to be stored as the variable is passed by reference.
- llvm::Value *DestVal = Builder.CreateExtractValue(Result, 0);
-
- // The store needs to be truncated to fit the destination type.
- // While i32 and i64 are natively supported on Hexagon, i8 and i16 needs
- // to be handled with stores of respective destination type.
- DestVal = Builder.CreateTrunc(DestVal, DestTy);
-
- llvm::Value *DestForStore =
- Builder.CreateBitCast(DestAddress, DestVal->getType()->getPointerTo());
- Builder.CreateAlignedStore(DestVal, DestForStore, DestAddr.getAlignment());
- // The updated value of the base pointer is returned.
- return Builder.CreateExtractValue(Result, 1);
- };
-
- switch (BuiltinID) {
- case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry:
- case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B: {
- Address Dest = EmitPointerWithAlignment(E->getArg(2));
- unsigned Size;
- if (BuiltinID == Hexagon::BI__builtin_HEXAGON_V6_vaddcarry) {
- Size = 512;
- ID = Intrinsic::hexagon_V6_vaddcarry;
- } else {
- Size = 1024;
- ID = Intrinsic::hexagon_V6_vaddcarry_128B;
- }
- Dest = Builder.CreateBitCast(Dest,
- llvm::VectorType::get(Builder.getInt1Ty(), Size)->getPointerTo(0));
- LoadInst *QLd = Builder.CreateLoad(Dest);
- Ops = { EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), QLd };
- llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
- llvm::Value *Vprd = Builder.CreateExtractValue(Result, 1);
- llvm::Value *Base = Builder.CreateBitCast(EmitScalarExpr(E->getArg(2)),
- Vprd->getType()->getPointerTo(0));
- Builder.CreateAlignedStore(Vprd, Base, Dest.getAlignment());
- return Builder.CreateExtractValue(Result, 0);
- }
- case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry:
- case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B: {
- Address Dest = EmitPointerWithAlignment(E->getArg(2));
- unsigned Size;
- if (BuiltinID == Hexagon::BI__builtin_HEXAGON_V6_vsubcarry) {
- Size = 512;
- ID = Intrinsic::hexagon_V6_vsubcarry;
- } else {
- Size = 1024;
- ID = Intrinsic::hexagon_V6_vsubcarry_128B;
- }
- Dest = Builder.CreateBitCast(Dest,
- llvm::VectorType::get(Builder.getInt1Ty(), Size)->getPointerTo(0));
- LoadInst *QLd = Builder.CreateLoad(Dest);
- Ops = { EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), QLd };
- llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
- llvm::Value *Vprd = Builder.CreateExtractValue(Result, 1);
- llvm::Value *Base = Builder.CreateBitCast(EmitScalarExpr(E->getArg(2)),
- Vprd->getType()->getPointerTo(0));
- Builder.CreateAlignedStore(Vprd, Base, Dest.getAlignment());
- return Builder.CreateExtractValue(Result, 0);
- }
- case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrub_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrb_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci:
- return MakeCircLd(Intrinsic::hexagon_L2_loadruh_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrh_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_L2_loadri_pci:
- return MakeCircLd(Intrinsic::hexagon_L2_loadri_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrd_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pcr:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrub_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pcr:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrb_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pcr:
- return MakeCircLd(Intrinsic::hexagon_L2_loadruh_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pcr:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrh_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_L2_loadri_pcr:
- return MakeCircLd(Intrinsic::hexagon_L2_loadri_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pcr:
- return MakeCircLd(Intrinsic::hexagon_L2_loadrd_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_S2_storerb_pci:
- return MakeCircSt(Intrinsic::hexagon_S2_storerb_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_S2_storerh_pci:
- return MakeCircSt(Intrinsic::hexagon_S2_storerh_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_S2_storerf_pci:
- return MakeCircSt(Intrinsic::hexagon_S2_storerf_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_S2_storeri_pci:
- return MakeCircSt(Intrinsic::hexagon_S2_storeri_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_S2_storerd_pci:
- return MakeCircSt(Intrinsic::hexagon_S2_storerd_pci, /*HasImm*/true);
- case Hexagon::BI__builtin_HEXAGON_S2_storerb_pcr:
- return MakeCircSt(Intrinsic::hexagon_S2_storerb_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_S2_storerh_pcr:
- return MakeCircSt(Intrinsic::hexagon_S2_storerh_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_S2_storerf_pcr:
- return MakeCircSt(Intrinsic::hexagon_S2_storerf_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_S2_storeri_pcr:
- return MakeCircSt(Intrinsic::hexagon_S2_storeri_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_HEXAGON_S2_storerd_pcr:
- return MakeCircSt(Intrinsic::hexagon_S2_storerd_pcr, /*HasImm*/false);
- case Hexagon::BI__builtin_brev_ldub:
- return MakeBrevLd(Intrinsic::hexagon_L2_loadrub_pbr, Int8Ty);
- case Hexagon::BI__builtin_brev_ldb:
- return MakeBrevLd(Intrinsic::hexagon_L2_loadrb_pbr, Int8Ty);
- case Hexagon::BI__builtin_brev_lduh:
- return MakeBrevLd(Intrinsic::hexagon_L2_loadruh_pbr, Int16Ty);
- case Hexagon::BI__builtin_brev_ldh:
- return MakeBrevLd(Intrinsic::hexagon_L2_loadrh_pbr, Int16Ty);
- case Hexagon::BI__builtin_brev_ldw:
- return MakeBrevLd(Intrinsic::hexagon_L2_loadri_pbr, Int32Ty);
- case Hexagon::BI__builtin_brev_ldd:
- return MakeBrevLd(Intrinsic::hexagon_L2_loadrd_pbr, Int64Ty);
- default:
- break;
- } // switch
-
- return nullptr;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp
deleted file mode 100644
index 1c578bd151b..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp
+++ /dev/null
@@ -1,632 +0,0 @@
-//===----- CGCUDANV.cpp - Interface to NVIDIA CUDA Runtime ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides a class for CUDA code generation targeting the NVIDIA CUDA
-// runtime library.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCUDARuntime.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "clang/AST/Decl.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/Support/Format.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-constexpr unsigned CudaFatMagic = 0x466243b1;
-constexpr unsigned HIPFatMagic = 0x48495046; // "HIPF"
-
-class CGNVCUDARuntime : public CGCUDARuntime {
-
-private:
- llvm::IntegerType *IntTy, *SizeTy;
- llvm::Type *VoidTy;
- llvm::PointerType *CharPtrTy, *VoidPtrTy, *VoidPtrPtrTy;
-
- /// Convenience reference to LLVM Context
- llvm::LLVMContext &Context;
- /// Convenience reference to the current module
- llvm::Module &TheModule;
- /// Keeps track of kernel launch stubs emitted in this module
- llvm::SmallVector<llvm::Function *, 16> EmittedKernels;
- llvm::SmallVector<std::pair<llvm::GlobalVariable *, unsigned>, 16> DeviceVars;
- /// Keeps track of variable containing handle of GPU binary. Populated by
- /// ModuleCtorFunction() and used to create corresponding cleanup calls in
- /// ModuleDtorFunction()
- llvm::GlobalVariable *GpuBinaryHandle = nullptr;
- /// Whether we generate relocatable device code.
- bool RelocatableDeviceCode;
-
- llvm::Constant *getSetupArgumentFn() const;
- llvm::Constant *getLaunchFn() const;
-
- llvm::FunctionType *getRegisterGlobalsFnTy() const;
- llvm::FunctionType *getCallbackFnTy() const;
- llvm::FunctionType *getRegisterLinkedBinaryFnTy() const;
- std::string addPrefixToName(StringRef FuncName) const;
- std::string addUnderscoredPrefixToName(StringRef FuncName) const;
-
- /// Creates a function to register all kernel stubs generated in this module.
- llvm::Function *makeRegisterGlobalsFn();
-
- /// Helper function that generates a constant string and returns a pointer to
- /// the start of the string. The result of this function can be used anywhere
- /// where the C code specifies const char*.
- llvm::Constant *makeConstantString(const std::string &Str,
- const std::string &Name = "",
- const std::string &SectionName = "",
- unsigned Alignment = 0) {
- llvm::Constant *Zeros[] = {llvm::ConstantInt::get(SizeTy, 0),
- llvm::ConstantInt::get(SizeTy, 0)};
- auto ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
- llvm::GlobalVariable *GV =
- cast<llvm::GlobalVariable>(ConstStr.getPointer());
- if (!SectionName.empty()) {
- GV->setSection(SectionName);
- // Mark the address as used which make sure that this section isn't
- // merged and we will really have it in the object file.
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
- }
- if (Alignment)
- GV->setAlignment(Alignment);
-
- return llvm::ConstantExpr::getGetElementPtr(ConstStr.getElementType(),
- ConstStr.getPointer(), Zeros);
- }
-
- /// Helper function that generates an empty dummy function returning void.
- llvm::Function *makeDummyFunction(llvm::FunctionType *FnTy) {
- assert(FnTy->getReturnType()->isVoidTy() &&
- "Can only generate dummy functions returning void!");
- llvm::Function *DummyFunc = llvm::Function::Create(
- FnTy, llvm::GlobalValue::InternalLinkage, "dummy", &TheModule);
-
- llvm::BasicBlock *DummyBlock =
- llvm::BasicBlock::Create(Context, "", DummyFunc);
- CGBuilderTy FuncBuilder(CGM, Context);
- FuncBuilder.SetInsertPoint(DummyBlock);
- FuncBuilder.CreateRetVoid();
-
- return DummyFunc;
- }
-
- void emitDeviceStubBody(CodeGenFunction &CGF, FunctionArgList &Args);
-
-public:
- CGNVCUDARuntime(CodeGenModule &CGM);
-
- void emitDeviceStub(CodeGenFunction &CGF, FunctionArgList &Args) override;
- void registerDeviceVar(llvm::GlobalVariable &Var, unsigned Flags) override {
- DeviceVars.push_back(std::make_pair(&Var, Flags));
- }
-
- /// Creates module constructor function
- llvm::Function *makeModuleCtorFunction() override;
- /// Creates module destructor function
- llvm::Function *makeModuleDtorFunction() override;
-};
-
-}
-
-std::string CGNVCUDARuntime::addPrefixToName(StringRef FuncName) const {
- if (CGM.getLangOpts().HIP)
- return ((Twine("hip") + Twine(FuncName)).str());
- return ((Twine("cuda") + Twine(FuncName)).str());
-}
-std::string
-CGNVCUDARuntime::addUnderscoredPrefixToName(StringRef FuncName) const {
- if (CGM.getLangOpts().HIP)
- return ((Twine("__hip") + Twine(FuncName)).str());
- return ((Twine("__cuda") + Twine(FuncName)).str());
-}
-
-CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM)
- : CGCUDARuntime(CGM), Context(CGM.getLLVMContext()),
- TheModule(CGM.getModule()),
- RelocatableDeviceCode(CGM.getLangOpts().GPURelocatableDeviceCode) {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
-
- IntTy = CGM.IntTy;
- SizeTy = CGM.SizeTy;
- VoidTy = CGM.VoidTy;
-
- CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy));
- VoidPtrTy = cast<llvm::PointerType>(Types.ConvertType(Ctx.VoidPtrTy));
- VoidPtrPtrTy = VoidPtrTy->getPointerTo();
-}
-
-llvm::Constant *CGNVCUDARuntime::getSetupArgumentFn() const {
- // cudaError_t cudaSetupArgument(void *, size_t, size_t)
- llvm::Type *Params[] = {VoidPtrTy, SizeTy, SizeTy};
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, Params, false),
- addPrefixToName("SetupArgument"));
-}
-
-llvm::Constant *CGNVCUDARuntime::getLaunchFn() const {
- if (CGM.getLangOpts().HIP) {
- // hipError_t hipLaunchByPtr(char *);
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, CharPtrTy, false), "hipLaunchByPtr");
- } else {
- // cudaError_t cudaLaunch(char *);
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, CharPtrTy, false), "cudaLaunch");
- }
-}
-
-llvm::FunctionType *CGNVCUDARuntime::getRegisterGlobalsFnTy() const {
- return llvm::FunctionType::get(VoidTy, VoidPtrPtrTy, false);
-}
-
-llvm::FunctionType *CGNVCUDARuntime::getCallbackFnTy() const {
- return llvm::FunctionType::get(VoidTy, VoidPtrTy, false);
-}
-
-llvm::FunctionType *CGNVCUDARuntime::getRegisterLinkedBinaryFnTy() const {
- auto CallbackFnTy = getCallbackFnTy();
- auto RegisterGlobalsFnTy = getRegisterGlobalsFnTy();
- llvm::Type *Params[] = {RegisterGlobalsFnTy->getPointerTo(), VoidPtrTy,
- VoidPtrTy, CallbackFnTy->getPointerTo()};
- return llvm::FunctionType::get(VoidTy, Params, false);
-}
-
-void CGNVCUDARuntime::emitDeviceStub(CodeGenFunction &CGF,
- FunctionArgList &Args) {
- EmittedKernels.push_back(CGF.CurFn);
- emitDeviceStubBody(CGF, Args);
-}
-
-void CGNVCUDARuntime::emitDeviceStubBody(CodeGenFunction &CGF,
- FunctionArgList &Args) {
- // Emit a call to cudaSetupArgument for each arg in Args.
- llvm::Constant *cudaSetupArgFn = getSetupArgumentFn();
- llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end");
- CharUnits Offset = CharUnits::Zero();
- for (const VarDecl *A : Args) {
- CharUnits TyWidth, TyAlign;
- std::tie(TyWidth, TyAlign) =
- CGM.getContext().getTypeInfoInChars(A->getType());
- Offset = Offset.alignTo(TyAlign);
- llvm::Value *Args[] = {
- CGF.Builder.CreatePointerCast(CGF.GetAddrOfLocalVar(A).getPointer(),
- VoidPtrTy),
- llvm::ConstantInt::get(SizeTy, TyWidth.getQuantity()),
- llvm::ConstantInt::get(SizeTy, Offset.getQuantity()),
- };
- llvm::CallSite CS = CGF.EmitRuntimeCallOrInvoke(cudaSetupArgFn, Args);
- llvm::Constant *Zero = llvm::ConstantInt::get(IntTy, 0);
- llvm::Value *CSZero = CGF.Builder.CreateICmpEQ(CS.getInstruction(), Zero);
- llvm::BasicBlock *NextBlock = CGF.createBasicBlock("setup.next");
- CGF.Builder.CreateCondBr(CSZero, NextBlock, EndBlock);
- CGF.EmitBlock(NextBlock);
- Offset += TyWidth;
- }
-
- // Emit the call to cudaLaunch
- llvm::Constant *cudaLaunchFn = getLaunchFn();
- llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy);
- CGF.EmitRuntimeCallOrInvoke(cudaLaunchFn, Arg);
- CGF.EmitBranch(EndBlock);
-
- CGF.EmitBlock(EndBlock);
-}
-
-/// Creates a function that sets up state on the host side for CUDA objects that
-/// have a presence on both the host and device sides. Specifically, registers
-/// the host side of kernel functions and device global variables with the CUDA
-/// runtime.
-/// \code
-/// void __cuda_register_globals(void** GpuBinaryHandle) {
-/// __cudaRegisterFunction(GpuBinaryHandle,Kernel0,...);
-/// ...
-/// __cudaRegisterFunction(GpuBinaryHandle,KernelM,...);
-/// __cudaRegisterVar(GpuBinaryHandle, GlobalVar0, ...);
-/// ...
-/// __cudaRegisterVar(GpuBinaryHandle, GlobalVarN, ...);
-/// }
-/// \endcode
-llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() {
- // No need to register anything
- if (EmittedKernels.empty() && DeviceVars.empty())
- return nullptr;
-
- llvm::Function *RegisterKernelsFunc = llvm::Function::Create(
- getRegisterGlobalsFnTy(), llvm::GlobalValue::InternalLinkage,
- addUnderscoredPrefixToName("_register_globals"), &TheModule);
- llvm::BasicBlock *EntryBB =
- llvm::BasicBlock::Create(Context, "entry", RegisterKernelsFunc);
- CGBuilderTy Builder(CGM, Context);
- Builder.SetInsertPoint(EntryBB);
-
- // void __cudaRegisterFunction(void **, const char *, char *, const char *,
- // int, uint3*, uint3*, dim3*, dim3*, int*)
- llvm::Type *RegisterFuncParams[] = {
- VoidPtrPtrTy, CharPtrTy, CharPtrTy, CharPtrTy, IntTy,
- VoidPtrTy, VoidPtrTy, VoidPtrTy, VoidPtrTy, IntTy->getPointerTo()};
- llvm::Constant *RegisterFunc = CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, RegisterFuncParams, false),
- addUnderscoredPrefixToName("RegisterFunction"));
-
- // Extract GpuBinaryHandle passed as the first argument passed to
- // __cuda_register_globals() and generate __cudaRegisterFunction() call for
- // each emitted kernel.
- llvm::Argument &GpuBinaryHandlePtr = *RegisterKernelsFunc->arg_begin();
- for (llvm::Function *Kernel : EmittedKernels) {
- llvm::Constant *KernelName = makeConstantString(Kernel->getName());
- llvm::Constant *NullPtr = llvm::ConstantPointerNull::get(VoidPtrTy);
- llvm::Value *Args[] = {
- &GpuBinaryHandlePtr, Builder.CreateBitCast(Kernel, VoidPtrTy),
- KernelName, KernelName, llvm::ConstantInt::get(IntTy, -1), NullPtr,
- NullPtr, NullPtr, NullPtr,
- llvm::ConstantPointerNull::get(IntTy->getPointerTo())};
- Builder.CreateCall(RegisterFunc, Args);
- }
-
- // void __cudaRegisterVar(void **, char *, char *, const char *,
- // int, int, int, int)
- llvm::Type *RegisterVarParams[] = {VoidPtrPtrTy, CharPtrTy, CharPtrTy,
- CharPtrTy, IntTy, IntTy,
- IntTy, IntTy};
- llvm::Constant *RegisterVar = CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, RegisterVarParams, false),
- addUnderscoredPrefixToName("RegisterVar"));
- for (auto &Pair : DeviceVars) {
- llvm::GlobalVariable *Var = Pair.first;
- unsigned Flags = Pair.second;
- llvm::Constant *VarName = makeConstantString(Var->getName());
- uint64_t VarSize =
- CGM.getDataLayout().getTypeAllocSize(Var->getValueType());
- llvm::Value *Args[] = {
- &GpuBinaryHandlePtr,
- Builder.CreateBitCast(Var, VoidPtrTy),
- VarName,
- VarName,
- llvm::ConstantInt::get(IntTy, (Flags & ExternDeviceVar) ? 1 : 0),
- llvm::ConstantInt::get(IntTy, VarSize),
- llvm::ConstantInt::get(IntTy, (Flags & ConstantDeviceVar) ? 1 : 0),
- llvm::ConstantInt::get(IntTy, 0)};
- Builder.CreateCall(RegisterVar, Args);
- }
-
- Builder.CreateRetVoid();
- return RegisterKernelsFunc;
-}
-
-/// Creates a global constructor function for the module:
-///
-/// For CUDA:
-/// \code
-/// void __cuda_module_ctor(void*) {
-/// Handle = __cudaRegisterFatBinary(GpuBinaryBlob);
-/// __cuda_register_globals(Handle);
-/// }
-/// \endcode
-///
-/// For HIP:
-/// \code
-/// void __hip_module_ctor(void*) {
-/// if (__hip_gpubin_handle == 0) {
-/// __hip_gpubin_handle = __hipRegisterFatBinary(GpuBinaryBlob);
-/// __hip_register_globals(__hip_gpubin_handle);
-/// }
-/// }
-/// \endcode
-llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
- bool IsHIP = CGM.getLangOpts().HIP;
- // No need to generate ctors/dtors if there is no GPU binary.
- StringRef CudaGpuBinaryFileName = CGM.getCodeGenOpts().CudaGpuBinaryFileName;
- if (CudaGpuBinaryFileName.empty() && !IsHIP)
- return nullptr;
-
- // void __{cuda|hip}_register_globals(void* handle);
- llvm::Function *RegisterGlobalsFunc = makeRegisterGlobalsFn();
- // We always need a function to pass in as callback. Create a dummy
- // implementation if we don't need to register anything.
- if (RelocatableDeviceCode && !RegisterGlobalsFunc)
- RegisterGlobalsFunc = makeDummyFunction(getRegisterGlobalsFnTy());
-
- // void ** __{cuda|hip}RegisterFatBinary(void *);
- llvm::Constant *RegisterFatbinFunc = CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(VoidPtrPtrTy, VoidPtrTy, false),
- addUnderscoredPrefixToName("RegisterFatBinary"));
- // struct { int magic, int version, void * gpu_binary, void * dont_care };
- llvm::StructType *FatbinWrapperTy =
- llvm::StructType::get(IntTy, IntTy, VoidPtrTy, VoidPtrTy);
-
- // Register GPU binary with the CUDA runtime, store returned handle in a
- // global variable and save a reference in GpuBinaryHandle to be cleaned up
- // in destructor on exit. Then associate all known kernels with the GPU binary
- // handle so CUDA runtime can figure out what to call on the GPU side.
- std::unique_ptr<llvm::MemoryBuffer> CudaGpuBinary = nullptr;
- if (!CudaGpuBinaryFileName.empty()) {
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CudaGpuBinaryOrErr =
- llvm::MemoryBuffer::getFileOrSTDIN(CudaGpuBinaryFileName);
- if (std::error_code EC = CudaGpuBinaryOrErr.getError()) {
- CGM.getDiags().Report(diag::err_cannot_open_file)
- << CudaGpuBinaryFileName << EC.message();
- return nullptr;
- }
- CudaGpuBinary = std::move(CudaGpuBinaryOrErr.get());
- }
-
- llvm::Function *ModuleCtorFunc = llvm::Function::Create(
- llvm::FunctionType::get(VoidTy, VoidPtrTy, false),
- llvm::GlobalValue::InternalLinkage,
- addUnderscoredPrefixToName("_module_ctor"), &TheModule);
- llvm::BasicBlock *CtorEntryBB =
- llvm::BasicBlock::Create(Context, "entry", ModuleCtorFunc);
- CGBuilderTy CtorBuilder(CGM, Context);
-
- CtorBuilder.SetInsertPoint(CtorEntryBB);
-
- const char *FatbinConstantName;
- const char *FatbinSectionName;
- const char *ModuleIDSectionName;
- StringRef ModuleIDPrefix;
- llvm::Constant *FatBinStr;
- unsigned FatMagic;
- if (IsHIP) {
- FatbinConstantName = ".hip_fatbin";
- FatbinSectionName = ".hipFatBinSegment";
-
- ModuleIDSectionName = "__hip_module_id";
- ModuleIDPrefix = "__hip_";
-
- if (CudaGpuBinary) {
- // If fatbin is available from early finalization, create a string
- // literal containing the fat binary loaded from the given file.
- FatBinStr = makeConstantString(CudaGpuBinary->getBuffer(), "",
- FatbinConstantName, 8);
- } else {
- // If fatbin is not available, create an external symbol
- // __hip_fatbin in section .hip_fatbin. The external symbol is supposed
- // to contain the fat binary but will be populated somewhere else,
- // e.g. by lld through link script.
- FatBinStr = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty,
- /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr,
- "__hip_fatbin", nullptr,
- llvm::GlobalVariable::NotThreadLocal);
- cast<llvm::GlobalVariable>(FatBinStr)->setSection(FatbinConstantName);
- }
-
- FatMagic = HIPFatMagic;
- } else {
- if (RelocatableDeviceCode)
- FatbinConstantName = CGM.getTriple().isMacOSX()
- ? "__NV_CUDA,__nv_relfatbin"
- : "__nv_relfatbin";
- else
- FatbinConstantName =
- CGM.getTriple().isMacOSX() ? "__NV_CUDA,__nv_fatbin" : ".nv_fatbin";
- // NVIDIA's cuobjdump looks for fatbins in this section.
- FatbinSectionName =
- CGM.getTriple().isMacOSX() ? "__NV_CUDA,__fatbin" : ".nvFatBinSegment";
-
- ModuleIDSectionName = CGM.getTriple().isMacOSX()
- ? "__NV_CUDA,__nv_module_id"
- : "__nv_module_id";
- ModuleIDPrefix = "__nv_";
-
- // For CUDA, create a string literal containing the fat binary loaded from
- // the given file.
- FatBinStr = makeConstantString(CudaGpuBinary->getBuffer(), "",
- FatbinConstantName, 8);
- FatMagic = CudaFatMagic;
- }
-
- // Create initialized wrapper structure that points to the loaded GPU binary
- ConstantInitBuilder Builder(CGM);
- auto Values = Builder.beginStruct(FatbinWrapperTy);
- // Fatbin wrapper magic.
- Values.addInt(IntTy, FatMagic);
- // Fatbin version.
- Values.addInt(IntTy, 1);
- // Data.
- Values.add(FatBinStr);
- // Unused in fatbin v1.
- Values.add(llvm::ConstantPointerNull::get(VoidPtrTy));
- llvm::GlobalVariable *FatbinWrapper = Values.finishAndCreateGlobal(
- addUnderscoredPrefixToName("_fatbin_wrapper"), CGM.getPointerAlign(),
- /*constant*/ true);
- FatbinWrapper->setSection(FatbinSectionName);
-
- // There is only one HIP fat binary per linked module, however there are
- // multiple constructor functions. Make sure the fat binary is registered
- // only once. The constructor functions are executed by the dynamic loader
- // before the program gains control. The dynamic loader cannot execute the
- // constructor functions concurrently since doing that would not guarantee
- // thread safety of the loaded program. Therefore we can assume sequential
- // execution of constructor functions here.
- if (IsHIP) {
- auto Linkage = CudaGpuBinary ? llvm::GlobalValue::InternalLinkage :
- llvm::GlobalValue::LinkOnceAnyLinkage;
- llvm::BasicBlock *IfBlock =
- llvm::BasicBlock::Create(Context, "if", ModuleCtorFunc);
- llvm::BasicBlock *ExitBlock =
- llvm::BasicBlock::Create(Context, "exit", ModuleCtorFunc);
- // The name, size, and initialization pattern of this variable is part
- // of HIP ABI.
- GpuBinaryHandle = new llvm::GlobalVariable(
- TheModule, VoidPtrPtrTy, /*isConstant=*/false,
- Linkage,
- /*Initializer=*/llvm::ConstantPointerNull::get(VoidPtrPtrTy),
- "__hip_gpubin_handle");
- GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getQuantity());
- // Prevent the weak symbol in different shared libraries being merged.
- if (Linkage != llvm::GlobalValue::InternalLinkage)
- GpuBinaryHandle->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Address GpuBinaryAddr(
- GpuBinaryHandle,
- CharUnits::fromQuantity(GpuBinaryHandle->getAlignment()));
- {
- auto HandleValue = CtorBuilder.CreateLoad(GpuBinaryAddr);
- llvm::Constant *Zero =
- llvm::Constant::getNullValue(HandleValue->getType());
- llvm::Value *EQZero = CtorBuilder.CreateICmpEQ(HandleValue, Zero);
- CtorBuilder.CreateCondBr(EQZero, IfBlock, ExitBlock);
- }
- {
- CtorBuilder.SetInsertPoint(IfBlock);
- // GpuBinaryHandle = __hipRegisterFatBinary(&FatbinWrapper);
- llvm::CallInst *RegisterFatbinCall = CtorBuilder.CreateCall(
- RegisterFatbinFunc,
- CtorBuilder.CreateBitCast(FatbinWrapper, VoidPtrTy));
- CtorBuilder.CreateStore(RegisterFatbinCall, GpuBinaryAddr);
- CtorBuilder.CreateBr(ExitBlock);
- }
- {
- CtorBuilder.SetInsertPoint(ExitBlock);
- // Call __hip_register_globals(GpuBinaryHandle);
- if (RegisterGlobalsFunc) {
- auto HandleValue = CtorBuilder.CreateLoad(GpuBinaryAddr);
- CtorBuilder.CreateCall(RegisterGlobalsFunc, HandleValue);
- }
- }
- } else if (!RelocatableDeviceCode) {
- // Register binary with CUDA runtime. This is substantially different in
- // default mode vs. separate compilation!
- // GpuBinaryHandle = __cudaRegisterFatBinary(&FatbinWrapper);
- llvm::CallInst *RegisterFatbinCall = CtorBuilder.CreateCall(
- RegisterFatbinFunc,
- CtorBuilder.CreateBitCast(FatbinWrapper, VoidPtrTy));
- GpuBinaryHandle = new llvm::GlobalVariable(
- TheModule, VoidPtrPtrTy, false, llvm::GlobalValue::InternalLinkage,
- llvm::ConstantPointerNull::get(VoidPtrPtrTy), "__cuda_gpubin_handle");
- GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getQuantity());
- CtorBuilder.CreateAlignedStore(RegisterFatbinCall, GpuBinaryHandle,
- CGM.getPointerAlign());
-
- // Call __cuda_register_globals(GpuBinaryHandle);
- if (RegisterGlobalsFunc)
- CtorBuilder.CreateCall(RegisterGlobalsFunc, RegisterFatbinCall);
- } else {
- // Generate a unique module ID.
- SmallString<64> ModuleID;
- llvm::raw_svector_ostream OS(ModuleID);
- OS << ModuleIDPrefix << llvm::format("%" PRIx64, FatbinWrapper->getGUID());
- llvm::Constant *ModuleIDConstant =
- makeConstantString(ModuleID.str(), "", ModuleIDSectionName, 32);
-
- // Create an alias for the FatbinWrapper that nvcc will look for.
- llvm::GlobalAlias::create(llvm::GlobalValue::ExternalLinkage,
- Twine("__fatbinwrap") + ModuleID, FatbinWrapper);
-
- // void __cudaRegisterLinkedBinary%ModuleID%(void (*)(void *), void *,
- // void *, void (*)(void **))
- SmallString<128> RegisterLinkedBinaryName("__cudaRegisterLinkedBinary");
- RegisterLinkedBinaryName += ModuleID;
- llvm::Constant *RegisterLinkedBinaryFunc = CGM.CreateRuntimeFunction(
- getRegisterLinkedBinaryFnTy(), RegisterLinkedBinaryName);
-
- assert(RegisterGlobalsFunc && "Expecting at least dummy function!");
- llvm::Value *Args[] = {RegisterGlobalsFunc,
- CtorBuilder.CreateBitCast(FatbinWrapper, VoidPtrTy),
- ModuleIDConstant,
- makeDummyFunction(getCallbackFnTy())};
- CtorBuilder.CreateCall(RegisterLinkedBinaryFunc, Args);
- }
-
- // Create destructor and register it with atexit() the way NVCC does it. Doing
- // it during regular destructor phase worked in CUDA before 9.2 but results in
- // double-free in 9.2.
- if (llvm::Function *CleanupFn = makeModuleDtorFunction()) {
- // extern "C" int atexit(void (*f)(void));
- llvm::FunctionType *AtExitTy =
- llvm::FunctionType::get(IntTy, CleanupFn->getType(), false);
- llvm::Constant *AtExitFunc =
- CGM.CreateRuntimeFunction(AtExitTy, "atexit", llvm::AttributeList(),
- /*Local=*/true);
- CtorBuilder.CreateCall(AtExitFunc, CleanupFn);
- }
-
- CtorBuilder.CreateRetVoid();
- return ModuleCtorFunc;
-}
-
-/// Creates a global destructor function that unregisters the GPU code blob
-/// registered by constructor.
-///
-/// For CUDA:
-/// \code
-/// void __cuda_module_dtor(void*) {
-/// __cudaUnregisterFatBinary(Handle);
-/// }
-/// \endcode
-///
-/// For HIP:
-/// \code
-/// void __hip_module_dtor(void*) {
-/// if (__hip_gpubin_handle) {
-/// __hipUnregisterFatBinary(__hip_gpubin_handle);
-/// __hip_gpubin_handle = 0;
-/// }
-/// }
-/// \endcode
-llvm::Function *CGNVCUDARuntime::makeModuleDtorFunction() {
- // No need for destructor if we don't have a handle to unregister.
- if (!GpuBinaryHandle)
- return nullptr;
-
- // void __cudaUnregisterFatBinary(void ** handle);
- llvm::Constant *UnregisterFatbinFunc = CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(VoidTy, VoidPtrPtrTy, false),
- addUnderscoredPrefixToName("UnregisterFatBinary"));
-
- llvm::Function *ModuleDtorFunc = llvm::Function::Create(
- llvm::FunctionType::get(VoidTy, VoidPtrTy, false),
- llvm::GlobalValue::InternalLinkage,
- addUnderscoredPrefixToName("_module_dtor"), &TheModule);
-
- llvm::BasicBlock *DtorEntryBB =
- llvm::BasicBlock::Create(Context, "entry", ModuleDtorFunc);
- CGBuilderTy DtorBuilder(CGM, Context);
- DtorBuilder.SetInsertPoint(DtorEntryBB);
-
- Address GpuBinaryAddr(GpuBinaryHandle, CharUnits::fromQuantity(
- GpuBinaryHandle->getAlignment()));
- auto HandleValue = DtorBuilder.CreateLoad(GpuBinaryAddr);
- // There is only one HIP fat binary per linked module, however there are
- // multiple destructor functions. Make sure the fat binary is unregistered
- // only once.
- if (CGM.getLangOpts().HIP) {
- llvm::BasicBlock *IfBlock =
- llvm::BasicBlock::Create(Context, "if", ModuleDtorFunc);
- llvm::BasicBlock *ExitBlock =
- llvm::BasicBlock::Create(Context, "exit", ModuleDtorFunc);
- llvm::Constant *Zero = llvm::Constant::getNullValue(HandleValue->getType());
- llvm::Value *NEZero = DtorBuilder.CreateICmpNE(HandleValue, Zero);
- DtorBuilder.CreateCondBr(NEZero, IfBlock, ExitBlock);
-
- DtorBuilder.SetInsertPoint(IfBlock);
- DtorBuilder.CreateCall(UnregisterFatbinFunc, HandleValue);
- DtorBuilder.CreateStore(Zero, GpuBinaryAddr);
- DtorBuilder.CreateBr(ExitBlock);
-
- DtorBuilder.SetInsertPoint(ExitBlock);
- } else {
- DtorBuilder.CreateCall(UnregisterFatbinFunc, HandleValue);
- }
- DtorBuilder.CreateRetVoid();
- return ModuleDtorFunc;
-}
-
-CGCUDARuntime *CodeGen::CreateNVCUDARuntime(CodeGenModule &CGM) {
- return new CGNVCUDARuntime(CGM);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.cpp
deleted file mode 100644
index 1936f9f1369..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//===----- CGCUDARuntime.cpp - Interface to CUDA Runtimes -----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for CUDA code generation. Concrete
-// subclasses of this implement code generation for specific CUDA
-// runtime libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCUDARuntime.h"
-#include "CGCall.h"
-#include "CodeGenFunction.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/ExprCXX.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-CGCUDARuntime::~CGCUDARuntime() {}
-
-RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
- const CUDAKernelCallExpr *E,
- ReturnValueSlot ReturnValue) {
- llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock("kcall.configok");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("kcall.end");
-
- CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(E->getConfig(), ContBlock, ConfigOKBlock,
- /*TrueCount=*/0);
-
- eval.begin(CGF);
- CGF.EmitBlock(ConfigOKBlock);
- CGF.EmitSimpleCallExpr(E, ReturnValue);
- CGF.EmitBranch(ContBlock);
-
- CGF.EmitBlock(ContBlock);
- eval.end(CGF);
-
- return RValue::get(nullptr);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.h b/gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.h
deleted file mode 100644
index 0168f4f9e94..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//===----- CGCUDARuntime.h - Interface to CUDA Runtimes ---------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for CUDA code generation. Concrete
-// subclasses of this implement code generation for specific CUDA
-// runtime libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGCUDARUNTIME_H
-#define LLVM_CLANG_LIB_CODEGEN_CGCUDARUNTIME_H
-
-namespace llvm {
-class Function;
-class GlobalVariable;
-}
-
-namespace clang {
-
-class CUDAKernelCallExpr;
-
-namespace CodeGen {
-
-class CodeGenFunction;
-class CodeGenModule;
-class FunctionArgList;
-class ReturnValueSlot;
-class RValue;
-
-class CGCUDARuntime {
-protected:
- CodeGenModule &CGM;
-
-public:
- // Global variable properties that must be passed to CUDA runtime.
- enum DeviceVarFlags {
- ExternDeviceVar = 0x01, // extern
- ConstantDeviceVar = 0x02, // __constant__
- };
-
- CGCUDARuntime(CodeGenModule &CGM) : CGM(CGM) {}
- virtual ~CGCUDARuntime();
-
- virtual RValue EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
- const CUDAKernelCallExpr *E,
- ReturnValueSlot ReturnValue);
-
- /// Emits a kernel launch stub.
- virtual void emitDeviceStub(CodeGenFunction &CGF, FunctionArgList &Args) = 0;
- virtual void registerDeviceVar(llvm::GlobalVariable &Var, unsigned Flags) = 0;
-
- /// Constructs and returns a module initialization function or nullptr if it's
- /// not needed. Must be called after all kernels have been emitted.
- virtual llvm::Function *makeModuleCtorFunction() = 0;
-
- /// Returns a module cleanup function or nullptr if it's not needed.
- /// Must be called after ModuleCtorFunction
- virtual llvm::Function *makeModuleDtorFunction() = 0;
-};
-
-/// Creates an instance of a CUDA runtime class.
-CGCUDARuntime *CreateNVCUDARuntime(CodeGenModule &CGM);
-
-}
-}
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCXX.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCXX.cpp
deleted file mode 100644
index 8b0733fbec3..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCXX.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-//===--- CGCXX.cpp - Emit LLVM Code for declarations ----------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation.
-//
-//===----------------------------------------------------------------------===//
-
-// We might split this into multiple files if it gets too unwieldy
-
-#include "CodeGenModule.h"
-#include "CGCXXABI.h"
-#include "CodeGenFunction.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Mangle.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "llvm/ADT/StringExtras.h"
-using namespace clang;
-using namespace CodeGen;
-
-
-/// Try to emit a base destructor as an alias to its primary
-/// base-class destructor.
-bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
- if (!getCodeGenOpts().CXXCtorDtorAliases)
- return true;
-
- // Producing an alias to a base class ctor/dtor can degrade debug quality
- // as the debugger cannot tell them apart.
- if (getCodeGenOpts().OptimizationLevel == 0)
- return true;
-
- // If sanitizing memory to check for use-after-dtor, do not emit as
- // an alias, unless this class owns no members.
- if (getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
- !D->getParent()->field_empty())
- return true;
-
- // If the destructor doesn't have a trivial body, we have to emit it
- // separately.
- if (!D->hasTrivialBody())
- return true;
-
- const CXXRecordDecl *Class = D->getParent();
-
- // We are going to instrument this destructor, so give up even if it is
- // currently empty.
- if (Class->mayInsertExtraPadding())
- return true;
-
- // If we need to manipulate a VTT parameter, give up.
- if (Class->getNumVBases()) {
- // Extra Credit: passing extra parameters is perfectly safe
- // in many calling conventions, so only bail out if the ctor's
- // calling convention is nonstandard.
- return true;
- }
-
- // If any field has a non-trivial destructor, we have to emit the
- // destructor separately.
- for (const auto *I : Class->fields())
- if (I->getType().isDestructedType())
- return true;
-
- // Try to find a unique base class with a non-trivial destructor.
- const CXXRecordDecl *UniqueBase = nullptr;
- for (const auto &I : Class->bases()) {
-
- // We're in the base destructor, so skip virtual bases.
- if (I.isVirtual()) continue;
-
- // Skip base classes with trivial destructors.
- const auto *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
- if (Base->hasTrivialDestructor()) continue;
-
- // If we've already found a base class with a non-trivial
- // destructor, give up.
- if (UniqueBase) return true;
- UniqueBase = Base;
- }
-
- // If we didn't find any bases with a non-trivial destructor, then
- // the base destructor is actually effectively trivial, which can
- // happen if it was needlessly user-defined or if there are virtual
- // bases with non-trivial destructors.
- if (!UniqueBase)
- return true;
-
- // If the base is at a non-zero offset, give up.
- const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
- if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero())
- return true;
-
- // Give up if the calling conventions don't match. We could update the call,
- // but it is probably not worth it.
- const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
- if (BaseD->getType()->getAs<FunctionType>()->getCallConv() !=
- D->getType()->getAs<FunctionType>()->getCallConv())
- return true;
-
- GlobalDecl AliasDecl(D, Dtor_Base);
- GlobalDecl TargetDecl(BaseD, Dtor_Base);
-
- // The alias will use the linkage of the referent. If we can't
- // support aliases with that linkage, fail.
- llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);
-
- // We can't use an alias if the linkage is not valid for one.
- if (!llvm::GlobalAlias::isValidLinkage(Linkage))
- return true;
-
- llvm::GlobalValue::LinkageTypes TargetLinkage =
- getFunctionLinkage(TargetDecl);
-
- // Check if we have it already.
- StringRef MangledName = getMangledName(AliasDecl);
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- if (Entry && !Entry->isDeclaration())
- return false;
- if (Replacements.count(MangledName))
- return false;
-
- // Derive the type for the alias.
- llvm::Type *AliasValueType = getTypes().GetFunctionType(AliasDecl);
- llvm::PointerType *AliasType = AliasValueType->getPointerTo();
-
- // Find the referent. Some aliases might require a bitcast, in
- // which case the caller is responsible for ensuring the soundness
- // of these semantics.
- auto *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
- llvm::Constant *Aliasee = Ref;
- if (Ref->getType() != AliasType)
- Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
-
- // Instead of creating as alias to a linkonce_odr, replace all of the uses
- // of the aliasee.
- if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
- !(TargetLinkage == llvm::GlobalValue::AvailableExternallyLinkage &&
- TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
- // FIXME: An extern template instantiation will create functions with
- // linkage "AvailableExternally". In libc++, some classes also define
- // members with attribute "AlwaysInline" and expect no reference to
- // be generated. It is desirable to reenable this optimisation after
- // corresponding LLVM changes.
- addReplacement(MangledName, Aliasee);
- return false;
- }
-
- // If we have a weak, non-discardable alias (weak, weak_odr), like an extern
- // template instantiation or a dllexported class, avoid forming it on COFF.
- // A COFF weak external alias cannot satisfy a normal undefined symbol
- // reference from another TU. The other TU must also mark the referenced
- // symbol as weak, which we cannot rely on.
- if (llvm::GlobalValue::isWeakForLinker(Linkage) &&
- getTriple().isOSBinFormatCOFF()) {
- return true;
- }
-
- // If we don't have a definition for the destructor yet or the definition is
- // avaialable_externally, don't emit an alias. We can't emit aliases to
- // declarations; that's just not how aliases work.
- if (Ref->isDeclarationForLinker())
- return true;
-
- // Don't create an alias to a linker weak symbol. This avoids producing
- // different COMDATs in different TUs. Another option would be to
- // output the alias both for weak_odr and linkonce_odr, but that
- // requires explicit comdat support in the IL.
- if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
- return true;
-
- // Create the alias with no name.
- auto *Alias = llvm::GlobalAlias::create(AliasValueType, 0, Linkage, "",
- Aliasee, &getModule());
-
- // Destructors are always unnamed_addr.
- Alias->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- // Switch any previous uses to the alias.
- if (Entry) {
- assert(Entry->getType() == AliasType &&
- "declaration exists with different type");
- Alias->takeName(Entry);
- Entry->replaceAllUsesWith(Alias);
- Entry->eraseFromParent();
- } else {
- Alias->setName(MangledName);
- }
-
- // Finally, set up the alias with its proper name and attributes.
- SetCommonAttributes(AliasDecl, Alias);
-
- return false;
-}
-
-llvm::Function *CodeGenModule::codegenCXXStructor(const CXXMethodDecl *MD,
- StructorType Type) {
- const CGFunctionInfo &FnInfo =
- getTypes().arrangeCXXStructorDeclaration(MD, Type);
- auto *Fn = cast<llvm::Function>(
- getAddrOfCXXStructor(MD, Type, &FnInfo, /*FnType=*/nullptr,
- /*DontDefer=*/true, ForDefinition));
-
- GlobalDecl GD;
- if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- GD = GlobalDecl(DD, toCXXDtorType(Type));
- } else {
- const auto *CD = cast<CXXConstructorDecl>(MD);
- GD = GlobalDecl(CD, toCXXCtorType(Type));
- }
-
- setFunctionLinkage(GD, Fn);
-
- CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo);
- setNonAliasAttributes(GD, Fn);
- SetLLVMFunctionAttributesForDefinition(MD, Fn);
- return Fn;
-}
-
-llvm::Constant *CodeGenModule::getAddrOfCXXStructor(
- const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo,
- llvm::FunctionType *FnType, bool DontDefer,
- ForDefinition_t IsForDefinition) {
- GlobalDecl GD;
- if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
- GD = GlobalDecl(CD, toCXXCtorType(Type));
- } else {
- // Always alias equivalent complete destructors to base destructors in the
- // MS ABI.
- if (getTarget().getCXXABI().isMicrosoft() &&
- Type == StructorType::Complete && MD->getParent()->getNumVBases() == 0)
- Type = StructorType::Base;
- GD = GlobalDecl(cast<CXXDestructorDecl>(MD), toCXXDtorType(Type));
- }
-
- if (!FnType) {
- if (!FnInfo)
- FnInfo = &getTypes().arrangeCXXStructorDeclaration(MD, Type);
- FnType = getTypes().GetFunctionType(*FnInfo);
- }
-
- return GetOrCreateLLVMFunction(
- getMangledName(GD), FnType, GD, /*ForVTable=*/false, DontDefer,
- /*isThunk=*/false, /*ExtraAttrs=*/llvm::AttributeList(), IsForDefinition);
-}
-
-static CGCallee BuildAppleKextVirtualCall(CodeGenFunction &CGF,
- GlobalDecl GD,
- llvm::Type *Ty,
- const CXXRecordDecl *RD) {
- assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() &&
- "No kext in Microsoft ABI");
- CodeGenModule &CGM = CGF.CGM;
- llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
- Ty = Ty->getPointerTo()->getPointerTo();
- VTable = CGF.Builder.CreateBitCast(VTable, Ty);
- assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
- uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
- const VTableLayout &VTLayout = CGM.getItaniumVTableContext().getVTableLayout(RD);
- VTableLayout::AddressPointLocation AddressPoint =
- VTLayout.getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
- VTableIndex += VTLayout.getVTableOffset(AddressPoint.VTableIndex) +
- AddressPoint.AddressPointIndex;
- llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
- llvm::Value *VFunc =
- CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.PointerAlignInBytes);
- CGCallee Callee(GD, VFunc);
- return Callee;
-}
-
-/// BuildAppleKextVirtualCall - This routine is to support gcc's kext ABI making
-/// indirect call to virtual functions. It makes the call through indexing
-/// into the vtable.
-CGCallee
-CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
- NestedNameSpecifier *Qual,
- llvm::Type *Ty) {
- assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) &&
- "BuildAppleKextVirtualCall - bad Qual kind");
-
- const Type *QTy = Qual->getAsType();
- QualType T = QualType(QTy, 0);
- const RecordType *RT = T->getAs<RecordType>();
- assert(RT && "BuildAppleKextVirtualCall - Qual type must be record");
- const auto *RD = cast<CXXRecordDecl>(RT->getDecl());
-
- if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD))
- return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD);
-
- return ::BuildAppleKextVirtualCall(*this, MD, Ty, RD);
-}
-
-/// BuildVirtualCall - This routine makes indirect vtable call for
-/// call to virtual destructors. It returns 0 if it could not do it.
-CGCallee
-CodeGenFunction::BuildAppleKextVirtualDestructorCall(
- const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const CXXRecordDecl *RD) {
- assert(DD->isVirtual() && Type != Dtor_Base);
- // Compute the function type we're calling.
- const CGFunctionInfo &FInfo = CGM.getTypes().arrangeCXXStructorDeclaration(
- DD, StructorType::Complete);
- llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
- return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp
deleted file mode 100644
index ed168b1ce72..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-//===----- CGCXXABI.cpp - Interface to C++ ABIs ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for C++ code generation. Concrete subclasses
-// of this implement code generation for specific C++ ABIs.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-CGCXXABI::~CGCXXABI() { }
-
-void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
- DiagnosticsEngine &Diags = CGF.CGM.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot yet compile %0 in this ABI");
- Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()),
- DiagID)
- << S;
-}
-
-bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
- // We can only copy the argument if there exists at least one trivial,
- // non-deleted copy or move constructor.
- return RD->canPassInRegisters();
-}
-
-llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
- return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
-}
-
-llvm::Type *
-CGCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
- return CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
-}
-
-CGCallee CGCXXABI::EmitLoadOfMemberFunctionPointer(
- CodeGenFunction &CGF, const Expr *E, Address This,
- llvm::Value *&ThisPtrForCall,
- llvm::Value *MemPtr, const MemberPointerType *MPT) {
- ErrorUnsupportedABI(CGF, "calls through member pointers");
-
- ThisPtrForCall = This.getPointer();
- const FunctionProtoType *FPT =
- MPT->getPointeeType()->getAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
- CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
- llvm::Constant *FnPtr = llvm::Constant::getNullValue(FTy->getPointerTo());
- return CGCallee::forDirect(FnPtr, FPT);
-}
-
-llvm::Value *
-CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
- Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
- ErrorUnsupportedABI(CGF, "loads of member pointers");
- llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType())
- ->getPointerTo(Base.getAddressSpace());
- return llvm::Constant::getNullValue(Ty);
-}
-
-llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
- const CastExpr *E,
- llvm::Value *Src) {
- ErrorUnsupportedABI(CGF, "member function pointer conversions");
- return GetBogusMemberPointer(E->getType());
-}
-
-llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *Src) {
- return GetBogusMemberPointer(E->getType());
-}
-
-llvm::Value *
-CGCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L,
- llvm::Value *R,
- const MemberPointerType *MPT,
- bool Inequality) {
- ErrorUnsupportedABI(CGF, "member function pointer comparison");
- return CGF.Builder.getFalse();
-}
-
-llvm::Value *
-CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
- ErrorUnsupportedABI(CGF, "member function pointer null testing");
- return CGF.Builder.getFalse();
-}
-
-llvm::Constant *
-CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- return GetBogusMemberPointer(QualType(MPT, 0));
-}
-
-llvm::Constant *CGCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
- return GetBogusMemberPointer(CGM.getContext().getMemberPointerType(
- MD->getType(), MD->getParent()->getTypeForDecl()));
-}
-
-llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset) {
- return GetBogusMemberPointer(QualType(MPT, 0));
-}
-
-llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
- return GetBogusMemberPointer(MPT);
-}
-
-bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
- // Fake answer.
- return true;
-}
-
-void CGCXXABI::buildThisParam(CodeGenFunction &CGF, FunctionArgList &params) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
-
- // FIXME: I'm not entirely sure I like using a fake decl just for code
- // generation. Maybe we can come up with a better way?
- auto *ThisDecl = ImplicitParamDecl::Create(
- CGM.getContext(), nullptr, MD->getLocation(),
- &CGM.getContext().Idents.get("this"), MD->getThisType(),
- ImplicitParamDecl::CXXThis);
- params.push_back(ThisDecl);
- CGF.CXXABIThisDecl = ThisDecl;
-
- // Compute the presumed alignment of 'this', which basically comes
- // down to whether we know it's a complete object or not.
- auto &Layout = CGF.getContext().getASTRecordLayout(MD->getParent());
- if (MD->getParent()->getNumVBases() == 0 || // avoid vcall in common case
- MD->getParent()->hasAttr<FinalAttr>() ||
- !isThisCompleteObject(CGF.CurGD)) {
- CGF.CXXABIThisAlignment = Layout.getAlignment();
- } else {
- CGF.CXXABIThisAlignment = Layout.getNonVirtualAlignment();
- }
-}
-
-llvm::Value *CGCXXABI::loadIncomingCXXThis(CodeGenFunction &CGF) {
- return CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getThisDecl(CGF)),
- "this");
-}
-
-void CGCXXABI::setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr) {
- /// Initialize the 'this' slot.
- assert(getThisDecl(CGF) && "no 'this' variable for function");
- CGF.CXXABIThisValue = ThisPtr;
-}
-
-void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
- RValue RV, QualType ResultType) {
- CGF.EmitReturnOfRValue(RV, ResultType);
-}
-
-CharUnits CGCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
- if (!requiresArrayCookie(expr))
- return CharUnits::Zero();
- return getArrayCookieSizeImpl(expr->getAllocatedType());
-}
-
-CharUnits CGCXXABI::getArrayCookieSizeImpl(QualType elementType) {
- // BOGUS
- return CharUnits::Zero();
-}
-
-Address CGCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
- Address NewPtr,
- llvm::Value *NumElements,
- const CXXNewExpr *expr,
- QualType ElementType) {
- // Should never be called.
- ErrorUnsupportedABI(CGF, "array cookie initialization");
- return Address::invalid();
-}
-
-bool CGCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
- QualType elementType) {
- // If the class's usual deallocation function takes two arguments,
- // it needs a cookie.
- if (expr->doesUsualArrayDeleteWantSize())
- return true;
-
- return elementType.isDestructedType();
-}
-
-bool CGCXXABI::requiresArrayCookie(const CXXNewExpr *expr) {
- // If the class's usual deallocation function takes two arguments,
- // it needs a cookie.
- if (expr->doesUsualArrayDeleteWantSize())
- return true;
-
- return expr->getAllocatedType().isDestructedType();
-}
-
-void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, Address ptr,
- const CXXDeleteExpr *expr, QualType eltTy,
- llvm::Value *&numElements,
- llvm::Value *&allocPtr, CharUnits &cookieSize) {
- // Derive a char* in the same address space as the pointer.
- ptr = CGF.Builder.CreateElementBitCast(ptr, CGF.Int8Ty);
-
- // If we don't need an array cookie, bail out early.
- if (!requiresArrayCookie(expr, eltTy)) {
- allocPtr = ptr.getPointer();
- numElements = nullptr;
- cookieSize = CharUnits::Zero();
- return;
- }
-
- cookieSize = getArrayCookieSizeImpl(eltTy);
- Address allocAddr =
- CGF.Builder.CreateConstInBoundsByteGEP(ptr, -cookieSize);
- allocPtr = allocAddr.getPointer();
- numElements = readArrayCookieImpl(CGF, allocAddr, cookieSize);
-}
-
-llvm::Value *CGCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
- Address ptr,
- CharUnits cookieSize) {
- ErrorUnsupportedABI(CGF, "reading a new[] cookie");
- return llvm::ConstantInt::get(CGF.SizeTy, 0);
-}
-
-/// Returns the adjustment, in bytes, required for the given
-/// member-pointer operation. Returns null if no adjustment is
-/// required.
-llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) {
- assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
- E->getCastKind() == CK_BaseToDerivedMemberPointer);
-
- QualType derivedType;
- if (E->getCastKind() == CK_DerivedToBaseMemberPointer)
- derivedType = E->getSubExpr()->getType();
- else
- derivedType = E->getType();
-
- const CXXRecordDecl *derivedClass =
- derivedType->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl();
-
- return CGM.GetNonVirtualBaseClassOffset(derivedClass,
- E->path_begin(),
- E->path_end());
-}
-
-CharUnits CGCXXABI::getMemberPointerPathAdjustment(const APValue &MP) {
- // TODO: Store base specifiers in APValue member pointer paths so we can
- // easily reuse CGM.GetNonVirtualBaseClassOffset().
- const ValueDecl *MPD = MP.getMemberPointerDecl();
- CharUnits ThisAdjustment = CharUnits::Zero();
- ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath();
- bool DerivedMember = MP.isMemberPointerToDerivedMember();
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPD->getDeclContext());
- for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- const CXXRecordDecl *Base = RD;
- const CXXRecordDecl *Derived = Path[I];
- if (DerivedMember)
- std::swap(Base, Derived);
- ThisAdjustment +=
- getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base);
- RD = Path[I];
- }
- if (DerivedMember)
- ThisAdjustment = -ThisAdjustment;
- return ThisAdjustment;
-}
-
-llvm::BasicBlock *
-CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
- const CXXRecordDecl *RD) {
- if (CGM.getTarget().getCXXABI().hasConstructorVariants())
- llvm_unreachable("shouldn't be called in this ABI");
-
- ErrorUnsupportedABI(CGF, "complete object detection in ctor");
- return nullptr;
-}
-
-void CGCXXABI::setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const {
- // Assume the base C++ ABI has no special rules for destructor variants.
- CGM.setDLLImportDLLExport(GV, Dtor);
-}
-
-llvm::GlobalValue::LinkageTypes CGCXXABI::getCXXDestructorLinkage(
- GVALinkage Linkage, const CXXDestructorDecl *Dtor, CXXDtorType DT) const {
- // Delegate back to CGM by default.
- return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage,
- /*isConstantVariable=*/false);
-}
-
-bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) {
- return false;
-}
-
-llvm::CallInst *
-CGCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
- llvm::Value *Exn) {
- // Just call std::terminate and ignore the violating exception.
- return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());
-}
-
-CatchTypeInfo CGCXXABI::getCatchAllTypeInfo() {
- return CatchTypeInfo{nullptr, 0};
-}
-
-std::vector<CharUnits> CGCXXABI::getVBPtrOffsets(const CXXRecordDecl *RD) {
- return std::vector<CharUnits>();
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.h b/gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.h
deleted file mode 100644
index 65b50e14f43..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCXXABI.h
+++ /dev/null
@@ -1,624 +0,0 @@
-//===----- CGCXXABI.h - Interface to C++ ABIs -------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for C++ code generation. Concrete subclasses
-// of this implement code generation for specific C++ ABIs.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGCXXABI_H
-#define LLVM_CLANG_LIB_CODEGEN_CGCXXABI_H
-
-#include "CodeGenFunction.h"
-#include "clang/Basic/LLVM.h"
-
-namespace llvm {
-class Constant;
-class Type;
-class Value;
-class CallInst;
-}
-
-namespace clang {
-class CastExpr;
-class CXXConstructorDecl;
-class CXXDestructorDecl;
-class CXXMethodDecl;
-class CXXRecordDecl;
-class FieldDecl;
-class MangleContext;
-
-namespace CodeGen {
-class CGCallee;
-class CodeGenFunction;
-class CodeGenModule;
-struct CatchTypeInfo;
-
-/// Implements C++ ABI-specific code generation functions.
-class CGCXXABI {
-protected:
- CodeGenModule &CGM;
- std::unique_ptr<MangleContext> MangleCtx;
-
- CGCXXABI(CodeGenModule &CGM)
- : CGM(CGM), MangleCtx(CGM.getContext().createMangleContext()) {}
-
-protected:
- ImplicitParamDecl *getThisDecl(CodeGenFunction &CGF) {
- return CGF.CXXABIThisDecl;
- }
- llvm::Value *getThisValue(CodeGenFunction &CGF) {
- return CGF.CXXABIThisValue;
- }
- Address getThisAddress(CodeGenFunction &CGF) {
- return Address(CGF.CXXABIThisValue, CGF.CXXABIThisAlignment);
- }
-
- /// Issue a diagnostic about unsupported features in the ABI.
- void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S);
-
- /// Get a null value for unsupported member pointers.
- llvm::Constant *GetBogusMemberPointer(QualType T);
-
- ImplicitParamDecl *&getStructorImplicitParamDecl(CodeGenFunction &CGF) {
- return CGF.CXXStructorImplicitParamDecl;
- }
- llvm::Value *&getStructorImplicitParamValue(CodeGenFunction &CGF) {
- return CGF.CXXStructorImplicitParamValue;
- }
-
- /// Loads the incoming C++ this pointer as it was passed by the caller.
- llvm::Value *loadIncomingCXXThis(CodeGenFunction &CGF);
-
- void setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr);
-
- ASTContext &getContext() const { return CGM.getContext(); }
-
- virtual bool requiresArrayCookie(const CXXDeleteExpr *E, QualType eltType);
- virtual bool requiresArrayCookie(const CXXNewExpr *E);
-
- /// Determine whether there's something special about the rules of
- /// the ABI tell us that 'this' is a complete object within the
- /// given function. Obvious common logic like being defined on a
- /// final class will have been taken care of by the caller.
- virtual bool isThisCompleteObject(GlobalDecl GD) const = 0;
-
-public:
-
- virtual ~CGCXXABI();
-
- /// Gets the mangle context.
- MangleContext &getMangleContext() {
- return *MangleCtx;
- }
-
- /// Returns true if the given constructor or destructor is one of the
- /// kinds that the ABI says returns 'this' (only applies when called
- /// non-virtually for destructors).
- ///
- /// There currently is no way to indicate if a destructor returns 'this'
- /// when called virtually, and code generation does not support the case.
- virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
-
- virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; }
-
- /// Returns true if the target allows calling a function through a pointer
- /// with a different signature than the actual function (or equivalently,
- /// bitcasting a function or function pointer to a different function type).
- /// In principle in the most general case this could depend on the target, the
- /// calling convention, and the actual types of the arguments and return
- /// value. Here it just means whether the signature mismatch could *ever* be
- /// allowed; in other words, does the target do strict checking of signatures
- /// for all calls.
- virtual bool canCallMismatchedFunctionType() const { return true; }
-
- /// If the C++ ABI requires the given type be returned in a particular way,
- /// this method sets RetAI and returns true.
- virtual bool classifyReturnType(CGFunctionInfo &FI) const = 0;
-
- /// Specify how one should pass an argument of a record type.
- enum RecordArgABI {
- /// Pass it using the normal C aggregate rules for the ABI, potentially
- /// introducing extra copies and passing some or all of it in registers.
- RAA_Default = 0,
-
- /// Pass it on the stack using its defined layout. The argument must be
- /// evaluated directly into the correct stack position in the arguments area,
- /// and the call machinery must not move it or introduce extra copies.
- RAA_DirectInMemory,
-
- /// Pass it as a pointer to temporary memory.
- RAA_Indirect
- };
-
- /// Returns true if C++ allows us to copy the memory of an object of type RD
- /// when it is passed as an argument.
- bool canCopyArgument(const CXXRecordDecl *RD) const;
-
- /// Returns how an argument of the given record type should be passed.
- virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0;
-
- /// Returns true if the implicit 'sret' parameter comes after the implicit
- /// 'this' parameter of C++ instance methods.
- virtual bool isSRetParameterAfterThis() const { return false; }
-
- /// Find the LLVM type used to represent the given member pointer
- /// type.
- virtual llvm::Type *
- ConvertMemberPointerType(const MemberPointerType *MPT);
-
- /// Load a member function from an object and a member function
- /// pointer. Apply the this-adjustment and set 'This' to the
- /// adjusted value.
- virtual CGCallee EmitLoadOfMemberFunctionPointer(
- CodeGenFunction &CGF, const Expr *E, Address This,
- llvm::Value *&ThisPtrForCall, llvm::Value *MemPtr,
- const MemberPointerType *MPT);
-
- /// Calculate an l-value from an object and a data member pointer.
- virtual llvm::Value *
- EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
- Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT);
-
- /// Perform a derived-to-base, base-to-derived, or bitcast member
- /// pointer conversion.
- virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
- const CastExpr *E,
- llvm::Value *Src);
-
- /// Perform a derived-to-base, base-to-derived, or bitcast member
- /// pointer conversion on a constant value.
- virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *Src);
-
- /// Return true if the given member pointer can be zero-initialized
- /// (in the C++ sense) with an LLVM zeroinitializer.
- virtual bool isZeroInitializable(const MemberPointerType *MPT);
-
- /// Return whether or not a member pointers type is convertible to an IR type.
- virtual bool isMemberPointerConvertible(const MemberPointerType *MPT) const {
- return true;
- }
-
- /// Create a null member pointer of the given type.
- virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
-
- /// Create a member pointer for the given method.
- virtual llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD);
-
- /// Create a member pointer for the given field.
- virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset);
-
- /// Create a member pointer for the given member pointer constant.
- virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT);
-
- /// Emit a comparison between two member pointers. Returns an i1.
- virtual llvm::Value *
- EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L,
- llvm::Value *R,
- const MemberPointerType *MPT,
- bool Inequality);
-
- /// Determine if a member pointer is non-null. Returns an i1.
- virtual llvm::Value *
- EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT);
-
-protected:
- /// A utility method for computing the offset required for the given
- /// base-to-derived or derived-to-base member-pointer conversion.
- /// Does not handle virtual conversions (in case we ever fully
- /// support an ABI that allows this). Returns null if no adjustment
- /// is required.
- llvm::Constant *getMemberPointerAdjustment(const CastExpr *E);
-
- /// Computes the non-virtual adjustment needed for a member pointer
- /// conversion along an inheritance path stored in an APValue. Unlike
- /// getMemberPointerAdjustment(), the adjustment can be negative if the path
- /// is from a derived type to a base type.
- CharUnits getMemberPointerPathAdjustment(const APValue &MP);
-
-public:
- virtual void emitVirtualObjectDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- Address Ptr, QualType ElementType,
- const CXXDestructorDecl *Dtor) = 0;
- virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0;
- virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0;
- virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; }
-
- /// Determine whether it's possible to emit a vtable for \p RD, even
- /// though we do not know that the vtable has been marked as used by semantic
- /// analysis.
- virtual bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const = 0;
-
- virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0;
-
- virtual llvm::CallInst *
- emitTerminateForUnexpectedException(CodeGenFunction &CGF,
- llvm::Value *Exn);
-
- virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
- virtual CatchTypeInfo
- getAddrOfCXXCatchHandlerType(QualType Ty, QualType CatchHandlerType) = 0;
- virtual CatchTypeInfo getCatchAllTypeInfo();
-
- virtual bool shouldTypeidBeNullChecked(bool IsDeref,
- QualType SrcRecordTy) = 0;
- virtual void EmitBadTypeidCall(CodeGenFunction &CGF) = 0;
- virtual llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
- Address ThisPtr,
- llvm::Type *StdTypeInfoPtrTy) = 0;
-
- virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
- QualType SrcRecordTy) = 0;
-
- virtual llvm::Value *
- EmitDynamicCastCall(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy, QualType DestTy,
- QualType DestRecordTy, llvm::BasicBlock *CastEnd) = 0;
-
- virtual llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF,
- Address Value,
- QualType SrcRecordTy,
- QualType DestTy) = 0;
-
- virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
-
- virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
- Address This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) = 0;
-
- virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
- const CXXRecordDecl *RD);
-
- /// Emit the code to initialize hidden members required
- /// to handle virtual inheritance, if needed by the ABI.
- virtual void
- initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
- const CXXRecordDecl *RD) {}
-
- /// Emit constructor variants required by this ABI.
- virtual void EmitCXXConstructors(const CXXConstructorDecl *D) = 0;
-
- /// Notes how many arguments were added to the beginning (Prefix) and ending
- /// (Suffix) of an arg list.
- ///
- /// Note that Prefix actually refers to the number of args *after* the first
- /// one: `this` arguments always come first.
- struct AddedStructorArgs {
- unsigned Prefix = 0;
- unsigned Suffix = 0;
- AddedStructorArgs() = default;
- AddedStructorArgs(unsigned P, unsigned S) : Prefix(P), Suffix(S) {}
- static AddedStructorArgs prefix(unsigned N) { return {N, 0}; }
- static AddedStructorArgs suffix(unsigned N) { return {0, N}; }
- };
-
- /// Build the signature of the given constructor or destructor variant by
- /// adding any required parameters. For convenience, ArgTys has been
- /// initialized with the type of 'this'.
- virtual AddedStructorArgs
- buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) = 0;
-
- /// Returns true if the given destructor type should be emitted as a linkonce
- /// delegating thunk, regardless of whether the dtor is defined in this TU or
- /// not.
- virtual bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const = 0;
-
- virtual void setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const;
-
- virtual llvm::GlobalValue::LinkageTypes
- getCXXDestructorLinkage(GVALinkage Linkage, const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const;
-
- /// Emit destructor variants required by this ABI.
- virtual void EmitCXXDestructors(const CXXDestructorDecl *D) = 0;
-
- /// Get the type of the implicit "this" parameter used by a method. May return
- /// zero if no specific type is applicable, e.g. if the ABI expects the "this"
- /// parameter to point to some artificial offset in a complete object due to
- /// vbases being reordered.
- virtual const CXXRecordDecl *
- getThisArgumentTypeForMethod(const CXXMethodDecl *MD) {
- return MD->getParent();
- }
-
- /// Perform ABI-specific "this" argument adjustment required prior to
- /// a call of a virtual function.
- /// The "VirtualCall" argument is true iff the call itself is virtual.
- virtual Address
- adjustThisArgumentForVirtualFunctionCall(CodeGenFunction &CGF, GlobalDecl GD,
- Address This, bool VirtualCall) {
- return This;
- }
-
- /// Build a parameter variable suitable for 'this'.
- void buildThisParam(CodeGenFunction &CGF, FunctionArgList &Params);
-
- /// Insert any ABI-specific implicit parameters into the parameter list for a
- /// function. This generally involves extra data for constructors and
- /// destructors.
- ///
- /// ABIs may also choose to override the return type, which has been
- /// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or
- /// the formal return type of the function otherwise.
- virtual void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy,
- FunctionArgList &Params) = 0;
-
- /// Get the ABI-specific "this" parameter adjustment to apply in the prologue
- /// of a virtual function.
- virtual CharUnits getVirtualFunctionPrologueThisAdjustment(GlobalDecl GD) {
- return CharUnits::Zero();
- }
-
- /// Emit the ABI-specific prolog for the function.
- virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
-
- /// Add any ABI-specific implicit arguments needed to call a constructor.
- ///
- /// \return The number of arguments added at the beginning and end of the
- /// call, which is typically zero or one.
- virtual AddedStructorArgs
- addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating, CallArgList &Args) = 0;
-
- /// Emit the destructor call.
- virtual void EmitDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *DD, CXXDtorType Type,
- bool ForVirtualBase, bool Delegating,
- Address This) = 0;
-
- /// Emits the VTable definitions required for the given record type.
- virtual void emitVTableDefinitions(CodeGenVTables &CGVT,
- const CXXRecordDecl *RD) = 0;
-
- /// Checks if ABI requires extra virtual offset for vtable field.
- virtual bool
- isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF,
- CodeGenFunction::VPtr Vptr) = 0;
-
- /// Checks if ABI requires to initialize vptrs for given dynamic class.
- virtual bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) = 0;
-
- /// Get the address point of the vtable for the given base subobject.
- virtual llvm::Constant *
- getVTableAddressPoint(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) = 0;
-
- /// Get the address point of the vtable for the given base subobject while
- /// building a constructor or a destructor.
- virtual llvm::Value *
- getVTableAddressPointInStructor(CodeGenFunction &CGF, const CXXRecordDecl *RD,
- BaseSubobject Base,
- const CXXRecordDecl *NearestVBase) = 0;
-
- /// Get the address point of the vtable for the given base subobject while
- /// building a constexpr.
- virtual llvm::Constant *
- getVTableAddressPointForConstExpr(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) = 0;
-
- /// Get the address of the vtable for the given record decl which should be
- /// used for the vptr at the given offset in RD.
- virtual llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
- CharUnits VPtrOffset) = 0;
-
- /// Build a virtual function pointer in the ABI-specific way.
- virtual CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF,
- GlobalDecl GD, Address This,
- llvm::Type *Ty,
- SourceLocation Loc) = 0;
-
- /// Emit the ABI-specific virtual destructor call.
- virtual llvm::Value *
- EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType, Address This,
- const CXXMemberCallExpr *CE) = 0;
-
- virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
- GlobalDecl GD,
- CallArgList &CallArgs) {}
-
- /// Emit any tables needed to implement virtual inheritance. For Itanium,
- /// this emits virtual table tables. For the MSVC++ ABI, this emits virtual
- /// base tables.
- virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0;
-
- virtual bool exportThunk() = 0;
- virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable,
- GlobalDecl GD, bool ReturnAdjustment) = 0;
-
- virtual llvm::Value *performThisAdjustment(CodeGenFunction &CGF,
- Address This,
- const ThisAdjustment &TA) = 0;
-
- virtual llvm::Value *performReturnAdjustment(CodeGenFunction &CGF,
- Address Ret,
- const ReturnAdjustment &RA) = 0;
-
- virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
- RValue RV, QualType ResultType);
-
- virtual size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
- FunctionArgList &Args) const = 0;
-
- /// Gets the offsets of all the virtual base pointers in a given class.
- virtual std::vector<CharUnits> getVBPtrOffsets(const CXXRecordDecl *RD);
-
- /// Gets the pure virtual member call function.
- virtual StringRef GetPureVirtualCallName() = 0;
-
- /// Gets the deleted virtual member call name.
- virtual StringRef GetDeletedVirtualCallName() = 0;
-
- /**************************** Array cookies ******************************/
-
- /// Returns the extra size required in order to store the array
- /// cookie for the given new-expression. May return 0 to indicate that no
- /// array cookie is required.
- ///
- /// Several cases are filtered out before this method is called:
- /// - non-array allocations never need a cookie
- /// - calls to \::operator new(size_t, void*) never need a cookie
- ///
- /// \param expr - the new-expression being allocated.
- virtual CharUnits GetArrayCookieSize(const CXXNewExpr *expr);
-
- /// Initialize the array cookie for the given allocation.
- ///
- /// \param NewPtr - a char* which is the presumed-non-null
- /// return value of the allocation function
- /// \param NumElements - the computed number of elements,
- /// potentially collapsed from the multidimensional array case;
- /// always a size_t
- /// \param ElementType - the base element allocated type,
- /// i.e. the allocated type after stripping all array types
- virtual Address InitializeArrayCookie(CodeGenFunction &CGF,
- Address NewPtr,
- llvm::Value *NumElements,
- const CXXNewExpr *expr,
- QualType ElementType);
-
- /// Reads the array cookie associated with the given pointer,
- /// if it has one.
- ///
- /// \param Ptr - a pointer to the first element in the array
- /// \param ElementType - the base element type of elements of the array
- /// \param NumElements - an out parameter which will be initialized
- /// with the number of elements allocated, or zero if there is no
- /// cookie
- /// \param AllocPtr - an out parameter which will be initialized
- /// with a char* pointing to the address returned by the allocation
- /// function
- /// \param CookieSize - an out parameter which will be initialized
- /// with the size of the cookie, or zero if there is no cookie
- virtual void ReadArrayCookie(CodeGenFunction &CGF, Address Ptr,
- const CXXDeleteExpr *expr,
- QualType ElementType, llvm::Value *&NumElements,
- llvm::Value *&AllocPtr, CharUnits &CookieSize);
-
- /// Return whether the given global decl needs a VTT parameter.
- virtual bool NeedsVTTParameter(GlobalDecl GD);
-
-protected:
- /// Returns the extra size required in order to store the array
- /// cookie for the given type. Assumes that an array cookie is
- /// required.
- virtual CharUnits getArrayCookieSizeImpl(QualType elementType);
-
- /// Reads the array cookie for an allocation which is known to have one.
- /// This is called by the standard implementation of ReadArrayCookie.
- ///
- /// \param ptr - a pointer to the allocation made for an array, as a char*
- /// \param cookieSize - the computed cookie size of an array
- ///
- /// Other parameters are as above.
- ///
- /// \return a size_t
- virtual llvm::Value *readArrayCookieImpl(CodeGenFunction &IGF, Address ptr,
- CharUnits cookieSize);
-
-public:
-
- /*************************** Static local guards ****************************/
-
- /// Emits the guarded initializer and destructor setup for the given
- /// variable, given that it couldn't be emitted as a constant.
- /// If \p PerformInit is false, the initialization has been folded to a
- /// constant and should not be performed.
- ///
- /// The variable may be:
- /// - a static local variable
- /// - a static data member of a class template instantiation
- virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr,
- bool PerformInit) = 0;
-
- /// Emit code to force the execution of a destructor during global
- /// teardown. The default implementation of this uses atexit.
- ///
- /// \param Dtor - a function taking a single pointer argument
- /// \param Addr - a pointer to pass to the destructor function.
- virtual void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *Dtor,
- llvm::Constant *Addr) = 0;
-
- /*************************** thread_local initialization ********************/
-
- /// Emits ABI-required functions necessary to initialize thread_local
- /// variables in this translation unit.
- ///
- /// \param CXXThreadLocals - The thread_local declarations in this translation
- /// unit.
- /// \param CXXThreadLocalInits - If this translation unit contains any
- /// non-constant initialization or non-trivial destruction for
- /// thread_local variables, a list of functions to perform the
- /// initialization.
- virtual void EmitThreadLocalInitFuncs(
- CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
- ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<const VarDecl *> CXXThreadLocalInitVars) = 0;
-
- // Determine if references to thread_local global variables can be made
- // directly or require access through a thread wrapper function.
- virtual bool usesThreadWrapperFunction() const = 0;
-
- /// Emit a reference to a non-local thread_local variable (including
- /// triggering the initialization of all thread_local variables in its
- /// translation unit).
- virtual LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
- const VarDecl *VD,
- QualType LValType) = 0;
-
- /// Emit a single constructor/destructor with the given type from a C++
- /// constructor Decl.
- virtual void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) = 0;
-
- /// Load a vtable from This, an object of polymorphic type RD, or from one of
- /// its virtual bases if it does not have its own vtable. Returns the vtable
- /// and the class from which the vtable was loaded.
- virtual std::pair<llvm::Value *, const CXXRecordDecl *>
- LoadVTablePtr(CodeGenFunction &CGF, Address This,
- const CXXRecordDecl *RD) = 0;
-};
-
-// Create an instance of a C++ ABI class:
-
-/// Creates an Itanium-family ABI.
-CGCXXABI *CreateItaniumCXXABI(CodeGenModule &CGM);
-
-/// Creates a Microsoft-family ABI.
-CGCXXABI *CreateMicrosoftCXXABI(CodeGenModule &CGM);
-
-struct CatchRetScope final : EHScopeStack::Cleanup {
- llvm::CatchPadInst *CPI;
-
- CatchRetScope(llvm::CatchPadInst *CPI) : CPI(CPI) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- llvm::BasicBlock *BB = CGF.createBasicBlock("catchret.dest");
- CGF.Builder.CreateCatchRet(CPI, BB);
- CGF.EmitBlock(BB);
- }
-};
-}
-}
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp
deleted file mode 100644
index 8a3ae7511cf..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp
+++ /dev/null
@@ -1,4579 +0,0 @@
-//===--- CGCall.cpp - Encapsulate calling convention details --------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes wrap the information about a call or function
-// definition used to handle ABI compliancy.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCall.h"
-#include "ABIInfo.h"
-#include "CGBlocks.h"
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/TargetBuiltins.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/CodeGen/SwiftCallingConv.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Transforms/Utils/Local.h"
-#include "llvm/Analysis/ValueTracking.h"
-#include "llvm/IR/Attributes.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/CallingConv.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Intrinsics.h"
-using namespace clang;
-using namespace CodeGen;
-
-/***/
-
-unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
- switch (CC) {
- default: return llvm::CallingConv::C;
- case CC_X86StdCall: return llvm::CallingConv::X86_StdCall;
- case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
- case CC_X86RegCall: return llvm::CallingConv::X86_RegCall;
- case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
- case CC_Win64: return llvm::CallingConv::Win64;
- case CC_X86_64SysV: return llvm::CallingConv::X86_64_SysV;
- case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
- case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
- case CC_IntelOclBicc: return llvm::CallingConv::Intel_OCL_BI;
- // TODO: Add support for __pascal to LLVM.
- case CC_X86Pascal: return llvm::CallingConv::C;
- // TODO: Add support for __vectorcall to LLVM.
- case CC_X86VectorCall: return llvm::CallingConv::X86_VectorCall;
- case CC_AArch64VectorCall: return llvm::CallingConv::AArch64_VectorCall;
- case CC_SpirFunction: return llvm::CallingConv::SPIR_FUNC;
- case CC_OpenCLKernel: return CGM.getTargetCodeGenInfo().getOpenCLKernelCallingConv();
- case CC_PreserveMost: return llvm::CallingConv::PreserveMost;
- case CC_PreserveAll: return llvm::CallingConv::PreserveAll;
- case CC_Swift: return llvm::CallingConv::Swift;
- }
-}
-
-/// Derives the 'this' type for codegen purposes, i.e. ignoring method CVR
-/// qualification.
-static CanQualType GetThisType(ASTContext &Context, const CXXRecordDecl *RD,
- const CXXMethodDecl *MD) {
- QualType RecTy = Context.getTagDeclType(RD)->getCanonicalTypeInternal();
- if (MD)
- RecTy = Context.getAddrSpaceQualType(RecTy, MD->getTypeQualifiers().getAddressSpace());
- return Context.getPointerType(CanQualType::CreateUnsafe(RecTy));
-}
-
-/// Returns the canonical formal type of the given C++ method.
-static CanQual<FunctionProtoType> GetFormalType(const CXXMethodDecl *MD) {
- return MD->getType()->getCanonicalTypeUnqualified()
- .getAs<FunctionProtoType>();
-}
-
-/// Returns the "extra-canonicalized" return type, which discards
-/// qualifiers on the return type. Codegen doesn't care about them,
-/// and it makes ABI code a little easier to be able to assume that
-/// all parameter and return types are top-level unqualified.
-static CanQualType GetReturnType(QualType RetTy) {
- return RetTy->getCanonicalTypeUnqualified().getUnqualifiedType();
-}
-
-/// Arrange the argument and result information for a value of the given
-/// unprototyped freestanding function type.
-const CGFunctionInfo &
-CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
- // When translating an unprototyped function type, always use a
- // variadic type.
- return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(),
- /*instanceMethod=*/false,
- /*chainCall=*/false, None,
- FTNP->getExtInfo(), {}, RequiredArgs(0));
-}
-
-static void addExtParameterInfosForCall(
- llvm::SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
- const FunctionProtoType *proto,
- unsigned prefixArgs,
- unsigned totalArgs) {
- assert(proto->hasExtParameterInfos());
- assert(paramInfos.size() <= prefixArgs);
- assert(proto->getNumParams() + prefixArgs <= totalArgs);
-
- paramInfos.reserve(totalArgs);
-
- // Add default infos for any prefix args that don't already have infos.
- paramInfos.resize(prefixArgs);
-
- // Add infos for the prototype.
- for (const auto &ParamInfo : proto->getExtParameterInfos()) {
- paramInfos.push_back(ParamInfo);
- // pass_object_size params have no parameter info.
- if (ParamInfo.hasPassObjectSize())
- paramInfos.emplace_back();
- }
-
- assert(paramInfos.size() <= totalArgs &&
- "Did we forget to insert pass_object_size args?");
- // Add default infos for the variadic and/or suffix arguments.
- paramInfos.resize(totalArgs);
-}
-
-/// Adds the formal parameters in FPT to the given prefix. If any parameter in
-/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
-static void appendParameterTypes(const CodeGenTypes &CGT,
- SmallVectorImpl<CanQualType> &prefix,
- SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
- CanQual<FunctionProtoType> FPT) {
- // Fast path: don't touch param info if we don't need to.
- if (!FPT->hasExtParameterInfos()) {
- assert(paramInfos.empty() &&
- "We have paramInfos, but the prototype doesn't?");
- prefix.append(FPT->param_type_begin(), FPT->param_type_end());
- return;
- }
-
- unsigned PrefixSize = prefix.size();
- // In the vast majority of cases, we'll have precisely FPT->getNumParams()
- // parameters; the only thing that can change this is the presence of
- // pass_object_size. So, we preallocate for the common case.
- prefix.reserve(prefix.size() + FPT->getNumParams());
-
- auto ExtInfos = FPT->getExtParameterInfos();
- assert(ExtInfos.size() == FPT->getNumParams());
- for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) {
- prefix.push_back(FPT->getParamType(I));
- if (ExtInfos[I].hasPassObjectSize())
- prefix.push_back(CGT.getContext().getSizeType());
- }
-
- addExtParameterInfosForCall(paramInfos, FPT.getTypePtr(), PrefixSize,
- prefix.size());
-}
-
-/// Arrange the LLVM function layout for a value of the given function
-/// type, on top of any implicit parameters already stored.
-static const CGFunctionInfo &
-arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod,
- SmallVectorImpl<CanQualType> &prefix,
- CanQual<FunctionProtoType> FTP,
- const FunctionDecl *FD) {
- SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos;
- RequiredArgs Required =
- RequiredArgs::forPrototypePlus(FTP, prefix.size(), FD);
- // FIXME: Kill copy.
- appendParameterTypes(CGT, prefix, paramInfos, FTP);
- CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
-
- return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod,
- /*chainCall=*/false, prefix,
- FTP->getExtInfo(), paramInfos,
- Required);
-}
-
-/// Arrange the argument and result information for a value of the
-/// given freestanding function type.
-const CGFunctionInfo &
-CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP,
- const FunctionDecl *FD) {
- SmallVector<CanQualType, 16> argTypes;
- return ::arrangeLLVMFunctionInfo(*this, /*instanceMethod=*/false, argTypes,
- FTP, FD);
-}
-
-static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
- // Set the appropriate calling convention for the Function.
- if (D->hasAttr<StdCallAttr>())
- return CC_X86StdCall;
-
- if (D->hasAttr<FastCallAttr>())
- return CC_X86FastCall;
-
- if (D->hasAttr<RegCallAttr>())
- return CC_X86RegCall;
-
- if (D->hasAttr<ThisCallAttr>())
- return CC_X86ThisCall;
-
- if (D->hasAttr<VectorCallAttr>())
- return CC_X86VectorCall;
-
- if (D->hasAttr<PascalAttr>())
- return CC_X86Pascal;
-
- if (PcsAttr *PCS = D->getAttr<PcsAttr>())
- return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP);
-
- if (D->hasAttr<AArch64VectorPcsAttr>())
- return CC_AArch64VectorCall;
-
- if (D->hasAttr<IntelOclBiccAttr>())
- return CC_IntelOclBicc;
-
- if (D->hasAttr<MSABIAttr>())
- return IsWindows ? CC_C : CC_Win64;
-
- if (D->hasAttr<SysVABIAttr>())
- return IsWindows ? CC_X86_64SysV : CC_C;
-
- if (D->hasAttr<PreserveMostAttr>())
- return CC_PreserveMost;
-
- if (D->hasAttr<PreserveAllAttr>())
- return CC_PreserveAll;
-
- return CC_C;
-}
-
-/// Arrange the argument and result information for a call to an
-/// unknown C++ non-static member function of the given abstract type.
-/// (Zero value of RD means we don't have any meaningful "this" argument type,
-/// so fall back to a generic pointer type).
-/// The member function must be an ordinary function, i.e. not a
-/// constructor or destructor.
-const CGFunctionInfo &
-CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP,
- const CXXMethodDecl *MD) {
- SmallVector<CanQualType, 16> argTypes;
-
- // Add the 'this' pointer.
- if (RD)
- argTypes.push_back(GetThisType(Context, RD, MD));
- else
- argTypes.push_back(Context.VoidPtrTy);
-
- return ::arrangeLLVMFunctionInfo(
- *this, true, argTypes,
- FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>(), MD);
-}
-
-/// Set calling convention for CUDA/HIP kernel.
-static void setCUDAKernelCallingConvention(CanQualType &FTy, CodeGenModule &CGM,
- const FunctionDecl *FD) {
- if (FD->hasAttr<CUDAGlobalAttr>()) {
- const FunctionType *FT = FTy->getAs<FunctionType>();
- CGM.getTargetCodeGenInfo().setCUDAKernelCallingConvention(FT);
- FTy = FT->getCanonicalTypeUnqualified();
- }
-}
-
-/// Arrange the argument and result information for a declaration or
-/// definition of the given C++ non-static member function. The
-/// member function must be an ordinary function, i.e. not a
-/// constructor or destructor.
-const CGFunctionInfo &
-CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
- assert(!isa<CXXConstructorDecl>(MD) && "wrong method for constructors!");
- assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!");
-
- CanQualType FT = GetFormalType(MD).getAs<Type>();
- setCUDAKernelCallingConvention(FT, CGM, MD);
- auto prototype = FT.getAs<FunctionProtoType>();
-
- if (MD->isInstance()) {
- // The abstract case is perfectly fine.
- const CXXRecordDecl *ThisType = TheCXXABI.getThisArgumentTypeForMethod(MD);
- return arrangeCXXMethodType(ThisType, prototype.getTypePtr(), MD);
- }
-
- return arrangeFreeFunctionType(prototype, MD);
-}
-
-bool CodeGenTypes::inheritingCtorHasParams(
- const InheritedConstructor &Inherited, CXXCtorType Type) {
- // Parameters are unnecessary if we're constructing a base class subobject
- // and the inherited constructor lives in a virtual base.
- return Type == Ctor_Complete ||
- !Inherited.getShadowDecl()->constructsVirtualBase() ||
- !Target.getCXXABI().hasConstructorVariants();
- }
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
- StructorType Type) {
-
- SmallVector<CanQualType, 16> argTypes;
- SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos;
- argTypes.push_back(GetThisType(Context, MD->getParent(), MD));
-
- bool PassParams = true;
-
- GlobalDecl GD;
- if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
- GD = GlobalDecl(CD, toCXXCtorType(Type));
-
- // A base class inheriting constructor doesn't get forwarded arguments
- // needed to construct a virtual base (or base class thereof).
- if (auto Inherited = CD->getInheritedConstructor())
- PassParams = inheritingCtorHasParams(Inherited, toCXXCtorType(Type));
- } else {
- auto *DD = dyn_cast<CXXDestructorDecl>(MD);
- GD = GlobalDecl(DD, toCXXDtorType(Type));
- }
-
- CanQual<FunctionProtoType> FTP = GetFormalType(MD);
-
- // Add the formal parameters.
- if (PassParams)
- appendParameterTypes(*this, argTypes, paramInfos, FTP);
-
- CGCXXABI::AddedStructorArgs AddedArgs =
- TheCXXABI.buildStructorSignature(MD, Type, argTypes);
- if (!paramInfos.empty()) {
- // Note: prefix implies after the first param.
- if (AddedArgs.Prefix)
- paramInfos.insert(paramInfos.begin() + 1, AddedArgs.Prefix,
- FunctionProtoType::ExtParameterInfo{});
- if (AddedArgs.Suffix)
- paramInfos.append(AddedArgs.Suffix,
- FunctionProtoType::ExtParameterInfo{});
- }
-
- RequiredArgs required =
- (PassParams && MD->isVariadic() ? RequiredArgs(argTypes.size())
- : RequiredArgs::All);
-
- FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- CanQualType resultType = TheCXXABI.HasThisReturn(GD)
- ? argTypes.front()
- : TheCXXABI.hasMostDerivedReturn(GD)
- ? CGM.getContext().VoidPtrTy
- : Context.VoidTy;
- return arrangeLLVMFunctionInfo(resultType, /*instanceMethod=*/true,
- /*chainCall=*/false, argTypes, extInfo,
- paramInfos, required);
-}
-
-static SmallVector<CanQualType, 16>
-getArgTypesForCall(ASTContext &ctx, const CallArgList &args) {
- SmallVector<CanQualType, 16> argTypes;
- for (auto &arg : args)
- argTypes.push_back(ctx.getCanonicalParamType(arg.Ty));
- return argTypes;
-}
-
-static SmallVector<CanQualType, 16>
-getArgTypesForDeclaration(ASTContext &ctx, const FunctionArgList &args) {
- SmallVector<CanQualType, 16> argTypes;
- for (auto &arg : args)
- argTypes.push_back(ctx.getCanonicalParamType(arg->getType()));
- return argTypes;
-}
-
-static llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16>
-getExtParameterInfosForCall(const FunctionProtoType *proto,
- unsigned prefixArgs, unsigned totalArgs) {
- llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16> result;
- if (proto->hasExtParameterInfos()) {
- addExtParameterInfosForCall(result, proto, prefixArgs, totalArgs);
- }
- return result;
-}
-
-/// Arrange a call to a C++ method, passing the given arguments.
-///
-/// ExtraPrefixArgs is the number of ABI-specific args passed after the `this`
-/// parameter.
-/// ExtraSuffixArgs is the number of ABI-specific args passed at the end of
-/// args.
-/// PassProtoArgs indicates whether `args` has args for the parameters in the
-/// given CXXConstructorDecl.
-const CGFunctionInfo &
-CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
- const CXXConstructorDecl *D,
- CXXCtorType CtorKind,
- unsigned ExtraPrefixArgs,
- unsigned ExtraSuffixArgs,
- bool PassProtoArgs) {
- // FIXME: Kill copy.
- SmallVector<CanQualType, 16> ArgTypes;
- for (const auto &Arg : args)
- ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
-
- // +1 for implicit this, which should always be args[0].
- unsigned TotalPrefixArgs = 1 + ExtraPrefixArgs;
-
- CanQual<FunctionProtoType> FPT = GetFormalType(D);
- RequiredArgs Required =
- RequiredArgs::forPrototypePlus(FPT, TotalPrefixArgs + ExtraSuffixArgs, D);
- GlobalDecl GD(D, CtorKind);
- CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
- ? ArgTypes.front()
- : TheCXXABI.hasMostDerivedReturn(GD)
- ? CGM.getContext().VoidPtrTy
- : Context.VoidTy;
-
- FunctionType::ExtInfo Info = FPT->getExtInfo();
- llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16> ParamInfos;
- // If the prototype args are elided, we should only have ABI-specific args,
- // which never have param info.
- if (PassProtoArgs && FPT->hasExtParameterInfos()) {
- // ABI-specific suffix arguments are treated the same as variadic arguments.
- addExtParameterInfosForCall(ParamInfos, FPT.getTypePtr(), TotalPrefixArgs,
- ArgTypes.size());
- }
- return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true,
- /*chainCall=*/false, ArgTypes, Info,
- ParamInfos, Required);
-}
-
-/// Arrange the argument and result information for the declaration or
-/// definition of the given function.
-const CGFunctionInfo &
-CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
- if (MD->isInstance())
- return arrangeCXXMethodDeclaration(MD);
-
- CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified();
-
- assert(isa<FunctionType>(FTy));
- setCUDAKernelCallingConvention(FTy, CGM, FD);
-
- // When declaring a function without a prototype, always use a
- // non-variadic type.
- if (CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>()) {
- return arrangeLLVMFunctionInfo(
- noProto->getReturnType(), /*instanceMethod=*/false,
- /*chainCall=*/false, None, noProto->getExtInfo(), {},RequiredArgs::All);
- }
-
- return arrangeFreeFunctionType(FTy.castAs<FunctionProtoType>(), FD);
-}
-
-/// Arrange the argument and result information for the declaration or
-/// definition of an Objective-C method.
-const CGFunctionInfo &
-CodeGenTypes::arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD) {
- // It happens that this is the same as a call with no optional
- // arguments, except also using the formal 'self' type.
- return arrangeObjCMessageSendSignature(MD, MD->getSelfDecl()->getType());
-}
-
-/// Arrange the argument and result information for the function type
-/// through which to perform a send to the given Objective-C method,
-/// using the given receiver type. The receiver type is not always
-/// the 'self' type of the method or even an Objective-C pointer type.
-/// This is *not* the right method for actually performing such a
-/// message send, due to the possibility of optional arguments.
-const CGFunctionInfo &
-CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
- QualType receiverType) {
- SmallVector<CanQualType, 16> argTys;
- SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(2);
- argTys.push_back(Context.getCanonicalParamType(receiverType));
- argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
- // FIXME: Kill copy?
- for (const auto *I : MD->parameters()) {
- argTys.push_back(Context.getCanonicalParamType(I->getType()));
- auto extParamInfo = FunctionProtoType::ExtParameterInfo().withIsNoEscape(
- I->hasAttr<NoEscapeAttr>());
- extParamInfos.push_back(extParamInfo);
- }
-
- FunctionType::ExtInfo einfo;
- bool IsWindows = getContext().getTargetInfo().getTriple().isOSWindows();
- einfo = einfo.withCallingConv(getCallingConventionForDecl(MD, IsWindows));
-
- if (getContext().getLangOpts().ObjCAutoRefCount &&
- MD->hasAttr<NSReturnsRetainedAttr>())
- einfo = einfo.withProducesResult(true);
-
- RequiredArgs required =
- (MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All);
-
- return arrangeLLVMFunctionInfo(
- GetReturnType(MD->getReturnType()), /*instanceMethod=*/false,
- /*chainCall=*/false, argTys, einfo, extParamInfos, required);
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeUnprototypedObjCMessageSend(QualType returnType,
- const CallArgList &args) {
- auto argTypes = getArgTypesForCall(Context, args);
- FunctionType::ExtInfo einfo;
-
- return arrangeLLVMFunctionInfo(
- GetReturnType(returnType), /*instanceMethod=*/false,
- /*chainCall=*/false, argTypes, einfo, {}, RequiredArgs::All);
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
- // FIXME: Do we need to handle ObjCMethodDecl?
- const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
- return arrangeCXXStructorDeclaration(CD, getFromCtorType(GD.getCtorType()));
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
- return arrangeCXXStructorDeclaration(DD, getFromDtorType(GD.getDtorType()));
-
- return arrangeFunctionDeclaration(FD);
-}
-
-/// Arrange a thunk that takes 'this' as the first parameter followed by
-/// varargs. Return a void pointer, regardless of the actual return type.
-/// The body of the thunk will end in a musttail call to a function of the
-/// correct type, and the caller will bitcast the function to the correct
-/// prototype.
-const CGFunctionInfo &
-CodeGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD) {
- assert(MD->isVirtual() && "only methods have thunks");
- CanQual<FunctionProtoType> FTP = GetFormalType(MD);
- CanQualType ArgTys[] = { GetThisType(Context, MD->getParent(), MD) };
- return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false,
- /*chainCall=*/false, ArgTys,
- FTP->getExtInfo(), {}, RequiredArgs(1));
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeMSCtorClosure(const CXXConstructorDecl *CD,
- CXXCtorType CT) {
- assert(CT == Ctor_CopyingClosure || CT == Ctor_DefaultClosure);
-
- CanQual<FunctionProtoType> FTP = GetFormalType(CD);
- SmallVector<CanQualType, 2> ArgTys;
- const CXXRecordDecl *RD = CD->getParent();
- ArgTys.push_back(GetThisType(Context, RD, CD));
- if (CT == Ctor_CopyingClosure)
- ArgTys.push_back(*FTP->param_type_begin());
- if (RD->getNumVBases() > 0)
- ArgTys.push_back(Context.IntTy);
- CallingConv CC = Context.getDefaultCallingConvention(
- /*IsVariadic=*/false, /*IsCXXMethod=*/true);
- return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/true,
- /*chainCall=*/false, ArgTys,
- FunctionType::ExtInfo(CC), {},
- RequiredArgs::All);
-}
-
-/// Arrange a call as unto a free function, except possibly with an
-/// additional number of formal parameters considered required.
-static const CGFunctionInfo &
-arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
- CodeGenModule &CGM,
- const CallArgList &args,
- const FunctionType *fnType,
- unsigned numExtraRequiredArgs,
- bool chainCall) {
- assert(args.size() >= numExtraRequiredArgs);
-
- llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos;
-
- // In most cases, there are no optional arguments.
- RequiredArgs required = RequiredArgs::All;
-
- // If we have a variadic prototype, the required arguments are the
- // extra prefix plus the arguments in the prototype.
- if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
- if (proto->isVariadic())
- required = RequiredArgs(proto->getNumParams() + numExtraRequiredArgs);
-
- if (proto->hasExtParameterInfos())
- addExtParameterInfosForCall(paramInfos, proto, numExtraRequiredArgs,
- args.size());
-
- // If we don't have a prototype at all, but we're supposed to
- // explicitly use the variadic convention for unprototyped calls,
- // treat all of the arguments as required but preserve the nominal
- // possibility of variadics.
- } else if (CGM.getTargetCodeGenInfo()
- .isNoProtoCallVariadic(args,
- cast<FunctionNoProtoType>(fnType))) {
- required = RequiredArgs(args.size());
- }
-
- // FIXME: Kill copy.
- SmallVector<CanQualType, 16> argTypes;
- for (const auto &arg : args)
- argTypes.push_back(CGT.getContext().getCanonicalParamType(arg.Ty));
- return CGT.arrangeLLVMFunctionInfo(GetReturnType(fnType->getReturnType()),
- /*instanceMethod=*/false, chainCall,
- argTypes, fnType->getExtInfo(), paramInfos,
- required);
-}
-
-/// Figure out the rules for calling a function with the given formal
-/// type using the given arguments. The arguments are necessary
-/// because the function might be unprototyped, in which case it's
-/// target-dependent in crazy ways.
-const CGFunctionInfo &
-CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
- const FunctionType *fnType,
- bool chainCall) {
- return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType,
- chainCall ? 1 : 0, chainCall);
-}
-
-/// A block function is essentially a free function with an
-/// extra implicit argument.
-const CGFunctionInfo &
-CodeGenTypes::arrangeBlockFunctionCall(const CallArgList &args,
- const FunctionType *fnType) {
- return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1,
- /*chainCall=*/false);
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeBlockFunctionDeclaration(const FunctionProtoType *proto,
- const FunctionArgList &params) {
- auto paramInfos = getExtParameterInfosForCall(proto, 1, params.size());
- auto argTypes = getArgTypesForDeclaration(Context, params);
-
- return arrangeLLVMFunctionInfo(
- GetReturnType(proto->getReturnType()),
- /*instanceMethod*/ false, /*chainCall*/ false, argTypes,
- proto->getExtInfo(), paramInfos,
- RequiredArgs::forPrototypePlus(proto, 1, nullptr));
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeBuiltinFunctionCall(QualType resultType,
- const CallArgList &args) {
- // FIXME: Kill copy.
- SmallVector<CanQualType, 16> argTypes;
- for (const auto &Arg : args)
- argTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
- return arrangeLLVMFunctionInfo(
- GetReturnType(resultType), /*instanceMethod=*/false,
- /*chainCall=*/false, argTypes, FunctionType::ExtInfo(),
- /*paramInfos=*/ {}, RequiredArgs::All);
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeBuiltinFunctionDeclaration(QualType resultType,
- const FunctionArgList &args) {
- auto argTypes = getArgTypesForDeclaration(Context, args);
-
- return arrangeLLVMFunctionInfo(
- GetReturnType(resultType), /*instanceMethod=*/false, /*chainCall=*/false,
- argTypes, FunctionType::ExtInfo(), {}, RequiredArgs::All);
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeBuiltinFunctionDeclaration(CanQualType resultType,
- ArrayRef<CanQualType> argTypes) {
- return arrangeLLVMFunctionInfo(
- resultType, /*instanceMethod=*/false, /*chainCall=*/false,
- argTypes, FunctionType::ExtInfo(), {}, RequiredArgs::All);
-}
-
-/// Arrange a call to a C++ method, passing the given arguments.
-///
-/// numPrefixArgs is the number of ABI-specific prefix arguments we have. It
-/// does not count `this`.
-const CGFunctionInfo &
-CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
- const FunctionProtoType *proto,
- RequiredArgs required,
- unsigned numPrefixArgs) {
- assert(numPrefixArgs + 1 <= args.size() &&
- "Emitting a call with less args than the required prefix?");
- // Add one to account for `this`. It's a bit awkward here, but we don't count
- // `this` in similar places elsewhere.
- auto paramInfos =
- getExtParameterInfosForCall(proto, numPrefixArgs + 1, args.size());
-
- // FIXME: Kill copy.
- auto argTypes = getArgTypesForCall(Context, args);
-
- FunctionType::ExtInfo info = proto->getExtInfo();
- return arrangeLLVMFunctionInfo(
- GetReturnType(proto->getReturnType()), /*instanceMethod=*/true,
- /*chainCall=*/false, argTypes, info, paramInfos, required);
-}
-
-const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
- return arrangeLLVMFunctionInfo(
- getContext().VoidTy, /*instanceMethod=*/false, /*chainCall=*/false,
- None, FunctionType::ExtInfo(), {}, RequiredArgs::All);
-}
-
-const CGFunctionInfo &
-CodeGenTypes::arrangeCall(const CGFunctionInfo &signature,
- const CallArgList &args) {
- assert(signature.arg_size() <= args.size());
- if (signature.arg_size() == args.size())
- return signature;
-
- SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos;
- auto sigParamInfos = signature.getExtParameterInfos();
- if (!sigParamInfos.empty()) {
- paramInfos.append(sigParamInfos.begin(), sigParamInfos.end());
- paramInfos.resize(args.size());
- }
-
- auto argTypes = getArgTypesForCall(Context, args);
-
- assert(signature.getRequiredArgs().allowsOptionalArgs());
- return arrangeLLVMFunctionInfo(signature.getReturnType(),
- signature.isInstanceMethod(),
- signature.isChainCall(),
- argTypes,
- signature.getExtInfo(),
- paramInfos,
- signature.getRequiredArgs());
-}
-
-namespace clang {
-namespace CodeGen {
-void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
-}
-}
-
-/// Arrange the argument and result information for an abstract value
-/// of a given function type. This is the method which all of the
-/// above functions ultimately defer to.
-const CGFunctionInfo &
-CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
- bool instanceMethod,
- bool chainCall,
- ArrayRef<CanQualType> argTypes,
- FunctionType::ExtInfo info,
- ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
- RequiredArgs required) {
- assert(llvm::all_of(argTypes,
- [](CanQualType T) { return T.isCanonicalAsParam(); }));
-
- // Lookup or create unique function info.
- llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, instanceMethod, chainCall, info, paramInfos,
- required, resultType, argTypes);
-
- void *insertPos = nullptr;
- CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
- if (FI)
- return *FI;
-
- unsigned CC = ClangCallConvToLLVMCallConv(info.getCC());
-
- // Construct the function info. We co-allocate the ArgInfos.
- FI = CGFunctionInfo::create(CC, instanceMethod, chainCall, info,
- paramInfos, resultType, argTypes, required);
- FunctionInfos.InsertNode(FI, insertPos);
-
- bool inserted = FunctionsBeingProcessed.insert(FI).second;
- (void)inserted;
- assert(inserted && "Recursively being processed?");
-
- // Compute ABI information.
- if (CC == llvm::CallingConv::SPIR_KERNEL) {
- // Force target independent argument handling for the host visible
- // kernel functions.
- computeSPIRKernelABIInfo(CGM, *FI);
- } else if (info.getCC() == CC_Swift) {
- swiftcall::computeABIInfo(CGM, *FI);
- } else {
- getABIInfo().computeInfo(*FI);
- }
-
- // Loop over all of the computed argument and return value info. If any of
- // them are direct or extend without a specified coerce type, specify the
- // default now.
- ABIArgInfo &retInfo = FI->getReturnInfo();
- if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
- retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
-
- for (auto &I : FI->arguments())
- if (I.info.canHaveCoerceToType() && I.info.getCoerceToType() == nullptr)
- I.info.setCoerceToType(ConvertType(I.type));
-
- bool erased = FunctionsBeingProcessed.erase(FI); (void)erased;
- assert(erased && "Not in set?");
-
- return *FI;
-}
-
-CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
- bool instanceMethod,
- bool chainCall,
- const FunctionType::ExtInfo &info,
- ArrayRef<ExtParameterInfo> paramInfos,
- CanQualType resultType,
- ArrayRef<CanQualType> argTypes,
- RequiredArgs required) {
- assert(paramInfos.empty() || paramInfos.size() == argTypes.size());
-
- void *buffer =
- operator new(totalSizeToAlloc<ArgInfo, ExtParameterInfo>(
- argTypes.size() + 1, paramInfos.size()));
-
- CGFunctionInfo *FI = new(buffer) CGFunctionInfo();
- FI->CallingConvention = llvmCC;
- FI->EffectiveCallingConvention = llvmCC;
- FI->ASTCallingConvention = info.getCC();
- FI->InstanceMethod = instanceMethod;
- FI->ChainCall = chainCall;
- FI->NoReturn = info.getNoReturn();
- FI->ReturnsRetained = info.getProducesResult();
- FI->NoCallerSavedRegs = info.getNoCallerSavedRegs();
- FI->NoCfCheck = info.getNoCfCheck();
- FI->Required = required;
- FI->HasRegParm = info.getHasRegParm();
- FI->RegParm = info.getRegParm();
- FI->ArgStruct = nullptr;
- FI->ArgStructAlign = 0;
- FI->NumArgs = argTypes.size();
- FI->HasExtParameterInfos = !paramInfos.empty();
- FI->getArgsBuffer()[0].type = resultType;
- for (unsigned i = 0, e = argTypes.size(); i != e; ++i)
- FI->getArgsBuffer()[i + 1].type = argTypes[i];
- for (unsigned i = 0, e = paramInfos.size(); i != e; ++i)
- FI->getExtParameterInfosBuffer()[i] = paramInfos[i];
- return FI;
-}
-
-/***/
-
-namespace {
-// ABIArgInfo::Expand implementation.
-
-// Specifies the way QualType passed as ABIArgInfo::Expand is expanded.
-struct TypeExpansion {
- enum TypeExpansionKind {
- // Elements of constant arrays are expanded recursively.
- TEK_ConstantArray,
- // Record fields are expanded recursively (but if record is a union, only
- // the field with the largest size is expanded).
- TEK_Record,
- // For complex types, real and imaginary parts are expanded recursively.
- TEK_Complex,
- // All other types are not expandable.
- TEK_None
- };
-
- const TypeExpansionKind Kind;
-
- TypeExpansion(TypeExpansionKind K) : Kind(K) {}
- virtual ~TypeExpansion() {}
-};
-
-struct ConstantArrayExpansion : TypeExpansion {
- QualType EltTy;
- uint64_t NumElts;
-
- ConstantArrayExpansion(QualType EltTy, uint64_t NumElts)
- : TypeExpansion(TEK_ConstantArray), EltTy(EltTy), NumElts(NumElts) {}
- static bool classof(const TypeExpansion *TE) {
- return TE->Kind == TEK_ConstantArray;
- }
-};
-
-struct RecordExpansion : TypeExpansion {
- SmallVector<const CXXBaseSpecifier *, 1> Bases;
-
- SmallVector<const FieldDecl *, 1> Fields;
-
- RecordExpansion(SmallVector<const CXXBaseSpecifier *, 1> &&Bases,
- SmallVector<const FieldDecl *, 1> &&Fields)
- : TypeExpansion(TEK_Record), Bases(std::move(Bases)),
- Fields(std::move(Fields)) {}
- static bool classof(const TypeExpansion *TE) {
- return TE->Kind == TEK_Record;
- }
-};
-
-struct ComplexExpansion : TypeExpansion {
- QualType EltTy;
-
- ComplexExpansion(QualType EltTy) : TypeExpansion(TEK_Complex), EltTy(EltTy) {}
- static bool classof(const TypeExpansion *TE) {
- return TE->Kind == TEK_Complex;
- }
-};
-
-struct NoExpansion : TypeExpansion {
- NoExpansion() : TypeExpansion(TEK_None) {}
- static bool classof(const TypeExpansion *TE) {
- return TE->Kind == TEK_None;
- }
-};
-} // namespace
-
-static std::unique_ptr<TypeExpansion>
-getTypeExpansion(QualType Ty, const ASTContext &Context) {
- if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
- return llvm::make_unique<ConstantArrayExpansion>(
- AT->getElementType(), AT->getSize().getZExtValue());
- }
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- SmallVector<const CXXBaseSpecifier *, 1> Bases;
- SmallVector<const FieldDecl *, 1> Fields;
- const RecordDecl *RD = RT->getDecl();
- assert(!RD->hasFlexibleArrayMember() &&
- "Cannot expand structure with flexible array.");
- if (RD->isUnion()) {
- // Unions can be here only in degenerative cases - all the fields are same
- // after flattening. Thus we have to use the "largest" field.
- const FieldDecl *LargestFD = nullptr;
- CharUnits UnionSize = CharUnits::Zero();
-
- for (const auto *FD : RD->fields()) {
- if (FD->isZeroLengthBitField(Context))
- continue;
- assert(!FD->isBitField() &&
- "Cannot expand structure with bit-field members.");
- CharUnits FieldSize = Context.getTypeSizeInChars(FD->getType());
- if (UnionSize < FieldSize) {
- UnionSize = FieldSize;
- LargestFD = FD;
- }
- }
- if (LargestFD)
- Fields.push_back(LargestFD);
- } else {
- if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- assert(!CXXRD->isDynamicClass() &&
- "cannot expand vtable pointers in dynamic classes");
- for (const CXXBaseSpecifier &BS : CXXRD->bases())
- Bases.push_back(&BS);
- }
-
- for (const auto *FD : RD->fields()) {
- if (FD->isZeroLengthBitField(Context))
- continue;
- assert(!FD->isBitField() &&
- "Cannot expand structure with bit-field members.");
- Fields.push_back(FD);
- }
- }
- return llvm::make_unique<RecordExpansion>(std::move(Bases),
- std::move(Fields));
- }
- if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
- return llvm::make_unique<ComplexExpansion>(CT->getElementType());
- }
- return llvm::make_unique<NoExpansion>();
-}
-
-static int getExpansionSize(QualType Ty, const ASTContext &Context) {
- auto Exp = getTypeExpansion(Ty, Context);
- if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
- return CAExp->NumElts * getExpansionSize(CAExp->EltTy, Context);
- }
- if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
- int Res = 0;
- for (auto BS : RExp->Bases)
- Res += getExpansionSize(BS->getType(), Context);
- for (auto FD : RExp->Fields)
- Res += getExpansionSize(FD->getType(), Context);
- return Res;
- }
- if (isa<ComplexExpansion>(Exp.get()))
- return 2;
- assert(isa<NoExpansion>(Exp.get()));
- return 1;
-}
-
-void
-CodeGenTypes::getExpandedTypes(QualType Ty,
- SmallVectorImpl<llvm::Type *>::iterator &TI) {
- auto Exp = getTypeExpansion(Ty, Context);
- if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
- for (int i = 0, n = CAExp->NumElts; i < n; i++) {
- getExpandedTypes(CAExp->EltTy, TI);
- }
- } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
- for (auto BS : RExp->Bases)
- getExpandedTypes(BS->getType(), TI);
- for (auto FD : RExp->Fields)
- getExpandedTypes(FD->getType(), TI);
- } else if (auto CExp = dyn_cast<ComplexExpansion>(Exp.get())) {
- llvm::Type *EltTy = ConvertType(CExp->EltTy);
- *TI++ = EltTy;
- *TI++ = EltTy;
- } else {
- assert(isa<NoExpansion>(Exp.get()));
- *TI++ = ConvertType(Ty);
- }
-}
-
-static void forConstantArrayExpansion(CodeGenFunction &CGF,
- ConstantArrayExpansion *CAE,
- Address BaseAddr,
- llvm::function_ref<void(Address)> Fn) {
- CharUnits EltSize = CGF.getContext().getTypeSizeInChars(CAE->EltTy);
- CharUnits EltAlign =
- BaseAddr.getAlignment().alignmentOfArrayElement(EltSize);
-
- for (int i = 0, n = CAE->NumElts; i < n; i++) {
- llvm::Value *EltAddr =
- CGF.Builder.CreateConstGEP2_32(nullptr, BaseAddr.getPointer(), 0, i);
- Fn(Address(EltAddr, EltAlign));
- }
-}
-
-void CodeGenFunction::ExpandTypeFromArgs(
- QualType Ty, LValue LV, SmallVectorImpl<llvm::Value *>::iterator &AI) {
- assert(LV.isSimple() &&
- "Unexpected non-simple lvalue during struct expansion.");
-
- auto Exp = getTypeExpansion(Ty, getContext());
- if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
- forConstantArrayExpansion(*this, CAExp, LV.getAddress(),
- [&](Address EltAddr) {
- LValue LV = MakeAddrLValue(EltAddr, CAExp->EltTy);
- ExpandTypeFromArgs(CAExp->EltTy, LV, AI);
- });
- } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
- Address This = LV.getAddress();
- for (const CXXBaseSpecifier *BS : RExp->Bases) {
- // Perform a single step derived-to-base conversion.
- Address Base =
- GetAddressOfBaseClass(This, Ty->getAsCXXRecordDecl(), &BS, &BS + 1,
- /*NullCheckValue=*/false, SourceLocation());
- LValue SubLV = MakeAddrLValue(Base, BS->getType());
-
- // Recurse onto bases.
- ExpandTypeFromArgs(BS->getType(), SubLV, AI);
- }
- for (auto FD : RExp->Fields) {
- // FIXME: What are the right qualifiers here?
- LValue SubLV = EmitLValueForFieldInitialization(LV, FD);
- ExpandTypeFromArgs(FD->getType(), SubLV, AI);
- }
- } else if (isa<ComplexExpansion>(Exp.get())) {
- auto realValue = *AI++;
- auto imagValue = *AI++;
- EmitStoreOfComplex(ComplexPairTy(realValue, imagValue), LV, /*init*/ true);
- } else {
- assert(isa<NoExpansion>(Exp.get()));
- EmitStoreThroughLValue(RValue::get(*AI++), LV);
- }
-}
-
-void CodeGenFunction::ExpandTypeToArgs(
- QualType Ty, CallArg Arg, llvm::FunctionType *IRFuncTy,
- SmallVectorImpl<llvm::Value *> &IRCallArgs, unsigned &IRCallArgPos) {
- auto Exp = getTypeExpansion(Ty, getContext());
- if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
- Address Addr = Arg.hasLValue() ? Arg.getKnownLValue().getAddress()
- : Arg.getKnownRValue().getAggregateAddress();
- forConstantArrayExpansion(
- *this, CAExp, Addr, [&](Address EltAddr) {
- CallArg EltArg = CallArg(
- convertTempToRValue(EltAddr, CAExp->EltTy, SourceLocation()),
- CAExp->EltTy);
- ExpandTypeToArgs(CAExp->EltTy, EltArg, IRFuncTy, IRCallArgs,
- IRCallArgPos);
- });
- } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
- Address This = Arg.hasLValue() ? Arg.getKnownLValue().getAddress()
- : Arg.getKnownRValue().getAggregateAddress();
- for (const CXXBaseSpecifier *BS : RExp->Bases) {
- // Perform a single step derived-to-base conversion.
- Address Base =
- GetAddressOfBaseClass(This, Ty->getAsCXXRecordDecl(), &BS, &BS + 1,
- /*NullCheckValue=*/false, SourceLocation());
- CallArg BaseArg = CallArg(RValue::getAggregate(Base), BS->getType());
-
- // Recurse onto bases.
- ExpandTypeToArgs(BS->getType(), BaseArg, IRFuncTy, IRCallArgs,
- IRCallArgPos);
- }
-
- LValue LV = MakeAddrLValue(This, Ty);
- for (auto FD : RExp->Fields) {
- CallArg FldArg =
- CallArg(EmitRValueForField(LV, FD, SourceLocation()), FD->getType());
- ExpandTypeToArgs(FD->getType(), FldArg, IRFuncTy, IRCallArgs,
- IRCallArgPos);
- }
- } else if (isa<ComplexExpansion>(Exp.get())) {
- ComplexPairTy CV = Arg.getKnownRValue().getComplexVal();
- IRCallArgs[IRCallArgPos++] = CV.first;
- IRCallArgs[IRCallArgPos++] = CV.second;
- } else {
- assert(isa<NoExpansion>(Exp.get()));
- auto RV = Arg.getKnownRValue();
- assert(RV.isScalar() &&
- "Unexpected non-scalar rvalue during struct expansion.");
-
- // Insert a bitcast as needed.
- llvm::Value *V = RV.getScalarVal();
- if (IRCallArgPos < IRFuncTy->getNumParams() &&
- V->getType() != IRFuncTy->getParamType(IRCallArgPos))
- V = Builder.CreateBitCast(V, IRFuncTy->getParamType(IRCallArgPos));
-
- IRCallArgs[IRCallArgPos++] = V;
- }
-}
-
-/// Create a temporary allocation for the purposes of coercion.
-static Address CreateTempAllocaForCoercion(CodeGenFunction &CGF, llvm::Type *Ty,
- CharUnits MinAlign) {
- // Don't use an alignment that's worse than what LLVM would prefer.
- auto PrefAlign = CGF.CGM.getDataLayout().getPrefTypeAlignment(Ty);
- CharUnits Align = std::max(MinAlign, CharUnits::fromQuantity(PrefAlign));
-
- return CGF.CreateTempAlloca(Ty, Align);
-}
-
-/// EnterStructPointerForCoercedAccess - Given a struct pointer that we are
-/// accessing some number of bytes out of it, try to gep into the struct to get
-/// at its inner goodness. Dive as deep as possible without entering an element
-/// with an in-memory size smaller than DstSize.
-static Address
-EnterStructPointerForCoercedAccess(Address SrcPtr,
- llvm::StructType *SrcSTy,
- uint64_t DstSize, CodeGenFunction &CGF) {
- // We can't dive into a zero-element struct.
- if (SrcSTy->getNumElements() == 0) return SrcPtr;
-
- llvm::Type *FirstElt = SrcSTy->getElementType(0);
-
- // If the first elt is at least as large as what we're looking for, or if the
- // first element is the same size as the whole struct, we can enter it. The
- // comparison must be made on the store size and not the alloca size. Using
- // the alloca size may overstate the size of the load.
- uint64_t FirstEltSize =
- CGF.CGM.getDataLayout().getTypeStoreSize(FirstElt);
- if (FirstEltSize < DstSize &&
- FirstEltSize < CGF.CGM.getDataLayout().getTypeStoreSize(SrcSTy))
- return SrcPtr;
-
- // GEP into the first element.
- SrcPtr = CGF.Builder.CreateStructGEP(SrcPtr, 0, CharUnits(), "coerce.dive");
-
- // If the first element is a struct, recurse.
- llvm::Type *SrcTy = SrcPtr.getElementType();
- if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy))
- return EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF);
-
- return SrcPtr;
-}
-
-/// CoerceIntOrPtrToIntOrPtr - Convert a value Val to the specific Ty where both
-/// are either integers or pointers. This does a truncation of the value if it
-/// is too large or a zero extension if it is too small.
-///
-/// This behaves as if the value were coerced through memory, so on big-endian
-/// targets the high bits are preserved in a truncation, while little-endian
-/// targets preserve the low bits.
-static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
- llvm::Type *Ty,
- CodeGenFunction &CGF) {
- if (Val->getType() == Ty)
- return Val;
-
- if (isa<llvm::PointerType>(Val->getType())) {
- // If this is Pointer->Pointer avoid conversion to and from int.
- if (isa<llvm::PointerType>(Ty))
- return CGF.Builder.CreateBitCast(Val, Ty, "coerce.val");
-
- // Convert the pointer to an integer so we can play with its width.
- Val = CGF.Builder.CreatePtrToInt(Val, CGF.IntPtrTy, "coerce.val.pi");
- }
-
- llvm::Type *DestIntTy = Ty;
- if (isa<llvm::PointerType>(DestIntTy))
- DestIntTy = CGF.IntPtrTy;
-
- if (Val->getType() != DestIntTy) {
- const llvm::DataLayout &DL = CGF.CGM.getDataLayout();
- if (DL.isBigEndian()) {
- // Preserve the high bits on big-endian targets.
- // That is what memory coercion does.
- uint64_t SrcSize = DL.getTypeSizeInBits(Val->getType());
- uint64_t DstSize = DL.getTypeSizeInBits(DestIntTy);
-
- if (SrcSize > DstSize) {
- Val = CGF.Builder.CreateLShr(Val, SrcSize - DstSize, "coerce.highbits");
- Val = CGF.Builder.CreateTrunc(Val, DestIntTy, "coerce.val.ii");
- } else {
- Val = CGF.Builder.CreateZExt(Val, DestIntTy, "coerce.val.ii");
- Val = CGF.Builder.CreateShl(Val, DstSize - SrcSize, "coerce.highbits");
- }
- } else {
- // Little-endian targets preserve the low bits. No shifts required.
- Val = CGF.Builder.CreateIntCast(Val, DestIntTy, false, "coerce.val.ii");
- }
- }
-
- if (isa<llvm::PointerType>(Ty))
- Val = CGF.Builder.CreateIntToPtr(Val, Ty, "coerce.val.ip");
- return Val;
-}
-
-
-
-/// CreateCoercedLoad - Create a load from \arg SrcPtr interpreted as
-/// a pointer to an object of type \arg Ty, known to be aligned to
-/// \arg SrcAlign bytes.
-///
-/// This safely handles the case when the src type is smaller than the
-/// destination type; in this situation the values of bits which not
-/// present in the src are undefined.
-static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
- CodeGenFunction &CGF) {
- llvm::Type *SrcTy = Src.getElementType();
-
- // If SrcTy and Ty are the same, just do a load.
- if (SrcTy == Ty)
- return CGF.Builder.CreateLoad(Src);
-
- uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty);
-
- if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
- Src = EnterStructPointerForCoercedAccess(Src, SrcSTy, DstSize, CGF);
- SrcTy = Src.getType()->getElementType();
- }
-
- uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
-
- // If the source and destination are integer or pointer types, just do an
- // extension or truncation to the desired type.
- if ((isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) &&
- (isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy))) {
- llvm::Value *Load = CGF.Builder.CreateLoad(Src);
- return CoerceIntOrPtrToIntOrPtr(Load, Ty, CGF);
- }
-
- // If load is legal, just bitcast the src pointer.
- if (SrcSize >= DstSize) {
- // Generally SrcSize is never greater than DstSize, since this means we are
- // losing bits. However, this can happen in cases where the structure has
- // additional padding, for example due to a user specified alignment.
- //
- // FIXME: Assert that we aren't truncating non-padding bits when have access
- // to that information.
- Src = CGF.Builder.CreateBitCast(Src,
- Ty->getPointerTo(Src.getAddressSpace()));
- return CGF.Builder.CreateLoad(Src);
- }
-
- // Otherwise do coercion through memory. This is stupid, but simple.
- Address Tmp = CreateTempAllocaForCoercion(CGF, Ty, Src.getAlignment());
- Address Casted = CGF.Builder.CreateElementBitCast(Tmp,CGF.Int8Ty);
- Address SrcCasted = CGF.Builder.CreateElementBitCast(Src,CGF.Int8Ty);
- CGF.Builder.CreateMemCpy(Casted, SrcCasted,
- llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize),
- false);
- return CGF.Builder.CreateLoad(Tmp);
-}
-
-// Function to store a first-class aggregate into memory. We prefer to
-// store the elements rather than the aggregate to be more friendly to
-// fast-isel.
-// FIXME: Do we need to recurse here?
-static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val,
- Address Dest, bool DestIsVolatile) {
- // Prefer scalar stores to first-class aggregate stores.
- if (llvm::StructType *STy =
- dyn_cast<llvm::StructType>(Val->getType())) {
- const llvm::StructLayout *Layout =
- CGF.CGM.getDataLayout().getStructLayout(STy);
-
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- auto EltOffset = CharUnits::fromQuantity(Layout->getElementOffset(i));
- Address EltPtr = CGF.Builder.CreateStructGEP(Dest, i, EltOffset);
- llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i);
- CGF.Builder.CreateStore(Elt, EltPtr, DestIsVolatile);
- }
- } else {
- CGF.Builder.CreateStore(Val, Dest, DestIsVolatile);
- }
-}
-
-/// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src,
-/// where the source and destination may have different types. The
-/// destination is known to be aligned to \arg DstAlign bytes.
-///
-/// This safely handles the case when the src type is larger than the
-/// destination type; the upper bits of the src will be lost.
-static void CreateCoercedStore(llvm::Value *Src,
- Address Dst,
- bool DstIsVolatile,
- CodeGenFunction &CGF) {
- llvm::Type *SrcTy = Src->getType();
- llvm::Type *DstTy = Dst.getType()->getElementType();
- if (SrcTy == DstTy) {
- CGF.Builder.CreateStore(Src, Dst, DstIsVolatile);
- return;
- }
-
- uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
-
- if (llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) {
- Dst = EnterStructPointerForCoercedAccess(Dst, DstSTy, SrcSize, CGF);
- DstTy = Dst.getType()->getElementType();
- }
-
- // If the source and destination are integer or pointer types, just do an
- // extension or truncation to the desired type.
- if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) &&
- (isa<llvm::IntegerType>(DstTy) || isa<llvm::PointerType>(DstTy))) {
- Src = CoerceIntOrPtrToIntOrPtr(Src, DstTy, CGF);
- CGF.Builder.CreateStore(Src, Dst, DstIsVolatile);
- return;
- }
-
- uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(DstTy);
-
- // If store is legal, just bitcast the src pointer.
- if (SrcSize <= DstSize) {
- Dst = CGF.Builder.CreateElementBitCast(Dst, SrcTy);
- BuildAggStore(CGF, Src, Dst, DstIsVolatile);
- } else {
- // Otherwise do coercion through memory. This is stupid, but
- // simple.
-
- // Generally SrcSize is never greater than DstSize, since this means we are
- // losing bits. However, this can happen in cases where the structure has
- // additional padding, for example due to a user specified alignment.
- //
- // FIXME: Assert that we aren't truncating non-padding bits when have access
- // to that information.
- Address Tmp = CreateTempAllocaForCoercion(CGF, SrcTy, Dst.getAlignment());
- CGF.Builder.CreateStore(Src, Tmp);
- Address Casted = CGF.Builder.CreateElementBitCast(Tmp,CGF.Int8Ty);
- Address DstCasted = CGF.Builder.CreateElementBitCast(Dst,CGF.Int8Ty);
- CGF.Builder.CreateMemCpy(DstCasted, Casted,
- llvm::ConstantInt::get(CGF.IntPtrTy, DstSize),
- false);
- }
-}
-
-static Address emitAddressAtOffset(CodeGenFunction &CGF, Address addr,
- const ABIArgInfo &info) {
- if (unsigned offset = info.getDirectOffset()) {
- addr = CGF.Builder.CreateElementBitCast(addr, CGF.Int8Ty);
- addr = CGF.Builder.CreateConstInBoundsByteGEP(addr,
- CharUnits::fromQuantity(offset));
- addr = CGF.Builder.CreateElementBitCast(addr, info.getCoerceToType());
- }
- return addr;
-}
-
-namespace {
-
-/// Encapsulates information about the way function arguments from
-/// CGFunctionInfo should be passed to actual LLVM IR function.
-class ClangToLLVMArgMapping {
- static const unsigned InvalidIndex = ~0U;
- unsigned InallocaArgNo;
- unsigned SRetArgNo;
- unsigned TotalIRArgs;
-
- /// Arguments of LLVM IR function corresponding to single Clang argument.
- struct IRArgs {
- unsigned PaddingArgIndex;
- // Argument is expanded to IR arguments at positions
- // [FirstArgIndex, FirstArgIndex + NumberOfArgs).
- unsigned FirstArgIndex;
- unsigned NumberOfArgs;
-
- IRArgs()
- : PaddingArgIndex(InvalidIndex), FirstArgIndex(InvalidIndex),
- NumberOfArgs(0) {}
- };
-
- SmallVector<IRArgs, 8> ArgInfo;
-
-public:
- ClangToLLVMArgMapping(const ASTContext &Context, const CGFunctionInfo &FI,
- bool OnlyRequiredArgs = false)
- : InallocaArgNo(InvalidIndex), SRetArgNo(InvalidIndex), TotalIRArgs(0),
- ArgInfo(OnlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size()) {
- construct(Context, FI, OnlyRequiredArgs);
- }
-
- bool hasInallocaArg() const { return InallocaArgNo != InvalidIndex; }
- unsigned getInallocaArgNo() const {
- assert(hasInallocaArg());
- return InallocaArgNo;
- }
-
- bool hasSRetArg() const { return SRetArgNo != InvalidIndex; }
- unsigned getSRetArgNo() const {
- assert(hasSRetArg());
- return SRetArgNo;
- }
-
- unsigned totalIRArgs() const { return TotalIRArgs; }
-
- bool hasPaddingArg(unsigned ArgNo) const {
- assert(ArgNo < ArgInfo.size());
- return ArgInfo[ArgNo].PaddingArgIndex != InvalidIndex;
- }
- unsigned getPaddingArgNo(unsigned ArgNo) const {
- assert(hasPaddingArg(ArgNo));
- return ArgInfo[ArgNo].PaddingArgIndex;
- }
-
- /// Returns index of first IR argument corresponding to ArgNo, and their
- /// quantity.
- std::pair<unsigned, unsigned> getIRArgs(unsigned ArgNo) const {
- assert(ArgNo < ArgInfo.size());
- return std::make_pair(ArgInfo[ArgNo].FirstArgIndex,
- ArgInfo[ArgNo].NumberOfArgs);
- }
-
-private:
- void construct(const ASTContext &Context, const CGFunctionInfo &FI,
- bool OnlyRequiredArgs);
-};
-
-void ClangToLLVMArgMapping::construct(const ASTContext &Context,
- const CGFunctionInfo &FI,
- bool OnlyRequiredArgs) {
- unsigned IRArgNo = 0;
- bool SwapThisWithSRet = false;
- const ABIArgInfo &RetAI = FI.getReturnInfo();
-
- if (RetAI.getKind() == ABIArgInfo::Indirect) {
- SwapThisWithSRet = RetAI.isSRetAfterThis();
- SRetArgNo = SwapThisWithSRet ? 1 : IRArgNo++;
- }
-
- unsigned ArgNo = 0;
- unsigned NumArgs = OnlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size();
- for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(); ArgNo < NumArgs;
- ++I, ++ArgNo) {
- assert(I != FI.arg_end());
- QualType ArgType = I->type;
- const ABIArgInfo &AI = I->info;
- // Collect data about IR arguments corresponding to Clang argument ArgNo.
- auto &IRArgs = ArgInfo[ArgNo];
-
- if (AI.getPaddingType())
- IRArgs.PaddingArgIndex = IRArgNo++;
-
- switch (AI.getKind()) {
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct: {
- // FIXME: handle sseregparm someday...
- llvm::StructType *STy = dyn_cast<llvm::StructType>(AI.getCoerceToType());
- if (AI.isDirect() && AI.getCanBeFlattened() && STy) {
- IRArgs.NumberOfArgs = STy->getNumElements();
- } else {
- IRArgs.NumberOfArgs = 1;
- }
- break;
- }
- case ABIArgInfo::Indirect:
- IRArgs.NumberOfArgs = 1;
- break;
- case ABIArgInfo::Ignore:
- case ABIArgInfo::InAlloca:
- // ignore and inalloca doesn't have matching LLVM parameters.
- IRArgs.NumberOfArgs = 0;
- break;
- case ABIArgInfo::CoerceAndExpand:
- IRArgs.NumberOfArgs = AI.getCoerceAndExpandTypeSequence().size();
- break;
- case ABIArgInfo::Expand:
- IRArgs.NumberOfArgs = getExpansionSize(ArgType, Context);
- break;
- }
-
- if (IRArgs.NumberOfArgs > 0) {
- IRArgs.FirstArgIndex = IRArgNo;
- IRArgNo += IRArgs.NumberOfArgs;
- }
-
- // Skip over the sret parameter when it comes second. We already handled it
- // above.
- if (IRArgNo == 1 && SwapThisWithSRet)
- IRArgNo++;
- }
- assert(ArgNo == ArgInfo.size());
-
- if (FI.usesInAlloca())
- InallocaArgNo = IRArgNo++;
-
- TotalIRArgs = IRArgNo;
-}
-} // namespace
-
-/***/
-
-bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) {
- const auto &RI = FI.getReturnInfo();
- return RI.isIndirect() || (RI.isInAlloca() && RI.getInAllocaSRet());
-}
-
-bool CodeGenModule::ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI) {
- return ReturnTypeUsesSRet(FI) &&
- getTargetCodeGenInfo().doesReturnSlotInterfereWithArgs();
-}
-
-bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
- if (const BuiltinType *BT = ResultType->getAs<BuiltinType>()) {
- switch (BT->getKind()) {
- default:
- return false;
- case BuiltinType::Float:
- return getTarget().useObjCFPRetForRealType(TargetInfo::Float);
- case BuiltinType::Double:
- return getTarget().useObjCFPRetForRealType(TargetInfo::Double);
- case BuiltinType::LongDouble:
- return getTarget().useObjCFPRetForRealType(TargetInfo::LongDouble);
- }
- }
-
- return false;
-}
-
-bool CodeGenModule::ReturnTypeUsesFP2Ret(QualType ResultType) {
- if (const ComplexType *CT = ResultType->getAs<ComplexType>()) {
- if (const BuiltinType *BT = CT->getElementType()->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::LongDouble)
- return getTarget().useObjCFP2RetForComplexLongDouble();
- }
- }
-
- return false;
-}
-
-llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
- const CGFunctionInfo &FI = arrangeGlobalDeclaration(GD);
- return GetFunctionType(FI);
-}
-
-llvm::FunctionType *
-CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
-
- bool Inserted = FunctionsBeingProcessed.insert(&FI).second;
- (void)Inserted;
- assert(Inserted && "Recursively being processed?");
-
- llvm::Type *resultType = nullptr;
- const ABIArgInfo &retAI = FI.getReturnInfo();
- switch (retAI.getKind()) {
- case ABIArgInfo::Expand:
- llvm_unreachable("Invalid ABI kind for return argument");
-
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct:
- resultType = retAI.getCoerceToType();
- break;
-
- case ABIArgInfo::InAlloca:
- if (retAI.getInAllocaSRet()) {
- // sret things on win32 aren't void, they return the sret pointer.
- QualType ret = FI.getReturnType();
- llvm::Type *ty = ConvertType(ret);
- unsigned addressSpace = Context.getTargetAddressSpace(ret);
- resultType = llvm::PointerType::get(ty, addressSpace);
- } else {
- resultType = llvm::Type::getVoidTy(getLLVMContext());
- }
- break;
-
- case ABIArgInfo::Indirect:
- case ABIArgInfo::Ignore:
- resultType = llvm::Type::getVoidTy(getLLVMContext());
- break;
-
- case ABIArgInfo::CoerceAndExpand:
- resultType = retAI.getUnpaddedCoerceAndExpandType();
- break;
- }
-
- ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI, true);
- SmallVector<llvm::Type*, 8> ArgTypes(IRFunctionArgs.totalIRArgs());
-
- // Add type for sret argument.
- if (IRFunctionArgs.hasSRetArg()) {
- QualType Ret = FI.getReturnType();
- llvm::Type *Ty = ConvertType(Ret);
- unsigned AddressSpace = Context.getTargetAddressSpace(Ret);
- ArgTypes[IRFunctionArgs.getSRetArgNo()] =
- llvm::PointerType::get(Ty, AddressSpace);
- }
-
- // Add type for inalloca argument.
- if (IRFunctionArgs.hasInallocaArg()) {
- auto ArgStruct = FI.getArgStruct();
- assert(ArgStruct);
- ArgTypes[IRFunctionArgs.getInallocaArgNo()] = ArgStruct->getPointerTo();
- }
-
- // Add in all of the required arguments.
- unsigned ArgNo = 0;
- CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
- ie = it + FI.getNumRequiredArgs();
- for (; it != ie; ++it, ++ArgNo) {
- const ABIArgInfo &ArgInfo = it->info;
-
- // Insert a padding type to ensure proper alignment.
- if (IRFunctionArgs.hasPaddingArg(ArgNo))
- ArgTypes[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
- ArgInfo.getPaddingType();
-
- unsigned FirstIRArg, NumIRArgs;
- std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
-
- switch (ArgInfo.getKind()) {
- case ABIArgInfo::Ignore:
- case ABIArgInfo::InAlloca:
- assert(NumIRArgs == 0);
- break;
-
- case ABIArgInfo::Indirect: {
- assert(NumIRArgs == 1);
- // indirect arguments are always on the stack, which is alloca addr space.
- llvm::Type *LTy = ConvertTypeForMem(it->type);
- ArgTypes[FirstIRArg] = LTy->getPointerTo(
- CGM.getDataLayout().getAllocaAddrSpace());
- break;
- }
-
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct: {
- // Fast-isel and the optimizer generally like scalar values better than
- // FCAs, so we flatten them if this is safe to do for this argument.
- llvm::Type *argType = ArgInfo.getCoerceToType();
- llvm::StructType *st = dyn_cast<llvm::StructType>(argType);
- if (st && ArgInfo.isDirect() && ArgInfo.getCanBeFlattened()) {
- assert(NumIRArgs == st->getNumElements());
- for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
- ArgTypes[FirstIRArg + i] = st->getElementType(i);
- } else {
- assert(NumIRArgs == 1);
- ArgTypes[FirstIRArg] = argType;
- }
- break;
- }
-
- case ABIArgInfo::CoerceAndExpand: {
- auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
- for (auto EltTy : ArgInfo.getCoerceAndExpandTypeSequence()) {
- *ArgTypesIter++ = EltTy;
- }
- assert(ArgTypesIter == ArgTypes.begin() + FirstIRArg + NumIRArgs);
- break;
- }
-
- case ABIArgInfo::Expand:
- auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
- getExpandedTypes(it->type, ArgTypesIter);
- assert(ArgTypesIter == ArgTypes.begin() + FirstIRArg + NumIRArgs);
- break;
- }
- }
-
- bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
- assert(Erased && "Not in set?");
-
- return llvm::FunctionType::get(resultType, ArgTypes, FI.isVariadic());
-}
-
-llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-
- if (!isFuncTypeConvertible(FPT))
- return llvm::StructType::get(getLLVMContext());
-
- const CGFunctionInfo *Info;
- if (isa<CXXDestructorDecl>(MD))
- Info =
- &arrangeCXXStructorDeclaration(MD, getFromDtorType(GD.getDtorType()));
- else
- Info = &arrangeCXXMethodDeclaration(MD);
- return GetFunctionType(*Info);
-}
-
-static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
- llvm::AttrBuilder &FuncAttrs,
- const FunctionProtoType *FPT) {
- if (!FPT)
- return;
-
- if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
- FPT->isNothrow())
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
-}
-
-void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
- bool AttrOnCallSite,
- llvm::AttrBuilder &FuncAttrs) {
- // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
- if (!HasOptnone) {
- if (CodeGenOpts.OptimizeSize)
- FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
- if (CodeGenOpts.OptimizeSize == 2)
- FuncAttrs.addAttribute(llvm::Attribute::MinSize);
- }
-
- if (CodeGenOpts.DisableRedZone)
- FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
- if (CodeGenOpts.IndirectTlsSegRefs)
- FuncAttrs.addAttribute("indirect-tls-seg-refs");
- if (CodeGenOpts.NoImplicitFloat)
- FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat);
-
- if (AttrOnCallSite) {
- // Attributes that should go on the call site only.
- if (!CodeGenOpts.SimplifyLibCalls ||
- CodeGenOpts.isNoBuiltinFunc(Name.data()))
- FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
- if (!CodeGenOpts.TrapFuncName.empty())
- FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
- } else {
- // Attributes that should go on the function, but not the call site.
- if (!CodeGenOpts.DisableFPElim) {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- } else if (CodeGenOpts.OmitLeafFramePointer) {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
- } else {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "true");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
- }
-
- FuncAttrs.addAttribute("less-precise-fpmad",
- llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD));
-
- if (CodeGenOpts.NullPointerIsValid)
- FuncAttrs.addAttribute("null-pointer-is-valid", "true");
- if (!CodeGenOpts.FPDenormalMode.empty())
- FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode);
-
- FuncAttrs.addAttribute("no-trapping-math",
- llvm::toStringRef(CodeGenOpts.NoTrappingMath));
-
- // Strict (compliant) code is the default, so only add this attribute to
- // indicate that we are trying to workaround a problem case.
- if (!CodeGenOpts.StrictFloatCastOverflow)
- FuncAttrs.addAttribute("strict-float-cast-overflow", "false");
-
- // TODO: Are these all needed?
- // unsafe/inf/nan/nsz are handled by instruction-level FastMathFlags.
- FuncAttrs.addAttribute("no-infs-fp-math",
- llvm::toStringRef(CodeGenOpts.NoInfsFPMath));
- FuncAttrs.addAttribute("no-nans-fp-math",
- llvm::toStringRef(CodeGenOpts.NoNaNsFPMath));
- FuncAttrs.addAttribute("unsafe-fp-math",
- llvm::toStringRef(CodeGenOpts.UnsafeFPMath));
- FuncAttrs.addAttribute("use-soft-float",
- llvm::toStringRef(CodeGenOpts.SoftFloat));
- FuncAttrs.addAttribute("stack-protector-buffer-size",
- llvm::utostr(CodeGenOpts.SSPBufferSize));
- FuncAttrs.addAttribute("no-signed-zeros-fp-math",
- llvm::toStringRef(CodeGenOpts.NoSignedZeros));
- FuncAttrs.addAttribute(
- "correctly-rounded-divide-sqrt-fp-math",
- llvm::toStringRef(CodeGenOpts.CorrectlyRoundedDivSqrt));
-
- if (getLangOpts().OpenCL)
- FuncAttrs.addAttribute("denorms-are-zero",
- llvm::toStringRef(CodeGenOpts.FlushDenorm));
-
- // TODO: Reciprocal estimate codegen options should apply to instructions?
- const std::vector<std::string> &Recips = CodeGenOpts.Reciprocals;
- if (!Recips.empty())
- FuncAttrs.addAttribute("reciprocal-estimates",
- llvm::join(Recips, ","));
-
- if (!CodeGenOpts.PreferVectorWidth.empty() &&
- CodeGenOpts.PreferVectorWidth != "none")
- FuncAttrs.addAttribute("prefer-vector-width",
- CodeGenOpts.PreferVectorWidth);
-
- if (CodeGenOpts.StackRealignment)
- FuncAttrs.addAttribute("stackrealign");
- if (CodeGenOpts.Backchain)
- FuncAttrs.addAttribute("backchain");
-
- // FIXME: The interaction of this attribute with the SLH command line flag
- // has not been determined.
- if (CodeGenOpts.SpeculativeLoadHardening)
- FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
- }
-
- if (getLangOpts().assumeFunctionsAreConvergent()) {
- // Conservatively, mark all functions and calls in CUDA and OpenCL as
- // convergent (meaning, they may call an intrinsically convergent op, such
- // as __syncthreads() / barrier(), and so can't have certain optimizations
- // applied around them). LLVM will remove this attribute where it safely
- // can.
- FuncAttrs.addAttribute(llvm::Attribute::Convergent);
- }
-
- if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
- // Exceptions aren't supported in CUDA device code.
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
-
- // Respect -fcuda-flush-denormals-to-zero.
- if (CodeGenOpts.FlushDenorm)
- FuncAttrs.addAttribute("nvptx-f32ftz", "true");
- }
-
- for (StringRef Attr : CodeGenOpts.DefaultFunctionAttrs) {
- StringRef Var, Value;
- std::tie(Var, Value) = Attr.split('=');
- FuncAttrs.addAttribute(Var, Value);
- }
-}
-
-void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) {
- llvm::AttrBuilder FuncAttrs;
- ConstructDefaultFnAttrList(F.getName(),
- F.hasFnAttribute(llvm::Attribute::OptimizeNone),
- /* AttrOnCallsite = */ false, FuncAttrs);
- F.addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs);
-}
-
-void CodeGenModule::ConstructAttributeList(
- StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
- llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite) {
- llvm::AttrBuilder FuncAttrs;
- llvm::AttrBuilder RetAttrs;
-
- CallingConv = FI.getEffectiveCallingConvention();
- if (FI.isNoReturn())
- FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
-
- // If we have information about the function prototype, we can learn
- // attributes from there.
- AddAttributesFromFunctionProtoType(getContext(), FuncAttrs,
- CalleeInfo.getCalleeFunctionProtoType());
-
- const Decl *TargetDecl = CalleeInfo.getCalleeDecl().getDecl();
-
- bool HasOptnone = false;
- // FIXME: handle sseregparm someday...
- if (TargetDecl) {
- if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::ReturnsTwice);
- if (TargetDecl->hasAttr<NoThrowAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
- if (TargetDecl->hasAttr<NoReturnAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
- if (TargetDecl->hasAttr<ColdAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::Cold);
- if (TargetDecl->hasAttr<NoDuplicateAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
- if (TargetDecl->hasAttr<ConvergentAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::Convergent);
- if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
-
- if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
- AddAttributesFromFunctionProtoType(
- getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());
- // Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
- // These attributes are not inherited by overloads.
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
- if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))
- FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
- }
-
- // 'const', 'pure' and 'noalias' attributed functions are also nounwind.
- if (TargetDecl->hasAttr<ConstAttr>()) {
- FuncAttrs.addAttribute(llvm::Attribute::ReadNone);
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
- } else if (TargetDecl->hasAttr<PureAttr>()) {
- FuncAttrs.addAttribute(llvm::Attribute::ReadOnly);
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
- } else if (TargetDecl->hasAttr<NoAliasAttr>()) {
- FuncAttrs.addAttribute(llvm::Attribute::ArgMemOnly);
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
- }
- if (TargetDecl->hasAttr<RestrictAttr>())
- RetAttrs.addAttribute(llvm::Attribute::NoAlias);
- if (TargetDecl->hasAttr<ReturnsNonNullAttr>() &&
- !CodeGenOpts.NullPointerIsValid)
- RetAttrs.addAttribute(llvm::Attribute::NonNull);
- if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())
- FuncAttrs.addAttribute("no_caller_saved_registers");
- if (TargetDecl->hasAttr<AnyX86NoCfCheckAttr>())
- FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck);
-
- HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
- if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
- Optional<unsigned> NumElemsParam;
- if (AllocSize->getNumElemsParam().isValid())
- NumElemsParam = AllocSize->getNumElemsParam().getLLVMIndex();
- FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam().getLLVMIndex(),
- NumElemsParam);
- }
- }
-
- ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs);
-
- if (CodeGenOpts.EnableSegmentedStacks &&
- !(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>()))
- FuncAttrs.addAttribute("split-stack");
-
- // Add NonLazyBind attribute to function declarations when -fno-plt
- // is used.
- if (TargetDecl && CodeGenOpts.NoPLT) {
- if (auto *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
- if (!Fn->isDefined() && !AttrOnCallSite) {
- FuncAttrs.addAttribute(llvm::Attribute::NonLazyBind);
- }
- }
- }
-
- if (TargetDecl && TargetDecl->hasAttr<OpenCLKernelAttr>()) {
- if (getLangOpts().OpenCLVersion <= 120) {
- // OpenCL v1.2 Work groups are always uniform
- FuncAttrs.addAttribute("uniform-work-group-size", "true");
- } else {
- // OpenCL v2.0 Work groups may be whether uniform or not.
- // '-cl-uniform-work-group-size' compile option gets a hint
- // to the compiler that the global work-size be a multiple of
- // the work-group size specified to clEnqueueNDRangeKernel
- // (i.e. work groups are uniform).
- FuncAttrs.addAttribute("uniform-work-group-size",
- llvm::toStringRef(CodeGenOpts.UniformWGSize));
- }
- }
-
- if (!AttrOnCallSite) {
- bool DisableTailCalls = false;
-
- if (CodeGenOpts.DisableTailCalls)
- DisableTailCalls = true;
- else if (TargetDecl) {
- if (TargetDecl->hasAttr<DisableTailCallsAttr>() ||
- TargetDecl->hasAttr<AnyX86InterruptAttr>())
- DisableTailCalls = true;
- else if (CodeGenOpts.NoEscapingBlockTailCalls) {
- if (const auto *BD = dyn_cast<BlockDecl>(TargetDecl))
- if (!BD->doesNotEscape())
- DisableTailCalls = true;
- }
- }
-
- FuncAttrs.addAttribute("disable-tail-calls",
- llvm::toStringRef(DisableTailCalls));
- GetCPUAndFeaturesAttributes(CalleeInfo.getCalleeDecl(), FuncAttrs);
-
- if (CodeGenOpts.ReturnProtector)
- FuncAttrs.addAttribute("ret-protector");
- }
-
- ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI);
-
- QualType RetTy = FI.getReturnType();
- const ABIArgInfo &RetAI = FI.getReturnInfo();
- switch (RetAI.getKind()) {
- case ABIArgInfo::Extend:
- if (RetAI.isSignExt())
- RetAttrs.addAttribute(llvm::Attribute::SExt);
- else
- RetAttrs.addAttribute(llvm::Attribute::ZExt);
- LLVM_FALLTHROUGH;
- case ABIArgInfo::Direct:
- if (RetAI.getInReg())
- RetAttrs.addAttribute(llvm::Attribute::InReg);
- break;
- case ABIArgInfo::Ignore:
- break;
-
- case ABIArgInfo::InAlloca:
- case ABIArgInfo::Indirect: {
- // inalloca and sret disable readnone and readonly
- FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
- .removeAttribute(llvm::Attribute::ReadNone);
- break;
- }
-
- case ABIArgInfo::CoerceAndExpand:
- break;
-
- case ABIArgInfo::Expand:
- llvm_unreachable("Invalid ABI kind for return argument");
- }
-
- if (const auto *RefTy = RetTy->getAs<ReferenceType>()) {
- QualType PTy = RefTy->getPointeeType();
- if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
- RetAttrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
- .getQuantity());
- else if (getContext().getTargetAddressSpace(PTy) == 0 &&
- !CodeGenOpts.NullPointerIsValid)
- RetAttrs.addAttribute(llvm::Attribute::NonNull);
- }
-
- bool hasUsedSRet = false;
- SmallVector<llvm::AttributeSet, 4> ArgAttrs(IRFunctionArgs.totalIRArgs());
-
- // Attach attributes to sret.
- if (IRFunctionArgs.hasSRetArg()) {
- llvm::AttrBuilder SRETAttrs;
- if (!RetAI.getSuppressSRet())
- SRETAttrs.addAttribute(llvm::Attribute::StructRet);
- hasUsedSRet = true;
- if (RetAI.getInReg())
- SRETAttrs.addAttribute(llvm::Attribute::InReg);
- ArgAttrs[IRFunctionArgs.getSRetArgNo()] =
- llvm::AttributeSet::get(getLLVMContext(), SRETAttrs);
- }
-
- // Attach attributes to inalloca argument.
- if (IRFunctionArgs.hasInallocaArg()) {
- llvm::AttrBuilder Attrs;
- Attrs.addAttribute(llvm::Attribute::InAlloca);
- ArgAttrs[IRFunctionArgs.getInallocaArgNo()] =
- llvm::AttributeSet::get(getLLVMContext(), Attrs);
- }
-
- unsigned ArgNo = 0;
- for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(),
- E = FI.arg_end();
- I != E; ++I, ++ArgNo) {
- QualType ParamType = I->type;
- const ABIArgInfo &AI = I->info;
- llvm::AttrBuilder Attrs;
-
- // Add attribute for padding argument, if necessary.
- if (IRFunctionArgs.hasPaddingArg(ArgNo)) {
- if (AI.getPaddingInReg()) {
- ArgAttrs[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
- llvm::AttributeSet::get(
- getLLVMContext(),
- llvm::AttrBuilder().addAttribute(llvm::Attribute::InReg));
- }
- }
-
- // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
- // have the corresponding parameter variable. It doesn't make
- // sense to do it here because parameters are so messed up.
- switch (AI.getKind()) {
- case ABIArgInfo::Extend:
- if (AI.isSignExt())
- Attrs.addAttribute(llvm::Attribute::SExt);
- else
- Attrs.addAttribute(llvm::Attribute::ZExt);
- LLVM_FALLTHROUGH;
- case ABIArgInfo::Direct:
- if (ArgNo == 0 && FI.isChainCall())
- Attrs.addAttribute(llvm::Attribute::Nest);
- else if (AI.getInReg())
- Attrs.addAttribute(llvm::Attribute::InReg);
- break;
-
- case ABIArgInfo::Indirect: {
- if (AI.getInReg())
- Attrs.addAttribute(llvm::Attribute::InReg);
-
- if (AI.getIndirectByVal())
- Attrs.addAttribute(llvm::Attribute::ByVal);
-
- CharUnits Align = AI.getIndirectAlign();
-
- // In a byval argument, it is important that the required
- // alignment of the type is honored, as LLVM might be creating a
- // *new* stack object, and needs to know what alignment to give
- // it. (Sometimes it can deduce a sensible alignment on its own,
- // but not if clang decides it must emit a packed struct, or the
- // user specifies increased alignment requirements.)
- //
- // This is different from indirect *not* byval, where the object
- // exists already, and the align attribute is purely
- // informative.
- assert(!Align.isZero());
-
- // For now, only add this when we have a byval argument.
- // TODO: be less lazy about updating test cases.
- if (AI.getIndirectByVal())
- Attrs.addAlignmentAttr(Align.getQuantity());
-
- // byval disables readnone and readonly.
- FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
- .removeAttribute(llvm::Attribute::ReadNone);
- break;
- }
- case ABIArgInfo::Ignore:
- case ABIArgInfo::Expand:
- case ABIArgInfo::CoerceAndExpand:
- break;
-
- case ABIArgInfo::InAlloca:
- // inalloca disables readnone and readonly.
- FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
- .removeAttribute(llvm::Attribute::ReadNone);
- continue;
- }
-
- if (const auto *RefTy = ParamType->getAs<ReferenceType>()) {
- QualType PTy = RefTy->getPointeeType();
- if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
- Attrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
- .getQuantity());
- else if (getContext().getTargetAddressSpace(PTy) == 0 &&
- !CodeGenOpts.NullPointerIsValid)
- Attrs.addAttribute(llvm::Attribute::NonNull);
- }
-
- switch (FI.getExtParameterInfo(ArgNo).getABI()) {
- case ParameterABI::Ordinary:
- break;
-
- case ParameterABI::SwiftIndirectResult: {
- // Add 'sret' if we haven't already used it for something, but
- // only if the result is void.
- if (!hasUsedSRet && RetTy->isVoidType()) {
- Attrs.addAttribute(llvm::Attribute::StructRet);
- hasUsedSRet = true;
- }
-
- // Add 'noalias' in either case.
- Attrs.addAttribute(llvm::Attribute::NoAlias);
-
- // Add 'dereferenceable' and 'alignment'.
- auto PTy = ParamType->getPointeeType();
- if (!PTy->isIncompleteType() && PTy->isConstantSizeType()) {
- auto info = getContext().getTypeInfoInChars(PTy);
- Attrs.addDereferenceableAttr(info.first.getQuantity());
- Attrs.addAttribute(llvm::Attribute::getWithAlignment(getLLVMContext(),
- info.second.getQuantity()));
- }
- break;
- }
-
- case ParameterABI::SwiftErrorResult:
- Attrs.addAttribute(llvm::Attribute::SwiftError);
- break;
-
- case ParameterABI::SwiftContext:
- Attrs.addAttribute(llvm::Attribute::SwiftSelf);
- break;
- }
-
- if (FI.getExtParameterInfo(ArgNo).isNoEscape())
- Attrs.addAttribute(llvm::Attribute::NoCapture);
-
- if (Attrs.hasAttributes()) {
- unsigned FirstIRArg, NumIRArgs;
- std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
- for (unsigned i = 0; i < NumIRArgs; i++)
- ArgAttrs[FirstIRArg + i] =
- llvm::AttributeSet::get(getLLVMContext(), Attrs);
- }
- }
- assert(ArgNo == FI.arg_size());
-
- AttrList = llvm::AttributeList::get(
- getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs),
- llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs);
-}
-
-/// An argument came in as a promoted argument; demote it back to its
-/// declared type.
-static llvm::Value *emitArgumentDemotion(CodeGenFunction &CGF,
- const VarDecl *var,
- llvm::Value *value) {
- llvm::Type *varType = CGF.ConvertType(var->getType());
-
- // This can happen with promotions that actually don't change the
- // underlying type, like the enum promotions.
- if (value->getType() == varType) return value;
-
- assert((varType->isIntegerTy() || varType->isFloatingPointTy())
- && "unexpected promotion type");
-
- if (isa<llvm::IntegerType>(varType))
- return CGF.Builder.CreateTrunc(value, varType, "arg.unpromote");
-
- return CGF.Builder.CreateFPCast(value, varType, "arg.unpromote");
-}
-
-/// Returns the attribute (either parameter attribute, or function
-/// attribute), which declares argument ArgNo to be non-null.
-static const NonNullAttr *getNonNullAttr(const Decl *FD, const ParmVarDecl *PVD,
- QualType ArgType, unsigned ArgNo) {
- // FIXME: __attribute__((nonnull)) can also be applied to:
- // - references to pointers, where the pointee is known to be
- // nonnull (apparently a Clang extension)
- // - transparent unions containing pointers
- // In the former case, LLVM IR cannot represent the constraint. In
- // the latter case, we have no guarantee that the transparent union
- // is in fact passed as a pointer.
- if (!ArgType->isAnyPointerType() && !ArgType->isBlockPointerType())
- return nullptr;
- // First, check attribute on parameter itself.
- if (PVD) {
- if (auto ParmNNAttr = PVD->getAttr<NonNullAttr>())
- return ParmNNAttr;
- }
- // Check function attributes.
- if (!FD)
- return nullptr;
- for (const auto *NNAttr : FD->specific_attrs<NonNullAttr>()) {
- if (NNAttr->isNonNull(ArgNo))
- return NNAttr;
- }
- return nullptr;
-}
-
-namespace {
- struct CopyBackSwiftError final : EHScopeStack::Cleanup {
- Address Temp;
- Address Arg;
- CopyBackSwiftError(Address temp, Address arg) : Temp(temp), Arg(arg) {}
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- llvm::Value *errorValue = CGF.Builder.CreateLoad(Temp);
- CGF.Builder.CreateStore(errorValue, Arg);
- }
- };
-}
-
-void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
- if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>())
- // Naked functions don't have prologues.
- return;
-
- // If this is an implicit-return-zero function, go ahead and
- // initialize the return value. TODO: it might be nice to have
- // a more general mechanism for this that didn't require synthesized
- // return statements.
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl)) {
- if (FD->hasImplicitReturnZero()) {
- QualType RetTy = FD->getReturnType().getUnqualifiedType();
- llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
- llvm::Constant* Zero = llvm::Constant::getNullValue(LLVMTy);
- Builder.CreateStore(Zero, ReturnValue);
- }
- }
-
- // FIXME: We no longer need the types from FunctionArgList; lift up and
- // simplify.
-
- ClangToLLVMArgMapping IRFunctionArgs(CGM.getContext(), FI);
- // Flattened function arguments.
- SmallVector<llvm::Value *, 16> FnArgs;
- FnArgs.reserve(IRFunctionArgs.totalIRArgs());
- for (auto &Arg : Fn->args()) {
- FnArgs.push_back(&Arg);
- }
- assert(FnArgs.size() == IRFunctionArgs.totalIRArgs());
-
- // If we're using inalloca, all the memory arguments are GEPs off of the last
- // parameter, which is a pointer to the complete memory area.
- Address ArgStruct = Address::invalid();
- const llvm::StructLayout *ArgStructLayout = nullptr;
- if (IRFunctionArgs.hasInallocaArg()) {
- ArgStructLayout = CGM.getDataLayout().getStructLayout(FI.getArgStruct());
- ArgStruct = Address(FnArgs[IRFunctionArgs.getInallocaArgNo()],
- FI.getArgStructAlignment());
-
- assert(ArgStruct.getType() == FI.getArgStruct()->getPointerTo());
- }
-
- // Name the struct return parameter.
- if (IRFunctionArgs.hasSRetArg()) {
- auto AI = cast<llvm::Argument>(FnArgs[IRFunctionArgs.getSRetArgNo()]);
- AI->setName("agg.result");
- AI->addAttr(llvm::Attribute::NoAlias);
- }
-
- // Track if we received the parameter as a pointer (indirect, byval, or
- // inalloca). If already have a pointer, EmitParmDecl doesn't need to copy it
- // into a local alloca for us.
- SmallVector<ParamValue, 16> ArgVals;
- ArgVals.reserve(Args.size());
-
- // Create a pointer value for every parameter declaration. This usually
- // entails copying one or more LLVM IR arguments into an alloca. Don't push
- // any cleanups or do anything that might unwind. We do that separately, so
- // we can push the cleanups in the correct order for the ABI.
- assert(FI.arg_size() == Args.size() &&
- "Mismatch between function signature & arguments.");
- unsigned ArgNo = 0;
- CGFunctionInfo::const_arg_iterator info_it = FI.arg_begin();
- for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
- i != e; ++i, ++info_it, ++ArgNo) {
- const VarDecl *Arg = *i;
- const ABIArgInfo &ArgI = info_it->info;
-
- bool isPromoted =
- isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted();
- // We are converting from ABIArgInfo type to VarDecl type directly, unless
- // the parameter is promoted. In this case we convert to
- // CGFunctionInfo::ArgInfo type with subsequent argument demotion.
- QualType Ty = isPromoted ? info_it->type : Arg->getType();
- assert(hasScalarEvaluationKind(Ty) ==
- hasScalarEvaluationKind(Arg->getType()));
-
- unsigned FirstIRArg, NumIRArgs;
- std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
-
- switch (ArgI.getKind()) {
- case ABIArgInfo::InAlloca: {
- assert(NumIRArgs == 0);
- auto FieldIndex = ArgI.getInAllocaFieldIndex();
- CharUnits FieldOffset =
- CharUnits::fromQuantity(ArgStructLayout->getElementOffset(FieldIndex));
- Address V = Builder.CreateStructGEP(ArgStruct, FieldIndex, FieldOffset,
- Arg->getName());
- ArgVals.push_back(ParamValue::forIndirect(V));
- break;
- }
-
- case ABIArgInfo::Indirect: {
- assert(NumIRArgs == 1);
- Address ParamAddr = Address(FnArgs[FirstIRArg], ArgI.getIndirectAlign());
-
- if (!hasScalarEvaluationKind(Ty)) {
- // Aggregates and complex variables are accessed by reference. All we
- // need to do is realign the value, if requested.
- Address V = ParamAddr;
- if (ArgI.getIndirectRealign()) {
- Address AlignedTemp = CreateMemTemp(Ty, "coerce");
-
- // Copy from the incoming argument pointer to the temporary with the
- // appropriate alignment.
- //
- // FIXME: We should have a common utility for generating an aggregate
- // copy.
- CharUnits Size = getContext().getTypeSizeInChars(Ty);
- auto SizeVal = llvm::ConstantInt::get(IntPtrTy, Size.getQuantity());
- Address Dst = Builder.CreateBitCast(AlignedTemp, Int8PtrTy);
- Address Src = Builder.CreateBitCast(ParamAddr, Int8PtrTy);
- Builder.CreateMemCpy(Dst, Src, SizeVal, false);
- V = AlignedTemp;
- }
- ArgVals.push_back(ParamValue::forIndirect(V));
- } else {
- // Load scalar value from indirect argument.
- llvm::Value *V =
- EmitLoadOfScalar(ParamAddr, false, Ty, Arg->getBeginLoc());
-
- if (isPromoted)
- V = emitArgumentDemotion(*this, Arg, V);
- ArgVals.push_back(ParamValue::forDirect(V));
- }
- break;
- }
-
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct: {
-
- // If we have the trivial case, handle it with no muss and fuss.
- if (!isa<llvm::StructType>(ArgI.getCoerceToType()) &&
- ArgI.getCoerceToType() == ConvertType(Ty) &&
- ArgI.getDirectOffset() == 0) {
- assert(NumIRArgs == 1);
- llvm::Value *V = FnArgs[FirstIRArg];
- auto AI = cast<llvm::Argument>(V);
-
- if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
- if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(),
- PVD->getFunctionScopeIndex()) &&
- !CGM.getCodeGenOpts().NullPointerIsValid)
- AI->addAttr(llvm::Attribute::NonNull);
-
- QualType OTy = PVD->getOriginalType();
- if (const auto *ArrTy =
- getContext().getAsConstantArrayType(OTy)) {
- // A C99 array parameter declaration with the static keyword also
- // indicates dereferenceability, and if the size is constant we can
- // use the dereferenceable attribute (which requires the size in
- // bytes).
- if (ArrTy->getSizeModifier() == ArrayType::Static) {
- QualType ETy = ArrTy->getElementType();
- uint64_t ArrSize = ArrTy->getSize().getZExtValue();
- if (!ETy->isIncompleteType() && ETy->isConstantSizeType() &&
- ArrSize) {
- llvm::AttrBuilder Attrs;
- Attrs.addDereferenceableAttr(
- getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize);
- AI->addAttrs(Attrs);
- } else if (getContext().getTargetAddressSpace(ETy) == 0 &&
- !CGM.getCodeGenOpts().NullPointerIsValid) {
- AI->addAttr(llvm::Attribute::NonNull);
- }
- }
- } else if (const auto *ArrTy =
- getContext().getAsVariableArrayType(OTy)) {
- // For C99 VLAs with the static keyword, we don't know the size so
- // we can't use the dereferenceable attribute, but in addrspace(0)
- // we know that it must be nonnull.
- if (ArrTy->getSizeModifier() == VariableArrayType::Static &&
- !getContext().getTargetAddressSpace(ArrTy->getElementType()) &&
- !CGM.getCodeGenOpts().NullPointerIsValid)
- AI->addAttr(llvm::Attribute::NonNull);
- }
-
- const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
- if (!AVAttr)
- if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
- AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
- if (AVAttr && !SanOpts.has(SanitizerKind::Alignment)) {
- // If alignment-assumption sanitizer is enabled, we do *not* add
- // alignment attribute here, but emit normal alignment assumption,
- // so the UBSAN check could function.
- llvm::Value *AlignmentValue =
- EmitScalarExpr(AVAttr->getAlignment());
- llvm::ConstantInt *AlignmentCI =
- cast<llvm::ConstantInt>(AlignmentValue);
- unsigned Alignment = std::min((unsigned)AlignmentCI->getZExtValue(),
- +llvm::Value::MaximumAlignment);
- AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment));
- }
- }
-
- if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::Attribute::NoAlias);
-
- // LLVM expects swifterror parameters to be used in very restricted
- // ways. Copy the value into a less-restricted temporary.
- if (FI.getExtParameterInfo(ArgNo).getABI()
- == ParameterABI::SwiftErrorResult) {
- QualType pointeeTy = Ty->getPointeeType();
- assert(pointeeTy->isPointerType());
- Address temp =
- CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp");
- Address arg = Address(V, getContext().getTypeAlignInChars(pointeeTy));
- llvm::Value *incomingErrorValue = Builder.CreateLoad(arg);
- Builder.CreateStore(incomingErrorValue, temp);
- V = temp.getPointer();
-
- // Push a cleanup to copy the value back at the end of the function.
- // The convention does not guarantee that the value will be written
- // back if the function exits with an unwind exception.
- EHStack.pushCleanup<CopyBackSwiftError>(NormalCleanup, temp, arg);
- }
-
- // Ensure the argument is the correct type.
- if (V->getType() != ArgI.getCoerceToType())
- V = Builder.CreateBitCast(V, ArgI.getCoerceToType());
-
- if (isPromoted)
- V = emitArgumentDemotion(*this, Arg, V);
-
- // Because of merging of function types from multiple decls it is
- // possible for the type of an argument to not match the corresponding
- // type in the function type. Since we are codegening the callee
- // in here, add a cast to the argument type.
- llvm::Type *LTy = ConvertType(Arg->getType());
- if (V->getType() != LTy)
- V = Builder.CreateBitCast(V, LTy);
-
- ArgVals.push_back(ParamValue::forDirect(V));
- break;
- }
-
- Address Alloca = CreateMemTemp(Ty, getContext().getDeclAlign(Arg),
- Arg->getName());
-
- // Pointer to store into.
- Address Ptr = emitAddressAtOffset(*this, Alloca, ArgI);
-
- // Fast-isel and the optimizer generally like scalar values better than
- // FCAs, so we flatten them if this is safe to do for this argument.
- llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
- if (ArgI.isDirect() && ArgI.getCanBeFlattened() && STy &&
- STy->getNumElements() > 1) {
- auto SrcLayout = CGM.getDataLayout().getStructLayout(STy);
- uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(STy);
- llvm::Type *DstTy = Ptr.getElementType();
- uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(DstTy);
-
- Address AddrToStoreInto = Address::invalid();
- if (SrcSize <= DstSize) {
- AddrToStoreInto = Builder.CreateElementBitCast(Ptr, STy);
- } else {
- AddrToStoreInto =
- CreateTempAlloca(STy, Alloca.getAlignment(), "coerce");
- }
-
- assert(STy->getNumElements() == NumIRArgs);
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- auto AI = FnArgs[FirstIRArg + i];
- AI->setName(Arg->getName() + ".coerce" + Twine(i));
- auto Offset = CharUnits::fromQuantity(SrcLayout->getElementOffset(i));
- Address EltPtr =
- Builder.CreateStructGEP(AddrToStoreInto, i, Offset);
- Builder.CreateStore(AI, EltPtr);
- }
-
- if (SrcSize > DstSize) {
- Builder.CreateMemCpy(Ptr, AddrToStoreInto, DstSize);
- }
-
- } else {
- // Simple case, just do a coerced store of the argument into the alloca.
- assert(NumIRArgs == 1);
- auto AI = FnArgs[FirstIRArg];
- AI->setName(Arg->getName() + ".coerce");
- CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, *this);
- }
-
- // Match to what EmitParmDecl is expecting for this type.
- if (CodeGenFunction::hasScalarEvaluationKind(Ty)) {
- llvm::Value *V =
- EmitLoadOfScalar(Alloca, false, Ty, Arg->getBeginLoc());
- if (isPromoted)
- V = emitArgumentDemotion(*this, Arg, V);
- ArgVals.push_back(ParamValue::forDirect(V));
- } else {
- ArgVals.push_back(ParamValue::forIndirect(Alloca));
- }
- break;
- }
-
- case ABIArgInfo::CoerceAndExpand: {
- // Reconstruct into a temporary.
- Address alloca = CreateMemTemp(Ty, getContext().getDeclAlign(Arg));
- ArgVals.push_back(ParamValue::forIndirect(alloca));
-
- auto coercionType = ArgI.getCoerceAndExpandType();
- alloca = Builder.CreateElementBitCast(alloca, coercionType);
- auto layout = CGM.getDataLayout().getStructLayout(coercionType);
-
- unsigned argIndex = FirstIRArg;
- for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
- llvm::Type *eltType = coercionType->getElementType(i);
- if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType))
- continue;
-
- auto eltAddr = Builder.CreateStructGEP(alloca, i, layout);
- auto elt = FnArgs[argIndex++];
- Builder.CreateStore(elt, eltAddr);
- }
- assert(argIndex == FirstIRArg + NumIRArgs);
- break;
- }
-
- case ABIArgInfo::Expand: {
- // If this structure was expanded into multiple arguments then
- // we need to create a temporary and reconstruct it from the
- // arguments.
- Address Alloca = CreateMemTemp(Ty, getContext().getDeclAlign(Arg));
- LValue LV = MakeAddrLValue(Alloca, Ty);
- ArgVals.push_back(ParamValue::forIndirect(Alloca));
-
- auto FnArgIter = FnArgs.begin() + FirstIRArg;
- ExpandTypeFromArgs(Ty, LV, FnArgIter);
- assert(FnArgIter == FnArgs.begin() + FirstIRArg + NumIRArgs);
- for (unsigned i = 0, e = NumIRArgs; i != e; ++i) {
- auto AI = FnArgs[FirstIRArg + i];
- AI->setName(Arg->getName() + "." + Twine(i));
- }
- break;
- }
-
- case ABIArgInfo::Ignore:
- assert(NumIRArgs == 0);
- // Initialize the local variable appropriately.
- if (!hasScalarEvaluationKind(Ty)) {
- ArgVals.push_back(ParamValue::forIndirect(CreateMemTemp(Ty)));
- } else {
- llvm::Value *U = llvm::UndefValue::get(ConvertType(Arg->getType()));
- ArgVals.push_back(ParamValue::forDirect(U));
- }
- break;
- }
- }
-
- if (getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
- for (int I = Args.size() - 1; I >= 0; --I)
- EmitParmDecl(*Args[I], ArgVals[I], I + 1);
- } else {
- for (unsigned I = 0, E = Args.size(); I != E; ++I)
- EmitParmDecl(*Args[I], ArgVals[I], I + 1);
- }
-}
-
-static void eraseUnusedBitCasts(llvm::Instruction *insn) {
- while (insn->use_empty()) {
- llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(insn);
- if (!bitcast) return;
-
- // This is "safe" because we would have used a ConstantExpr otherwise.
- insn = cast<llvm::Instruction>(bitcast->getOperand(0));
- bitcast->eraseFromParent();
- }
-}
-
-/// Try to emit a fused autorelease of a return result.
-static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
- llvm::Value *result) {
- // We must be immediately followed the cast.
- llvm::BasicBlock *BB = CGF.Builder.GetInsertBlock();
- if (BB->empty()) return nullptr;
- if (&BB->back() != result) return nullptr;
-
- llvm::Type *resultType = result->getType();
-
- // result is in a BasicBlock and is therefore an Instruction.
- llvm::Instruction *generator = cast<llvm::Instruction>(result);
-
- SmallVector<llvm::Instruction *, 4> InstsToKill;
-
- // Look for:
- // %generator = bitcast %type1* %generator2 to %type2*
- while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(generator)) {
- // We would have emitted this as a constant if the operand weren't
- // an Instruction.
- generator = cast<llvm::Instruction>(bitcast->getOperand(0));
-
- // Require the generator to be immediately followed by the cast.
- if (generator->getNextNode() != bitcast)
- return nullptr;
-
- InstsToKill.push_back(bitcast);
- }
-
- // Look for:
- // %generator = call i8* @objc_retain(i8* %originalResult)
- // or
- // %generator = call i8* @objc_retainAutoreleasedReturnValue(i8* %originalResult)
- llvm::CallInst *call = dyn_cast<llvm::CallInst>(generator);
- if (!call) return nullptr;
-
- bool doRetainAutorelease;
-
- if (call->getCalledValue() == CGF.CGM.getObjCEntrypoints().objc_retain) {
- doRetainAutorelease = true;
- } else if (call->getCalledValue() == CGF.CGM.getObjCEntrypoints()
- .objc_retainAutoreleasedReturnValue) {
- doRetainAutorelease = false;
-
- // If we emitted an assembly marker for this call (and the
- // ARCEntrypoints field should have been set if so), go looking
- // for that call. If we can't find it, we can't do this
- // optimization. But it should always be the immediately previous
- // instruction, unless we needed bitcasts around the call.
- if (CGF.CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker) {
- llvm::Instruction *prev = call->getPrevNode();
- assert(prev);
- if (isa<llvm::BitCastInst>(prev)) {
- prev = prev->getPrevNode();
- assert(prev);
- }
- assert(isa<llvm::CallInst>(prev));
- assert(cast<llvm::CallInst>(prev)->getCalledValue() ==
- CGF.CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker);
- InstsToKill.push_back(prev);
- }
- } else {
- return nullptr;
- }
-
- result = call->getArgOperand(0);
- InstsToKill.push_back(call);
-
- // Keep killing bitcasts, for sanity. Note that we no longer care
- // about precise ordering as long as there's exactly one use.
- while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(result)) {
- if (!bitcast->hasOneUse()) break;
- InstsToKill.push_back(bitcast);
- result = bitcast->getOperand(0);
- }
-
- // Delete all the unnecessary instructions, from latest to earliest.
- for (auto *I : InstsToKill)
- I->eraseFromParent();
-
- // Do the fused retain/autorelease if we were asked to.
- if (doRetainAutorelease)
- result = CGF.EmitARCRetainAutoreleaseReturnValue(result);
-
- // Cast back to the result type.
- return CGF.Builder.CreateBitCast(result, resultType);
-}
-
-/// If this is a +1 of the value of an immutable 'self', remove it.
-static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF,
- llvm::Value *result) {
- // This is only applicable to a method with an immutable 'self'.
- const ObjCMethodDecl *method =
- dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl);
- if (!method) return nullptr;
- const VarDecl *self = method->getSelfDecl();
- if (!self->getType().isConstQualified()) return nullptr;
-
- // Look for a retain call.
- llvm::CallInst *retainCall =
- dyn_cast<llvm::CallInst>(result->stripPointerCasts());
- if (!retainCall ||
- retainCall->getCalledValue() != CGF.CGM.getObjCEntrypoints().objc_retain)
- return nullptr;
-
- // Look for an ordinary load of 'self'.
- llvm::Value *retainedValue = retainCall->getArgOperand(0);
- llvm::LoadInst *load =
- dyn_cast<llvm::LoadInst>(retainedValue->stripPointerCasts());
- if (!load || load->isAtomic() || load->isVolatile() ||
- load->getPointerOperand() != CGF.GetAddrOfLocalVar(self).getPointer())
- return nullptr;
-
- // Okay! Burn it all down. This relies for correctness on the
- // assumption that the retain is emitted as part of the return and
- // that thereafter everything is used "linearly".
- llvm::Type *resultType = result->getType();
- eraseUnusedBitCasts(cast<llvm::Instruction>(result));
- assert(retainCall->use_empty());
- retainCall->eraseFromParent();
- eraseUnusedBitCasts(cast<llvm::Instruction>(retainedValue));
-
- return CGF.Builder.CreateBitCast(load, resultType);
-}
-
-/// Emit an ARC autorelease of the result of a function.
-///
-/// \return the value to actually return from the function
-static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF,
- llvm::Value *result) {
- // If we're returning 'self', kill the initial retain. This is a
- // heuristic attempt to "encourage correctness" in the really unfortunate
- // case where we have a return of self during a dealloc and we desperately
- // need to avoid the possible autorelease.
- if (llvm::Value *self = tryRemoveRetainOfSelf(CGF, result))
- return self;
-
- // At -O0, try to emit a fused retain/autorelease.
- if (CGF.shouldUseFusedARCCalls())
- if (llvm::Value *fused = tryEmitFusedAutoreleaseOfResult(CGF, result))
- return fused;
-
- return CGF.EmitARCAutoreleaseReturnValue(result);
-}
-
-/// Heuristically search for a dominating store to the return-value slot.
-static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
- // Check if a User is a store which pointerOperand is the ReturnValue.
- // We are looking for stores to the ReturnValue, not for stores of the
- // ReturnValue to some other location.
- auto GetStoreIfValid = [&CGF](llvm::User *U) -> llvm::StoreInst * {
- auto *SI = dyn_cast<llvm::StoreInst>(U);
- if (!SI || SI->getPointerOperand() != CGF.ReturnValue.getPointer())
- return nullptr;
- // These aren't actually possible for non-coerced returns, and we
- // only care about non-coerced returns on this code path.
- assert(!SI->isAtomic() && !SI->isVolatile());
- return SI;
- };
- // If there are multiple uses of the return-value slot, just check
- // for something immediately preceding the IP. Sometimes this can
- // happen with how we generate implicit-returns; it can also happen
- // with noreturn cleanups.
- if (!CGF.ReturnValue.getPointer()->hasOneUse()) {
- llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
- if (IP->empty()) return nullptr;
- llvm::Instruction *I = &IP->back();
-
- // Skip lifetime markers
- for (llvm::BasicBlock::reverse_iterator II = IP->rbegin(),
- IE = IP->rend();
- II != IE; ++II) {
- if (llvm::IntrinsicInst *Intrinsic =
- dyn_cast<llvm::IntrinsicInst>(&*II)) {
- if (Intrinsic->getIntrinsicID() == llvm::Intrinsic::lifetime_end) {
- const llvm::Value *CastAddr = Intrinsic->getArgOperand(1);
- ++II;
- if (II == IE)
- break;
- if (isa<llvm::BitCastInst>(&*II) && (CastAddr == &*II))
- continue;
- }
- }
- I = &*II;
- break;
- }
-
- return GetStoreIfValid(I);
- }
-
- llvm::StoreInst *store =
- GetStoreIfValid(CGF.ReturnValue.getPointer()->user_back());
- if (!store) return nullptr;
-
- // Now do a first-and-dirty dominance check: just walk up the
- // single-predecessors chain from the current insertion point.
- llvm::BasicBlock *StoreBB = store->getParent();
- llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
- while (IP != StoreBB) {
- if (!(IP = IP->getSinglePredecessor()))
- return nullptr;
- }
-
- // Okay, the store's basic block dominates the insertion point; we
- // can do our thing.
- return store;
-}
-
-void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
- bool EmitRetDbgLoc,
- SourceLocation EndLoc) {
- if (FI.isNoReturn()) {
- // Noreturn functions don't return.
- EmitUnreachable(EndLoc);
- return;
- }
-
- if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>()) {
- // Naked functions don't have epilogues.
- Builder.CreateUnreachable();
- return;
- }
-
- // Functions with no result always return void.
- if (!ReturnValue.isValid()) {
- Builder.CreateRetVoid();
- return;
- }
-
- llvm::DebugLoc RetDbgLoc;
- llvm::Value *RV = nullptr;
- QualType RetTy = FI.getReturnType();
- const ABIArgInfo &RetAI = FI.getReturnInfo();
-
- switch (RetAI.getKind()) {
- case ABIArgInfo::InAlloca:
- // Aggregrates get evaluated directly into the destination. Sometimes we
- // need to return the sret value in a register, though.
- assert(hasAggregateEvaluationKind(RetTy));
- if (RetAI.getInAllocaSRet()) {
- llvm::Function::arg_iterator EI = CurFn->arg_end();
- --EI;
- llvm::Value *ArgStruct = &*EI;
- llvm::Value *SRet = Builder.CreateStructGEP(
- nullptr, ArgStruct, RetAI.getInAllocaFieldIndex());
- RV = Builder.CreateAlignedLoad(SRet, getPointerAlign(), "sret");
- }
- break;
-
- case ABIArgInfo::Indirect: {
- auto AI = CurFn->arg_begin();
- if (RetAI.isSRetAfterThis())
- ++AI;
- switch (getEvaluationKind(RetTy)) {
- case TEK_Complex: {
- ComplexPairTy RT =
- EmitLoadOfComplex(MakeAddrLValue(ReturnValue, RetTy), EndLoc);
- EmitStoreOfComplex(RT, MakeNaturalAlignAddrLValue(&*AI, RetTy),
- /*isInit*/ true);
- break;
- }
- case TEK_Aggregate:
- // Do nothing; aggregrates get evaluated directly into the destination.
- break;
- case TEK_Scalar:
- EmitStoreOfScalar(Builder.CreateLoad(ReturnValue),
- MakeNaturalAlignAddrLValue(&*AI, RetTy),
- /*isInit*/ true);
- break;
- }
- break;
- }
-
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct:
- if (RetAI.getCoerceToType() == ConvertType(RetTy) &&
- RetAI.getDirectOffset() == 0) {
- // The internal return value temp always will have pointer-to-return-type
- // type, just do a load.
-
- // If there is a dominating store to ReturnValue, we can elide
- // the load, zap the store, and usually zap the alloca.
- if (llvm::StoreInst *SI =
- findDominatingStoreToReturnValue(*this)) {
- // Reuse the debug location from the store unless there is
- // cleanup code to be emitted between the store and return
- // instruction.
- if (EmitRetDbgLoc && !AutoreleaseResult)
- RetDbgLoc = SI->getDebugLoc();
- // Get the stored value and nuke the now-dead store.
- RV = SI->getValueOperand();
- SI->eraseFromParent();
-
- // If that was the only use of the return value, nuke it as well now.
- auto returnValueInst = ReturnValue.getPointer();
- if (returnValueInst->use_empty()) {
- if (auto alloca = dyn_cast<llvm::AllocaInst>(returnValueInst)) {
- alloca->eraseFromParent();
- ReturnValue = Address::invalid();
- }
- }
-
- // Otherwise, we have to do a simple load.
- } else {
- RV = Builder.CreateLoad(ReturnValue);
- }
- } else {
- // If the value is offset in memory, apply the offset now.
- Address V = emitAddressAtOffset(*this, ReturnValue, RetAI);
-
- RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
- }
-
- // In ARC, end functions that return a retainable type with a call
- // to objc_autoreleaseReturnValue.
- if (AutoreleaseResult) {
-#ifndef NDEBUG
- // Type::isObjCRetainabletype has to be called on a QualType that hasn't
- // been stripped of the typedefs, so we cannot use RetTy here. Get the
- // original return type of FunctionDecl, CurCodeDecl, and BlockDecl from
- // CurCodeDecl or BlockInfo.
- QualType RT;
-
- if (auto *FD = dyn_cast<FunctionDecl>(CurCodeDecl))
- RT = FD->getReturnType();
- else if (auto *MD = dyn_cast<ObjCMethodDecl>(CurCodeDecl))
- RT = MD->getReturnType();
- else if (isa<BlockDecl>(CurCodeDecl))
- RT = BlockInfo->BlockExpression->getFunctionType()->getReturnType();
- else
- llvm_unreachable("Unexpected function/method type");
-
- assert(getLangOpts().ObjCAutoRefCount &&
- !FI.isReturnsRetained() &&
- RT->isObjCRetainableType());
-#endif
- RV = emitAutoreleaseOfResult(*this, RV);
- }
-
- break;
-
- case ABIArgInfo::Ignore:
- break;
-
- case ABIArgInfo::CoerceAndExpand: {
- auto coercionType = RetAI.getCoerceAndExpandType();
- auto layout = CGM.getDataLayout().getStructLayout(coercionType);
-
- // Load all of the coerced elements out into results.
- llvm::SmallVector<llvm::Value*, 4> results;
- Address addr = Builder.CreateElementBitCast(ReturnValue, coercionType);
- for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
- auto coercedEltType = coercionType->getElementType(i);
- if (ABIArgInfo::isPaddingForCoerceAndExpand(coercedEltType))
- continue;
-
- auto eltAddr = Builder.CreateStructGEP(addr, i, layout);
- auto elt = Builder.CreateLoad(eltAddr);
- results.push_back(elt);
- }
-
- // If we have one result, it's the single direct result type.
- if (results.size() == 1) {
- RV = results[0];
-
- // Otherwise, we need to make a first-class aggregate.
- } else {
- // Construct a return type that lacks padding elements.
- llvm::Type *returnType = RetAI.getUnpaddedCoerceAndExpandType();
-
- RV = llvm::UndefValue::get(returnType);
- for (unsigned i = 0, e = results.size(); i != e; ++i) {
- RV = Builder.CreateInsertValue(RV, results[i], i);
- }
- }
- break;
- }
-
- case ABIArgInfo::Expand:
- llvm_unreachable("Invalid ABI kind for return argument");
- }
-
- llvm::Instruction *Ret;
- if (RV) {
- EmitReturnValueCheck(RV);
- Ret = Builder.CreateRet(RV);
- } else {
- Ret = Builder.CreateRetVoid();
- }
-
- if (RetDbgLoc)
- Ret->setDebugLoc(std::move(RetDbgLoc));
-}
-
-void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) {
- // A current decl may not be available when emitting vtable thunks.
- if (!CurCodeDecl)
- return;
-
- ReturnsNonNullAttr *RetNNAttr = nullptr;
- if (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute))
- RetNNAttr = CurCodeDecl->getAttr<ReturnsNonNullAttr>();
-
- if (!RetNNAttr && !requiresReturnValueNullabilityCheck())
- return;
-
- // Prefer the returns_nonnull attribute if it's present.
- SourceLocation AttrLoc;
- SanitizerMask CheckKind;
- SanitizerHandler Handler;
- if (RetNNAttr) {
- assert(!requiresReturnValueNullabilityCheck() &&
- "Cannot check nullability and the nonnull attribute");
- AttrLoc = RetNNAttr->getLocation();
- CheckKind = SanitizerKind::ReturnsNonnullAttribute;
- Handler = SanitizerHandler::NonnullReturn;
- } else {
- if (auto *DD = dyn_cast<DeclaratorDecl>(CurCodeDecl))
- if (auto *TSI = DD->getTypeSourceInfo())
- if (auto FTL = TSI->getTypeLoc().castAs<FunctionTypeLoc>())
- AttrLoc = FTL.getReturnLoc().findNullabilityLoc();
- CheckKind = SanitizerKind::NullabilityReturn;
- Handler = SanitizerHandler::NullabilityReturn;
- }
-
- SanitizerScope SanScope(this);
-
- // Make sure the "return" source location is valid. If we're checking a
- // nullability annotation, make sure the preconditions for the check are met.
- llvm::BasicBlock *Check = createBasicBlock("nullcheck");
- llvm::BasicBlock *NoCheck = createBasicBlock("no.nullcheck");
- llvm::Value *SLocPtr = Builder.CreateLoad(ReturnLocation, "return.sloc.load");
- llvm::Value *CanNullCheck = Builder.CreateIsNotNull(SLocPtr);
- if (requiresReturnValueNullabilityCheck())
- CanNullCheck =
- Builder.CreateAnd(CanNullCheck, RetValNullabilityPrecondition);
- Builder.CreateCondBr(CanNullCheck, Check, NoCheck);
- EmitBlock(Check);
-
- // Now do the null check.
- llvm::Value *Cond = Builder.CreateIsNotNull(RV);
- llvm::Constant *StaticData[] = {EmitCheckSourceLocation(AttrLoc)};
- llvm::Value *DynamicData[] = {SLocPtr};
- EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, DynamicData);
-
- EmitBlock(NoCheck);
-
-#ifndef NDEBUG
- // The return location should not be used after the check has been emitted.
- ReturnLocation = Address::invalid();
-#endif
-}
-
-static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) {
- const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
- return RD && ABI.getRecordArgABI(RD) == CGCXXABI::RAA_DirectInMemory;
-}
-
-static AggValueSlot createPlaceholderSlot(CodeGenFunction &CGF,
- QualType Ty) {
- // FIXME: Generate IR in one pass, rather than going back and fixing up these
- // placeholders.
- llvm::Type *IRTy = CGF.ConvertTypeForMem(Ty);
- llvm::Type *IRPtrTy = IRTy->getPointerTo();
- llvm::Value *Placeholder = llvm::UndefValue::get(IRPtrTy->getPointerTo());
-
- // FIXME: When we generate this IR in one pass, we shouldn't need
- // this win32-specific alignment hack.
- CharUnits Align = CharUnits::fromQuantity(4);
- Placeholder = CGF.Builder.CreateAlignedLoad(IRPtrTy, Placeholder, Align);
-
- return AggValueSlot::forAddr(Address(Placeholder, Align),
- Ty.getQualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap);
-}
-
-void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
- const VarDecl *param,
- SourceLocation loc) {
- // StartFunction converted the ABI-lowered parameter(s) into a
- // local alloca. We need to turn that into an r-value suitable
- // for EmitCall.
- Address local = GetAddrOfLocalVar(param);
-
- QualType type = param->getType();
-
- if (isInAllocaArgument(CGM.getCXXABI(), type)) {
- CGM.ErrorUnsupported(param, "forwarded non-trivially copyable parameter");
- }
-
- // GetAddrOfLocalVar returns a pointer-to-pointer for references,
- // but the argument needs to be the original pointer.
- if (type->isReferenceType()) {
- args.add(RValue::get(Builder.CreateLoad(local)), type);
-
- // In ARC, move out of consumed arguments so that the release cleanup
- // entered by StartFunction doesn't cause an over-release. This isn't
- // optimal -O0 code generation, but it should get cleaned up when
- // optimization is enabled. This also assumes that delegate calls are
- // performed exactly once for a set of arguments, but that should be safe.
- } else if (getLangOpts().ObjCAutoRefCount &&
- param->hasAttr<NSConsumedAttr>() &&
- type->isObjCRetainableType()) {
- llvm::Value *ptr = Builder.CreateLoad(local);
- auto null =
- llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ptr->getType()));
- Builder.CreateStore(null, local);
- args.add(RValue::get(ptr), type);
-
- // For the most part, we just need to load the alloca, except that
- // aggregate r-values are actually pointers to temporaries.
- } else {
- args.add(convertTempToRValue(local, type, loc), type);
- }
-
- // Deactivate the cleanup for the callee-destructed param that was pushed.
- if (hasAggregateEvaluationKind(type) && !CurFuncIsThunk &&
- type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee() &&
- type.isDestructedType()) {
- EHScopeStack::stable_iterator cleanup =
- CalleeDestructedParamCleanups.lookup(cast<ParmVarDecl>(param));
- assert(cleanup.isValid() &&
- "cleanup for callee-destructed param not recorded");
- // This unreachable is a temporary marker which will be removed later.
- llvm::Instruction *isActive = Builder.CreateUnreachable();
- args.addArgCleanupDeactivation(cleanup, isActive);
- }
-}
-
-static bool isProvablyNull(llvm::Value *addr) {
- return isa<llvm::ConstantPointerNull>(addr);
-}
-
-/// Emit the actual writing-back of a writeback.
-static void emitWriteback(CodeGenFunction &CGF,
- const CallArgList::Writeback &writeback) {
- const LValue &srcLV = writeback.Source;
- Address srcAddr = srcLV.getAddress();
- assert(!isProvablyNull(srcAddr.getPointer()) &&
- "shouldn't have writeback for provably null argument");
-
- llvm::BasicBlock *contBB = nullptr;
-
- // If the argument wasn't provably non-null, we need to null check
- // before doing the store.
- bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(),
- CGF.CGM.getDataLayout());
- if (!provablyNonNull) {
- llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback");
- contBB = CGF.createBasicBlock("icr.done");
-
- llvm::Value *isNull =
- CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull");
- CGF.Builder.CreateCondBr(isNull, contBB, writebackBB);
- CGF.EmitBlock(writebackBB);
- }
-
- // Load the value to writeback.
- llvm::Value *value = CGF.Builder.CreateLoad(writeback.Temporary);
-
- // Cast it back, in case we're writing an id to a Foo* or something.
- value = CGF.Builder.CreateBitCast(value, srcAddr.getElementType(),
- "icr.writeback-cast");
-
- // Perform the writeback.
-
- // If we have a "to use" value, it's something we need to emit a use
- // of. This has to be carefully threaded in: if it's done after the
- // release it's potentially undefined behavior (and the optimizer
- // will ignore it), and if it happens before the retain then the
- // optimizer could move the release there.
- if (writeback.ToUse) {
- assert(srcLV.getObjCLifetime() == Qualifiers::OCL_Strong);
-
- // Retain the new value. No need to block-copy here: the block's
- // being passed up the stack.
- value = CGF.EmitARCRetainNonBlock(value);
-
- // Emit the intrinsic use here.
- CGF.EmitARCIntrinsicUse(writeback.ToUse);
-
- // Load the old value (primitively).
- llvm::Value *oldValue = CGF.EmitLoadOfScalar(srcLV, SourceLocation());
-
- // Put the new value in place (primitively).
- CGF.EmitStoreOfScalar(value, srcLV, /*init*/ false);
-
- // Release the old value.
- CGF.EmitARCRelease(oldValue, srcLV.isARCPreciseLifetime());
-
- // Otherwise, we can just do a normal lvalue store.
- } else {
- CGF.EmitStoreThroughLValue(RValue::get(value), srcLV);
- }
-
- // Jump to the continuation block.
- if (!provablyNonNull)
- CGF.EmitBlock(contBB);
-}
-
-static void emitWritebacks(CodeGenFunction &CGF,
- const CallArgList &args) {
- for (const auto &I : args.writebacks())
- emitWriteback(CGF, I);
-}
-
-static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF,
- const CallArgList &CallArgs) {
- ArrayRef<CallArgList::CallArgCleanup> Cleanups =
- CallArgs.getCleanupsToDeactivate();
- // Iterate in reverse to increase the likelihood of popping the cleanup.
- for (const auto &I : llvm::reverse(Cleanups)) {
- CGF.DeactivateCleanupBlock(I.Cleanup, I.IsActiveIP);
- I.IsActiveIP->eraseFromParent();
- }
-}
-
-static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) {
- if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens()))
- if (uop->getOpcode() == UO_AddrOf)
- return uop->getSubExpr();
- return nullptr;
-}
-
-/// Emit an argument that's being passed call-by-writeback. That is,
-/// we are passing the address of an __autoreleased temporary; it
-/// might be copy-initialized with the current value of the given
-/// address, but it will definitely be copied out of after the call.
-static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
- const ObjCIndirectCopyRestoreExpr *CRE) {
- LValue srcLV;
-
- // Make an optimistic effort to emit the address as an l-value.
- // This can fail if the argument expression is more complicated.
- if (const Expr *lvExpr = maybeGetUnaryAddrOfOperand(CRE->getSubExpr())) {
- srcLV = CGF.EmitLValue(lvExpr);
-
- // Otherwise, just emit it as a scalar.
- } else {
- Address srcAddr = CGF.EmitPointerWithAlignment(CRE->getSubExpr());
-
- QualType srcAddrType =
- CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
- srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
- }
- Address srcAddr = srcLV.getAddress();
-
- // The dest and src types don't necessarily match in LLVM terms
- // because of the crazy ObjC compatibility rules.
-
- llvm::PointerType *destType =
- cast<llvm::PointerType>(CGF.ConvertType(CRE->getType()));
-
- // If the address is a constant null, just pass the appropriate null.
- if (isProvablyNull(srcAddr.getPointer())) {
- args.add(RValue::get(llvm::ConstantPointerNull::get(destType)),
- CRE->getType());
- return;
- }
-
- // Create the temporary.
- Address temp = CGF.CreateTempAlloca(destType->getElementType(),
- CGF.getPointerAlign(),
- "icr.temp");
- // Loading an l-value can introduce a cleanup if the l-value is __weak,
- // and that cleanup will be conditional if we can't prove that the l-value
- // isn't null, so we need to register a dominating point so that the cleanups
- // system will make valid IR.
- CodeGenFunction::ConditionalEvaluation condEval(CGF);
-
- // Zero-initialize it if we're not doing a copy-initialization.
- bool shouldCopy = CRE->shouldCopy();
- if (!shouldCopy) {
- llvm::Value *null =
- llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(destType->getElementType()));
- CGF.Builder.CreateStore(null, temp);
- }
-
- llvm::BasicBlock *contBB = nullptr;
- llvm::BasicBlock *originBB = nullptr;
-
- // If the address is *not* known to be non-null, we need to switch.
- llvm::Value *finalArgument;
-
- bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(),
- CGF.CGM.getDataLayout());
- if (provablyNonNull) {
- finalArgument = temp.getPointer();
- } else {
- llvm::Value *isNull =
- CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull");
-
- finalArgument = CGF.Builder.CreateSelect(isNull,
- llvm::ConstantPointerNull::get(destType),
- temp.getPointer(), "icr.argument");
-
- // If we need to copy, then the load has to be conditional, which
- // means we need control flow.
- if (shouldCopy) {
- originBB = CGF.Builder.GetInsertBlock();
- contBB = CGF.createBasicBlock("icr.cont");
- llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy");
- CGF.Builder.CreateCondBr(isNull, contBB, copyBB);
- CGF.EmitBlock(copyBB);
- condEval.begin(CGF);
- }
- }
-
- llvm::Value *valueToUse = nullptr;
-
- // Perform a copy if necessary.
- if (shouldCopy) {
- RValue srcRV = CGF.EmitLoadOfLValue(srcLV, SourceLocation());
- assert(srcRV.isScalar());
-
- llvm::Value *src = srcRV.getScalarVal();
- src = CGF.Builder.CreateBitCast(src, destType->getElementType(),
- "icr.cast");
-
- // Use an ordinary store, not a store-to-lvalue.
- CGF.Builder.CreateStore(src, temp);
-
- // If optimization is enabled, and the value was held in a
- // __strong variable, we need to tell the optimizer that this
- // value has to stay alive until we're doing the store back.
- // This is because the temporary is effectively unretained,
- // and so otherwise we can violate the high-level semantics.
- if (CGF.CGM.getCodeGenOpts().OptimizationLevel != 0 &&
- srcLV.getObjCLifetime() == Qualifiers::OCL_Strong) {
- valueToUse = src;
- }
- }
-
- // Finish the control flow if we needed it.
- if (shouldCopy && !provablyNonNull) {
- llvm::BasicBlock *copyBB = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(contBB);
-
- // Make a phi for the value to intrinsically use.
- if (valueToUse) {
- llvm::PHINode *phiToUse = CGF.Builder.CreatePHI(valueToUse->getType(), 2,
- "icr.to-use");
- phiToUse->addIncoming(valueToUse, copyBB);
- phiToUse->addIncoming(llvm::UndefValue::get(valueToUse->getType()),
- originBB);
- valueToUse = phiToUse;
- }
-
- condEval.end(CGF);
- }
-
- args.addWriteback(srcLV, temp, valueToUse);
- args.add(RValue::get(finalArgument), CRE->getType());
-}
-
-void CallArgList::allocateArgumentMemory(CodeGenFunction &CGF) {
- assert(!StackBase);
-
- // Save the stack.
- llvm::Function *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stacksave);
- StackBase = CGF.Builder.CreateCall(F, {}, "inalloca.save");
-}
-
-void CallArgList::freeArgumentMemory(CodeGenFunction &CGF) const {
- if (StackBase) {
- // Restore the stack after the call.
- llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
- CGF.Builder.CreateCall(F, StackBase);
- }
-}
-
-void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
- SourceLocation ArgLoc,
- AbstractCallee AC,
- unsigned ParmNum) {
- if (!AC.getDecl() || !(SanOpts.has(SanitizerKind::NonnullAttribute) ||
- SanOpts.has(SanitizerKind::NullabilityArg)))
- return;
-
- // The param decl may be missing in a variadic function.
- auto PVD = ParmNum < AC.getNumParams() ? AC.getParamDecl(ParmNum) : nullptr;
- unsigned ArgNo = PVD ? PVD->getFunctionScopeIndex() : ParmNum;
-
- // Prefer the nonnull attribute if it's present.
- const NonNullAttr *NNAttr = nullptr;
- if (SanOpts.has(SanitizerKind::NonnullAttribute))
- NNAttr = getNonNullAttr(AC.getDecl(), PVD, ArgType, ArgNo);
-
- bool CanCheckNullability = false;
- if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD) {
- auto Nullability = PVD->getType()->getNullability(getContext());
- CanCheckNullability = Nullability &&
- *Nullability == NullabilityKind::NonNull &&
- PVD->getTypeSourceInfo();
- }
-
- if (!NNAttr && !CanCheckNullability)
- return;
-
- SourceLocation AttrLoc;
- SanitizerMask CheckKind;
- SanitizerHandler Handler;
- if (NNAttr) {
- AttrLoc = NNAttr->getLocation();
- CheckKind = SanitizerKind::NonnullAttribute;
- Handler = SanitizerHandler::NonnullArg;
- } else {
- AttrLoc = PVD->getTypeSourceInfo()->getTypeLoc().findNullabilityLoc();
- CheckKind = SanitizerKind::NullabilityArg;
- Handler = SanitizerHandler::NullabilityArg;
- }
-
- SanitizerScope SanScope(this);
- assert(RV.isScalar());
- llvm::Value *V = RV.getScalarVal();
- llvm::Value *Cond =
- Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType()));
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(ArgLoc), EmitCheckSourceLocation(AttrLoc),
- llvm::ConstantInt::get(Int32Ty, ArgNo + 1),
- };
- EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
-}
-
-void CodeGenFunction::EmitCallArgs(
- CallArgList &Args, ArrayRef<QualType> ArgTypes,
- llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
- AbstractCallee AC, unsigned ParamsToSkip, EvaluationOrder Order) {
- assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin()));
-
- // We *have* to evaluate arguments from right to left in the MS C++ ABI,
- // because arguments are destroyed left to right in the callee. As a special
- // case, there are certain language constructs that require left-to-right
- // evaluation, and in those cases we consider the evaluation order requirement
- // to trump the "destruction order is reverse construction order" guarantee.
- bool LeftToRight =
- CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()
- ? Order == EvaluationOrder::ForceLeftToRight
- : Order != EvaluationOrder::ForceRightToLeft;
-
- auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg,
- RValue EmittedArg) {
- if (!AC.hasFunctionDecl() || I >= AC.getNumParams())
- return;
- auto *PS = AC.getParamDecl(I)->getAttr<PassObjectSizeAttr>();
- if (PS == nullptr)
- return;
-
- const auto &Context = getContext();
- auto SizeTy = Context.getSizeType();
- auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
- assert(EmittedArg.getScalarVal() && "We emitted nothing for the arg?");
- llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, PS->getType(), T,
- EmittedArg.getScalarVal());
- Args.add(RValue::get(V), SizeTy);
- // If we're emitting args in reverse, be sure to do so with
- // pass_object_size, as well.
- if (!LeftToRight)
- std::swap(Args.back(), *(&Args.back() - 1));
- };
-
- // Insert a stack save if we're going to need any inalloca args.
- bool HasInAllocaArgs = false;
- if (CGM.getTarget().getCXXABI().isMicrosoft()) {
- for (ArrayRef<QualType>::iterator I = ArgTypes.begin(), E = ArgTypes.end();
- I != E && !HasInAllocaArgs; ++I)
- HasInAllocaArgs = isInAllocaArgument(CGM.getCXXABI(), *I);
- if (HasInAllocaArgs) {
- assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
- Args.allocateArgumentMemory(*this);
- }
- }
-
- // Evaluate each argument in the appropriate order.
- size_t CallArgsStart = Args.size();
- for (unsigned I = 0, E = ArgTypes.size(); I != E; ++I) {
- unsigned Idx = LeftToRight ? I : E - I - 1;
- CallExpr::const_arg_iterator Arg = ArgRange.begin() + Idx;
- unsigned InitialArgSize = Args.size();
- // If *Arg is an ObjCIndirectCopyRestoreExpr, check that either the types of
- // the argument and parameter match or the objc method is parameterized.
- assert((!isa<ObjCIndirectCopyRestoreExpr>(*Arg) ||
- getContext().hasSameUnqualifiedType((*Arg)->getType(),
- ArgTypes[Idx]) ||
- (isa<ObjCMethodDecl>(AC.getDecl()) &&
- isObjCMethodWithTypeParams(cast<ObjCMethodDecl>(AC.getDecl())))) &&
- "Argument and parameter types don't match");
- EmitCallArg(Args, *Arg, ArgTypes[Idx]);
- // In particular, we depend on it being the last arg in Args, and the
- // objectsize bits depend on there only being one arg if !LeftToRight.
- assert(InitialArgSize + 1 == Args.size() &&
- "The code below depends on only adding one arg per EmitCallArg");
- (void)InitialArgSize;
- // Since pointer argument are never emitted as LValue, it is safe to emit
- // non-null argument check for r-value only.
- if (!Args.back().hasLValue()) {
- RValue RVArg = Args.back().getKnownRValue();
- EmitNonNullArgCheck(RVArg, ArgTypes[Idx], (*Arg)->getExprLoc(), AC,
- ParamsToSkip + Idx);
- // @llvm.objectsize should never have side-effects and shouldn't need
- // destruction/cleanups, so we can safely "emit" it after its arg,
- // regardless of right-to-leftness
- MaybeEmitImplicitObjectSize(Idx, *Arg, RVArg);
- }
- }
-
- if (!LeftToRight) {
- // Un-reverse the arguments we just evaluated so they match up with the LLVM
- // IR function.
- std::reverse(Args.begin() + CallArgsStart, Args.end());
- }
-}
-
-namespace {
-
-struct DestroyUnpassedArg final : EHScopeStack::Cleanup {
- DestroyUnpassedArg(Address Addr, QualType Ty)
- : Addr(Addr), Ty(Ty) {}
-
- Address Addr;
- QualType Ty;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- QualType::DestructionKind DtorKind = Ty.isDestructedType();
- if (DtorKind == QualType::DK_cxx_destructor) {
- const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
- assert(!Dtor->isTrivial());
- CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false,
- /*Delegating=*/false, Addr);
- } else {
- CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Ty));
- }
- }
-};
-
-struct DisableDebugLocationUpdates {
- CodeGenFunction &CGF;
- bool disabledDebugInfo;
- DisableDebugLocationUpdates(CodeGenFunction &CGF, const Expr *E) : CGF(CGF) {
- if ((disabledDebugInfo = isa<CXXDefaultArgExpr>(E) && CGF.getDebugInfo()))
- CGF.disableDebugInfo();
- }
- ~DisableDebugLocationUpdates() {
- if (disabledDebugInfo)
- CGF.enableDebugInfo();
- }
-};
-
-} // end anonymous namespace
-
-RValue CallArg::getRValue(CodeGenFunction &CGF) const {
- if (!HasLV)
- return RV;
- LValue Copy = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty), Ty);
- CGF.EmitAggregateCopy(Copy, LV, Ty, AggValueSlot::DoesNotOverlap,
- LV.isVolatile());
- IsUsed = true;
- return RValue::getAggregate(Copy.getAddress());
-}
-
-void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const {
- LValue Dst = CGF.MakeAddrLValue(Addr, Ty);
- if (!HasLV && RV.isScalar())
- CGF.EmitStoreOfScalar(RV.getScalarVal(), Dst, /*init=*/true);
- else if (!HasLV && RV.isComplex())
- CGF.EmitStoreOfComplex(RV.getComplexVal(), Dst, /*init=*/true);
- else {
- auto Addr = HasLV ? LV.getAddress() : RV.getAggregateAddress();
- LValue SrcLV = CGF.MakeAddrLValue(Addr, Ty);
- // We assume that call args are never copied into subobjects.
- CGF.EmitAggregateCopy(Dst, SrcLV, Ty, AggValueSlot::DoesNotOverlap,
- HasLV ? LV.isVolatileQualified()
- : RV.isVolatileQualified());
- }
- IsUsed = true;
-}
-
-void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
- QualType type) {
- DisableDebugLocationUpdates Dis(*this, E);
- if (const ObjCIndirectCopyRestoreExpr *CRE
- = dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
- assert(getLangOpts().ObjCAutoRefCount);
- return emitWritebackArg(*this, args, CRE);
- }
-
- assert(type->isReferenceType() == E->isGLValue() &&
- "reference binding to unmaterialized r-value!");
-
- if (E->isGLValue()) {
- assert(E->getObjectKind() == OK_Ordinary);
- return args.add(EmitReferenceBindingToExpr(E), type);
- }
-
- bool HasAggregateEvalKind = hasAggregateEvaluationKind(type);
-
- // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
- // However, we still have to push an EH-only cleanup in case we unwind before
- // we make it to the call.
- if (HasAggregateEvalKind &&
- type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
- // If we're using inalloca, use the argument memory. Otherwise, use a
- // temporary.
- AggValueSlot Slot;
- if (args.isUsingInAlloca())
- Slot = createPlaceholderSlot(*this, type);
- else
- Slot = CreateAggTemp(type, "agg.tmp");
-
- bool DestroyedInCallee = true, NeedsEHCleanup = true;
- if (const auto *RD = type->getAsCXXRecordDecl())
- DestroyedInCallee = RD->hasNonTrivialDestructor();
- else
- NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
-
- if (DestroyedInCallee)
- Slot.setExternallyDestructed();
-
- EmitAggExpr(E, Slot);
- RValue RV = Slot.asRValue();
- args.add(RV, type);
-
- if (DestroyedInCallee && NeedsEHCleanup) {
- // Create a no-op GEP between the placeholder and the cleanup so we can
- // RAUW it successfully. It also serves as a marker of the first
- // instruction where the cleanup is active.
- pushFullExprCleanup<DestroyUnpassedArg>(EHCleanup, Slot.getAddress(),
- type);
- // This unreachable is a temporary marker which will be removed later.
- llvm::Instruction *IsActive = Builder.CreateUnreachable();
- args.addArgCleanupDeactivation(EHStack.getInnermostEHScope(), IsActive);
- }
- return;
- }
-
- if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
- cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
- LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
- assert(L.isSimple());
- args.addUncopiedAggregate(L, type);
- return;
- }
-
- args.add(EmitAnyExprToTemp(E), type);
-}
-
-QualType CodeGenFunction::getVarArgType(const Expr *Arg) {
- // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC
- // implicitly widens null pointer constants that are arguments to varargs
- // functions to pointer-sized ints.
- if (!getTarget().getTriple().isOSWindows())
- return Arg->getType();
-
- if (Arg->getType()->isIntegerType() &&
- getContext().getTypeSize(Arg->getType()) <
- getContext().getTargetInfo().getPointerWidth(0) &&
- Arg->isNullPointerConstant(getContext(),
- Expr::NPC_ValueDependentIsNotNull)) {
- return getContext().getIntPtrType();
- }
-
- return Arg->getType();
-}
-
-// In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
-// optimizer it can aggressively ignore unwind edges.
-void
-CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
- if (CGM.getCodeGenOpts().OptimizationLevel != 0 &&
- !CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
- Inst->setMetadata("clang.arc.no_objc_arc_exceptions",
- CGM.getNoObjCARCExceptionsMetadata());
-}
-
-/// Emits a call to the given no-arguments nounwind runtime function.
-llvm::CallInst *
-CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
- const llvm::Twine &name) {
- return EmitNounwindRuntimeCall(callee, None, name);
-}
-
-/// Emits a call to the given nounwind runtime function.
-llvm::CallInst *
-CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
- ArrayRef<llvm::Value*> args,
- const llvm::Twine &name) {
- llvm::CallInst *call = EmitRuntimeCall(callee, args, name);
- call->setDoesNotThrow();
- return call;
-}
-
-/// Emits a simple call (never an invoke) to the given no-arguments
-/// runtime function.
-llvm::CallInst *
-CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
- const llvm::Twine &name) {
- return EmitRuntimeCall(callee, None, name);
-}
-
-// Calls which may throw must have operand bundles indicating which funclet
-// they are nested within.
-SmallVector<llvm::OperandBundleDef, 1>
-CodeGenFunction::getBundlesForFunclet(llvm::Value *Callee) {
- SmallVector<llvm::OperandBundleDef, 1> BundleList;
- // There is no need for a funclet operand bundle if we aren't inside a
- // funclet.
- if (!CurrentFuncletPad)
- return BundleList;
-
- // Skip intrinsics which cannot throw.
- auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts());
- if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow())
- return BundleList;
-
- BundleList.emplace_back("funclet", CurrentFuncletPad);
- return BundleList;
-}
-
-/// Emits a simple call (never an invoke) to the given runtime function.
-llvm::CallInst *
-CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
- ArrayRef<llvm::Value*> args,
- const llvm::Twine &name) {
- llvm::CallInst *call =
- Builder.CreateCall(callee, args, getBundlesForFunclet(callee), name);
- call->setCallingConv(getRuntimeCC());
- return call;
-}
-
-/// Emits a call or invoke to the given noreturn runtime function.
-void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
- ArrayRef<llvm::Value*> args) {
- SmallVector<llvm::OperandBundleDef, 1> BundleList =
- getBundlesForFunclet(callee);
-
- if (getInvokeDest()) {
- llvm::InvokeInst *invoke =
- Builder.CreateInvoke(callee,
- getUnreachableBlock(),
- getInvokeDest(),
- args,
- BundleList);
- invoke->setDoesNotReturn();
- invoke->setCallingConv(getRuntimeCC());
- } else {
- llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList);
- call->setDoesNotReturn();
- call->setCallingConv(getRuntimeCC());
- Builder.CreateUnreachable();
- }
-}
-
-/// Emits a call or invoke instruction to the given nullary runtime function.
-llvm::CallSite
-CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
- const Twine &name) {
- return EmitRuntimeCallOrInvoke(callee, None, name);
-}
-
-/// Emits a call or invoke instruction to the given runtime function.
-llvm::CallSite
-CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
- ArrayRef<llvm::Value*> args,
- const Twine &name) {
- llvm::CallSite callSite = EmitCallOrInvoke(callee, args, name);
- callSite.setCallingConv(getRuntimeCC());
- return callSite;
-}
-
-/// Emits a call or invoke instruction to the given function, depending
-/// on the current state of the EH stack.
-llvm::CallSite
-CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
- ArrayRef<llvm::Value *> Args,
- const Twine &Name) {
- llvm::BasicBlock *InvokeDest = getInvokeDest();
- SmallVector<llvm::OperandBundleDef, 1> BundleList =
- getBundlesForFunclet(Callee);
-
- llvm::Instruction *Inst;
- if (!InvokeDest)
- Inst = Builder.CreateCall(Callee, Args, BundleList, Name);
- else {
- llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
- Inst = Builder.CreateInvoke(Callee, ContBB, InvokeDest, Args, BundleList,
- Name);
- EmitBlock(ContBB);
- }
-
- // In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
- // optimizer it can aggressively ignore unwind edges.
- if (CGM.getLangOpts().ObjCAutoRefCount)
- AddObjCARCExceptionMetadata(Inst);
-
- return llvm::CallSite(Inst);
-}
-
-void CodeGenFunction::deferPlaceholderReplacement(llvm::Instruction *Old,
- llvm::Value *New) {
- DeferredReplacements.push_back(std::make_pair(Old, New));
-}
-
-RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
- const CGCallee &Callee,
- ReturnValueSlot ReturnValue,
- const CallArgList &CallArgs,
- llvm::Instruction **callOrInvoke,
- SourceLocation Loc) {
- // FIXME: We no longer need the types from CallArgs; lift up and simplify.
-
- assert(Callee.isOrdinary() || Callee.isVirtual());
-
- // Handle struct-return functions by passing a pointer to the
- // location that we would like to return into.
- QualType RetTy = CallInfo.getReturnType();
- const ABIArgInfo &RetAI = CallInfo.getReturnInfo();
-
- llvm::FunctionType *IRFuncTy = Callee.getFunctionType();
-
- // 1. Set up the arguments.
-
- // If we're using inalloca, insert the allocation after the stack save.
- // FIXME: Do this earlier rather than hacking it in here!
- Address ArgMemory = Address::invalid();
- const llvm::StructLayout *ArgMemoryLayout = nullptr;
- if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) {
- const llvm::DataLayout &DL = CGM.getDataLayout();
- ArgMemoryLayout = DL.getStructLayout(ArgStruct);
- llvm::Instruction *IP = CallArgs.getStackBase();
- llvm::AllocaInst *AI;
- if (IP) {
- IP = IP->getNextNode();
- AI = new llvm::AllocaInst(ArgStruct, DL.getAllocaAddrSpace(),
- "argmem", IP);
- } else {
- AI = CreateTempAlloca(ArgStruct, "argmem");
- }
- auto Align = CallInfo.getArgStructAlignment();
- AI->setAlignment(Align.getQuantity());
- AI->setUsedWithInAlloca(true);
- assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca());
- ArgMemory = Address(AI, Align);
- }
-
- // Helper function to drill into the inalloca allocation.
- auto createInAllocaStructGEP = [&](unsigned FieldIndex) -> Address {
- auto FieldOffset =
- CharUnits::fromQuantity(ArgMemoryLayout->getElementOffset(FieldIndex));
- return Builder.CreateStructGEP(ArgMemory, FieldIndex, FieldOffset);
- };
-
- ClangToLLVMArgMapping IRFunctionArgs(CGM.getContext(), CallInfo);
- SmallVector<llvm::Value *, 16> IRCallArgs(IRFunctionArgs.totalIRArgs());
-
- // If the call returns a temporary with struct return, create a temporary
- // alloca to hold the result, unless one is given to us.
- Address SRetPtr = Address::invalid();
- Address SRetAlloca = Address::invalid();
- llvm::Value *UnusedReturnSizePtr = nullptr;
- if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) {
- if (!ReturnValue.isNull()) {
- SRetPtr = ReturnValue.getValue();
- } else {
- SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca);
- if (HaveInsertPoint() && ReturnValue.isUnused()) {
- uint64_t size =
- CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(RetTy));
- UnusedReturnSizePtr = EmitLifetimeStart(size, SRetAlloca.getPointer());
- }
- }
- if (IRFunctionArgs.hasSRetArg()) {
- IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr.getPointer();
- } else if (RetAI.isInAlloca()) {
- Address Addr = createInAllocaStructGEP(RetAI.getInAllocaFieldIndex());
- Builder.CreateStore(SRetPtr.getPointer(), Addr);
- }
- }
-
- Address swiftErrorTemp = Address::invalid();
- Address swiftErrorArg = Address::invalid();
-
- // Translate all of the arguments as necessary to match the IR lowering.
- assert(CallInfo.arg_size() == CallArgs.size() &&
- "Mismatch between function signature & arguments.");
- unsigned ArgNo = 0;
- CGFunctionInfo::const_arg_iterator info_it = CallInfo.arg_begin();
- for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end();
- I != E; ++I, ++info_it, ++ArgNo) {
- const ABIArgInfo &ArgInfo = info_it->info;
-
- // Insert a padding argument to ensure proper alignment.
- if (IRFunctionArgs.hasPaddingArg(ArgNo))
- IRCallArgs[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
- llvm::UndefValue::get(ArgInfo.getPaddingType());
-
- unsigned FirstIRArg, NumIRArgs;
- std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
-
- switch (ArgInfo.getKind()) {
- case ABIArgInfo::InAlloca: {
- assert(NumIRArgs == 0);
- assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
- if (I->isAggregate()) {
- // Replace the placeholder with the appropriate argument slot GEP.
- Address Addr = I->hasLValue()
- ? I->getKnownLValue().getAddress()
- : I->getKnownRValue().getAggregateAddress();
- llvm::Instruction *Placeholder =
- cast<llvm::Instruction>(Addr.getPointer());
- CGBuilderTy::InsertPoint IP = Builder.saveIP();
- Builder.SetInsertPoint(Placeholder);
- Addr = createInAllocaStructGEP(ArgInfo.getInAllocaFieldIndex());
- Builder.restoreIP(IP);
- deferPlaceholderReplacement(Placeholder, Addr.getPointer());
- } else {
- // Store the RValue into the argument struct.
- Address Addr = createInAllocaStructGEP(ArgInfo.getInAllocaFieldIndex());
- unsigned AS = Addr.getType()->getPointerAddressSpace();
- llvm::Type *MemType = ConvertTypeForMem(I->Ty)->getPointerTo(AS);
- // There are some cases where a trivial bitcast is not avoidable. The
- // definition of a type later in a translation unit may change it's type
- // from {}* to (%struct.foo*)*.
- if (Addr.getType() != MemType)
- Addr = Builder.CreateBitCast(Addr, MemType);
- I->copyInto(*this, Addr);
- }
- break;
- }
-
- case ABIArgInfo::Indirect: {
- assert(NumIRArgs == 1);
- if (!I->isAggregate()) {
- // Make a temporary alloca to pass the argument.
- Address Addr = CreateMemTempWithoutCast(
- I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp");
- IRCallArgs[FirstIRArg] = Addr.getPointer();
-
- I->copyInto(*this, Addr);
- } else {
- // We want to avoid creating an unnecessary temporary+copy here;
- // however, we need one in three cases:
- // 1. If the argument is not byval, and we are required to copy the
- // source. (This case doesn't occur on any common architecture.)
- // 2. If the argument is byval, RV is not sufficiently aligned, and
- // we cannot force it to be sufficiently aligned.
- // 3. If the argument is byval, but RV is not located in default
- // or alloca address space.
- Address Addr = I->hasLValue()
- ? I->getKnownLValue().getAddress()
- : I->getKnownRValue().getAggregateAddress();
- llvm::Value *V = Addr.getPointer();
- CharUnits Align = ArgInfo.getIndirectAlign();
- const llvm::DataLayout *TD = &CGM.getDataLayout();
-
- assert((FirstIRArg >= IRFuncTy->getNumParams() ||
- IRFuncTy->getParamType(FirstIRArg)->getPointerAddressSpace() ==
- TD->getAllocaAddrSpace()) &&
- "indirect argument must be in alloca address space");
-
- bool NeedCopy = false;
-
- if (Addr.getAlignment() < Align &&
- llvm::getOrEnforceKnownAlignment(V, Align.getQuantity(), *TD) <
- Align.getQuantity()) {
- NeedCopy = true;
- } else if (I->hasLValue()) {
- auto LV = I->getKnownLValue();
- auto AS = LV.getAddressSpace();
-
- if ((!ArgInfo.getIndirectByVal() &&
- (LV.getAlignment() >=
- getContext().getTypeAlignInChars(I->Ty)))) {
- NeedCopy = true;
- }
- if (!getLangOpts().OpenCL) {
- if ((ArgInfo.getIndirectByVal() &&
- (AS != LangAS::Default &&
- AS != CGM.getASTAllocaAddressSpace()))) {
- NeedCopy = true;
- }
- }
- // For OpenCL even if RV is located in default or alloca address space
- // we don't want to perform address space cast for it.
- else if ((ArgInfo.getIndirectByVal() &&
- Addr.getType()->getAddressSpace() != IRFuncTy->
- getParamType(FirstIRArg)->getPointerAddressSpace())) {
- NeedCopy = true;
- }
- }
-
- if (NeedCopy) {
- // Create an aligned temporary, and copy to it.
- Address AI = CreateMemTempWithoutCast(
- I->Ty, ArgInfo.getIndirectAlign(), "byval-temp");
- IRCallArgs[FirstIRArg] = AI.getPointer();
- I->copyInto(*this, AI);
- } else {
- // Skip the extra memcpy call.
- auto *T = V->getType()->getPointerElementType()->getPointerTo(
- CGM.getDataLayout().getAllocaAddrSpace());
- IRCallArgs[FirstIRArg] = getTargetHooks().performAddrSpaceCast(
- *this, V, LangAS::Default, CGM.getASTAllocaAddressSpace(), T,
- true);
- }
- }
- break;
- }
-
- case ABIArgInfo::Ignore:
- assert(NumIRArgs == 0);
- break;
-
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct: {
- if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
- ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
- ArgInfo.getDirectOffset() == 0) {
- assert(NumIRArgs == 1);
- llvm::Value *V;
- if (!I->isAggregate())
- V = I->getKnownRValue().getScalarVal();
- else
- V = Builder.CreateLoad(
- I->hasLValue() ? I->getKnownLValue().getAddress()
- : I->getKnownRValue().getAggregateAddress());
-
- // Implement swifterror by copying into a new swifterror argument.
- // We'll write back in the normal path out of the call.
- if (CallInfo.getExtParameterInfo(ArgNo).getABI()
- == ParameterABI::SwiftErrorResult) {
- assert(!swiftErrorTemp.isValid() && "multiple swifterror args");
-
- QualType pointeeTy = I->Ty->getPointeeType();
- swiftErrorArg =
- Address(V, getContext().getTypeAlignInChars(pointeeTy));
-
- swiftErrorTemp =
- CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp");
- V = swiftErrorTemp.getPointer();
- cast<llvm::AllocaInst>(V)->setSwiftError(true);
-
- llvm::Value *errorValue = Builder.CreateLoad(swiftErrorArg);
- Builder.CreateStore(errorValue, swiftErrorTemp);
- }
-
- // We might have to widen integers, but we should never truncate.
- if (ArgInfo.getCoerceToType() != V->getType() &&
- V->getType()->isIntegerTy())
- V = Builder.CreateZExt(V, ArgInfo.getCoerceToType());
-
- // If the argument doesn't match, perform a bitcast to coerce it. This
- // can happen due to trivial type mismatches.
- if (FirstIRArg < IRFuncTy->getNumParams() &&
- V->getType() != IRFuncTy->getParamType(FirstIRArg))
- V = Builder.CreateBitCast(V, IRFuncTy->getParamType(FirstIRArg));
-
- IRCallArgs[FirstIRArg] = V;
- break;
- }
-
- // FIXME: Avoid the conversion through memory if possible.
- Address Src = Address::invalid();
- if (!I->isAggregate()) {
- Src = CreateMemTemp(I->Ty, "coerce");
- I->copyInto(*this, Src);
- } else {
- Src = I->hasLValue() ? I->getKnownLValue().getAddress()
- : I->getKnownRValue().getAggregateAddress();
- }
-
- // If the value is offset in memory, apply the offset now.
- Src = emitAddressAtOffset(*this, Src, ArgInfo);
-
- // Fast-isel and the optimizer generally like scalar values better than
- // FCAs, so we flatten them if this is safe to do for this argument.
- llvm::StructType *STy =
- dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType());
- if (STy && ArgInfo.isDirect() && ArgInfo.getCanBeFlattened()) {
- llvm::Type *SrcTy = Src.getType()->getElementType();
- uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
-
- // If the source type is smaller than the destination type of the
- // coerce-to logic, copy the source value into a temp alloca the size
- // of the destination type to allow loading all of it. The bits past
- // the source value are left undef.
- if (SrcSize < DstSize) {
- Address TempAlloca
- = CreateTempAlloca(STy, Src.getAlignment(),
- Src.getName() + ".coerce");
- Builder.CreateMemCpy(TempAlloca, Src, SrcSize);
- Src = TempAlloca;
- } else {
- Src = Builder.CreateBitCast(Src,
- STy->getPointerTo(Src.getAddressSpace()));
- }
-
- auto SrcLayout = CGM.getDataLayout().getStructLayout(STy);
- assert(NumIRArgs == STy->getNumElements());
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- auto Offset = CharUnits::fromQuantity(SrcLayout->getElementOffset(i));
- Address EltPtr = Builder.CreateStructGEP(Src, i, Offset);
- llvm::Value *LI = Builder.CreateLoad(EltPtr);
- IRCallArgs[FirstIRArg + i] = LI;
- }
- } else {
- // In the simple case, just pass the coerced loaded value.
- assert(NumIRArgs == 1);
- IRCallArgs[FirstIRArg] =
- CreateCoercedLoad(Src, ArgInfo.getCoerceToType(), *this);
- }
-
- break;
- }
-
- case ABIArgInfo::CoerceAndExpand: {
- auto coercionType = ArgInfo.getCoerceAndExpandType();
- auto layout = CGM.getDataLayout().getStructLayout(coercionType);
-
- llvm::Value *tempSize = nullptr;
- Address addr = Address::invalid();
- Address AllocaAddr = Address::invalid();
- if (I->isAggregate()) {
- addr = I->hasLValue() ? I->getKnownLValue().getAddress()
- : I->getKnownRValue().getAggregateAddress();
-
- } else {
- RValue RV = I->getKnownRValue();
- assert(RV.isScalar()); // complex should always just be direct
-
- llvm::Type *scalarType = RV.getScalarVal()->getType();
- auto scalarSize = CGM.getDataLayout().getTypeAllocSize(scalarType);
- auto scalarAlign = CGM.getDataLayout().getPrefTypeAlignment(scalarType);
-
- // Materialize to a temporary.
- addr = CreateTempAlloca(RV.getScalarVal()->getType(),
- CharUnits::fromQuantity(std::max(
- layout->getAlignment(), scalarAlign)),
- "tmp",
- /*ArraySize=*/nullptr, &AllocaAddr);
- tempSize = EmitLifetimeStart(scalarSize, AllocaAddr.getPointer());
-
- Builder.CreateStore(RV.getScalarVal(), addr);
- }
-
- addr = Builder.CreateElementBitCast(addr, coercionType);
-
- unsigned IRArgPos = FirstIRArg;
- for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
- llvm::Type *eltType = coercionType->getElementType(i);
- if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
- Address eltAddr = Builder.CreateStructGEP(addr, i, layout);
- llvm::Value *elt = Builder.CreateLoad(eltAddr);
- IRCallArgs[IRArgPos++] = elt;
- }
- assert(IRArgPos == FirstIRArg + NumIRArgs);
-
- if (tempSize) {
- EmitLifetimeEnd(tempSize, AllocaAddr.getPointer());
- }
-
- break;
- }
-
- case ABIArgInfo::Expand:
- unsigned IRArgPos = FirstIRArg;
- ExpandTypeToArgs(I->Ty, *I, IRFuncTy, IRCallArgs, IRArgPos);
- assert(IRArgPos == FirstIRArg + NumIRArgs);
- break;
- }
- }
-
- const CGCallee &ConcreteCallee = Callee.prepareConcreteCallee(*this);
- llvm::Value *CalleePtr = ConcreteCallee.getFunctionPointer();
-
- // If we're using inalloca, set up that argument.
- if (ArgMemory.isValid()) {
- llvm::Value *Arg = ArgMemory.getPointer();
- if (CallInfo.isVariadic()) {
- // When passing non-POD arguments by value to variadic functions, we will
- // end up with a variadic prototype and an inalloca call site. In such
- // cases, we can't do any parameter mismatch checks. Give up and bitcast
- // the callee.
- unsigned CalleeAS = CalleePtr->getType()->getPointerAddressSpace();
- auto FnTy = getTypes().GetFunctionType(CallInfo)->getPointerTo(CalleeAS);
- CalleePtr = Builder.CreateBitCast(CalleePtr, FnTy);
- } else {
- llvm::Type *LastParamTy =
- IRFuncTy->getParamType(IRFuncTy->getNumParams() - 1);
- if (Arg->getType() != LastParamTy) {
-#ifndef NDEBUG
- // Assert that these structs have equivalent element types.
- llvm::StructType *FullTy = CallInfo.getArgStruct();
- llvm::StructType *DeclaredTy = cast<llvm::StructType>(
- cast<llvm::PointerType>(LastParamTy)->getElementType());
- assert(DeclaredTy->getNumElements() == FullTy->getNumElements());
- for (llvm::StructType::element_iterator DI = DeclaredTy->element_begin(),
- DE = DeclaredTy->element_end(),
- FI = FullTy->element_begin();
- DI != DE; ++DI, ++FI)
- assert(*DI == *FI);
-#endif
- Arg = Builder.CreateBitCast(Arg, LastParamTy);
- }
- }
- assert(IRFunctionArgs.hasInallocaArg());
- IRCallArgs[IRFunctionArgs.getInallocaArgNo()] = Arg;
- }
-
- // 2. Prepare the function pointer.
-
- // If the callee is a bitcast of a non-variadic function to have a
- // variadic function pointer type, check to see if we can remove the
- // bitcast. This comes up with unprototyped functions.
- //
- // This makes the IR nicer, but more importantly it ensures that we
- // can inline the function at -O0 if it is marked always_inline.
- auto simplifyVariadicCallee = [](llvm::Value *Ptr) -> llvm::Value* {
- llvm::FunctionType *CalleeFT =
- cast<llvm::FunctionType>(Ptr->getType()->getPointerElementType());
- if (!CalleeFT->isVarArg())
- return Ptr;
-
- llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Ptr);
- if (!CE || CE->getOpcode() != llvm::Instruction::BitCast)
- return Ptr;
-
- llvm::Function *OrigFn = dyn_cast<llvm::Function>(CE->getOperand(0));
- if (!OrigFn)
- return Ptr;
-
- llvm::FunctionType *OrigFT = OrigFn->getFunctionType();
-
- // If the original type is variadic, or if any of the component types
- // disagree, we cannot remove the cast.
- if (OrigFT->isVarArg() ||
- OrigFT->getNumParams() != CalleeFT->getNumParams() ||
- OrigFT->getReturnType() != CalleeFT->getReturnType())
- return Ptr;
-
- for (unsigned i = 0, e = OrigFT->getNumParams(); i != e; ++i)
- if (OrigFT->getParamType(i) != CalleeFT->getParamType(i))
- return Ptr;
-
- return OrigFn;
- };
- CalleePtr = simplifyVariadicCallee(CalleePtr);
-
- // 3. Perform the actual call.
-
- // Deactivate any cleanups that we're supposed to do immediately before
- // the call.
- if (!CallArgs.getCleanupsToDeactivate().empty())
- deactivateArgCleanupsBeforeCall(*this, CallArgs);
-
- // Assert that the arguments we computed match up. The IR verifier
- // will catch this, but this is a common enough source of problems
- // during IRGen changes that it's way better for debugging to catch
- // it ourselves here.
-#ifndef NDEBUG
- assert(IRCallArgs.size() == IRFuncTy->getNumParams() || IRFuncTy->isVarArg());
- for (unsigned i = 0; i < IRCallArgs.size(); ++i) {
- // Inalloca argument can have different type.
- if (IRFunctionArgs.hasInallocaArg() &&
- i == IRFunctionArgs.getInallocaArgNo())
- continue;
- if (i < IRFuncTy->getNumParams())
- assert(IRCallArgs[i]->getType() == IRFuncTy->getParamType(i));
- }
-#endif
-
- // Update the largest vector width if any arguments have vector types.
- for (unsigned i = 0; i < IRCallArgs.size(); ++i) {
- if (auto *VT = dyn_cast<llvm::VectorType>(IRCallArgs[i]->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
- }
-
- // Compute the calling convention and attributes.
- unsigned CallingConv;
- llvm::AttributeList Attrs;
- CGM.ConstructAttributeList(CalleePtr->getName(), CallInfo,
- Callee.getAbstractInfo(), Attrs, CallingConv,
- /*AttrOnCallSite=*/true);
-
- // Apply some call-site-specific attributes.
- // TODO: work this into building the attribute set.
-
- // Apply always_inline to all calls within flatten functions.
- // FIXME: should this really take priority over __try, below?
- if (CurCodeDecl && CurCodeDecl->hasAttr<FlattenAttr>() &&
- !(Callee.getAbstractInfo().getCalleeDecl().getDecl() &&
- Callee.getAbstractInfo()
- .getCalleeDecl()
- .getDecl()
- ->hasAttr<NoInlineAttr>())) {
- Attrs =
- Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
- llvm::Attribute::AlwaysInline);
- }
-
- // Disable inlining inside SEH __try blocks.
- if (isSEHTryScope()) {
- Attrs =
- Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoInline);
- }
-
- // Decide whether to use a call or an invoke.
- bool CannotThrow;
- if (currentFunctionUsesSEHTry()) {
- // SEH cares about asynchronous exceptions, so everything can "throw."
- CannotThrow = false;
- } else if (isCleanupPadScope() &&
- EHPersonality::get(*this).isMSVCXXPersonality()) {
- // The MSVC++ personality will implicitly terminate the program if an
- // exception is thrown during a cleanup outside of a try/catch.
- // We don't need to model anything in IR to get this behavior.
- CannotThrow = true;
- } else {
- // Otherwise, nounwind call sites will never throw.
- CannotThrow = Attrs.hasAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind);
- }
-
- // If we made a temporary, be sure to clean up after ourselves. Note that we
- // can't depend on being inside of an ExprWithCleanups, so we need to manually
- // pop this cleanup later on. Being eager about this is OK, since this
- // temporary is 'invisible' outside of the callee.
- if (UnusedReturnSizePtr)
- pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, SRetAlloca,
- UnusedReturnSizePtr);
-
- llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest();
-
- SmallVector<llvm::OperandBundleDef, 1> BundleList =
- getBundlesForFunclet(CalleePtr);
-
- // Emit the actual call/invoke instruction.
- llvm::CallSite CS;
- if (!InvokeDest) {
- CS = Builder.CreateCall(CalleePtr, IRCallArgs, BundleList);
- } else {
- llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
- CS = Builder.CreateInvoke(CalleePtr, Cont, InvokeDest, IRCallArgs,
- BundleList);
- EmitBlock(Cont);
- }
- llvm::Instruction *CI = CS.getInstruction();
- if (callOrInvoke)
- *callOrInvoke = CI;
-
- // Apply the attributes and calling convention.
- CS.setAttributes(Attrs);
- CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
-
- // Apply various metadata.
-
- if (!CI->getType()->isVoidTy())
- CI->setName("call");
-
- // Update largest vector width from the return type.
- if (auto *VT = dyn_cast<llvm::VectorType>(CI->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
-
- // Insert instrumentation or attach profile metadata at indirect call sites.
- // For more details, see the comment before the definition of
- // IPVK_IndirectCallTarget in InstrProfData.inc.
- if (!CS.getCalledFunction())
- PGO.valueProfile(Builder, llvm::IPVK_IndirectCallTarget,
- CI, CalleePtr);
-
- // In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
- // optimizer it can aggressively ignore unwind edges.
- if (CGM.getLangOpts().ObjCAutoRefCount)
- AddObjCARCExceptionMetadata(CI);
-
- // Suppress tail calls if requested.
- if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
- const Decl *TargetDecl = Callee.getAbstractInfo().getCalleeDecl().getDecl();
- if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
- Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
- }
-
- // 4. Finish the call.
-
- // If the call doesn't return, finish the basic block and clear the
- // insertion point; this allows the rest of IRGen to discard
- // unreachable code.
- if (CS.doesNotReturn()) {
- if (UnusedReturnSizePtr)
- PopCleanupBlock();
-
- // Strip away the noreturn attribute to better diagnose unreachable UB.
- if (SanOpts.has(SanitizerKind::Unreachable)) {
- if (auto *F = CS.getCalledFunction())
- F->removeFnAttr(llvm::Attribute::NoReturn);
- CS.removeAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoReturn);
- }
-
- EmitUnreachable(Loc);
- Builder.ClearInsertionPoint();
-
- // FIXME: For now, emit a dummy basic block because expr emitters in
- // generally are not ready to handle emitting expressions at unreachable
- // points.
- EnsureInsertPoint();
-
- // Return a reasonable RValue.
- return GetUndefRValue(RetTy);
- }
-
- // Perform the swifterror writeback.
- if (swiftErrorTemp.isValid()) {
- llvm::Value *errorResult = Builder.CreateLoad(swiftErrorTemp);
- Builder.CreateStore(errorResult, swiftErrorArg);
- }
-
- // Emit any call-associated writebacks immediately. Arguably this
- // should happen after any return-value munging.
- if (CallArgs.hasWritebacks())
- emitWritebacks(*this, CallArgs);
-
- // The stack cleanup for inalloca arguments has to run out of the normal
- // lexical order, so deactivate it and run it manually here.
- CallArgs.freeArgumentMemory(*this);
-
- // Extract the return value.
- RValue Ret = [&] {
- switch (RetAI.getKind()) {
- case ABIArgInfo::CoerceAndExpand: {
- auto coercionType = RetAI.getCoerceAndExpandType();
- auto layout = CGM.getDataLayout().getStructLayout(coercionType);
-
- Address addr = SRetPtr;
- addr = Builder.CreateElementBitCast(addr, coercionType);
-
- assert(CI->getType() == RetAI.getUnpaddedCoerceAndExpandType());
- bool requiresExtract = isa<llvm::StructType>(CI->getType());
-
- unsigned unpaddedIndex = 0;
- for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
- llvm::Type *eltType = coercionType->getElementType(i);
- if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
- Address eltAddr = Builder.CreateStructGEP(addr, i, layout);
- llvm::Value *elt = CI;
- if (requiresExtract)
- elt = Builder.CreateExtractValue(elt, unpaddedIndex++);
- else
- assert(unpaddedIndex == 0);
- Builder.CreateStore(elt, eltAddr);
- }
- // FALLTHROUGH
- LLVM_FALLTHROUGH;
- }
-
- case ABIArgInfo::InAlloca:
- case ABIArgInfo::Indirect: {
- RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
- if (UnusedReturnSizePtr)
- PopCleanupBlock();
- return ret;
- }
-
- case ABIArgInfo::Ignore:
- // If we are ignoring an argument that had a result, make sure to
- // construct the appropriate return value for our caller.
- return GetUndefRValue(RetTy);
-
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct: {
- llvm::Type *RetIRTy = ConvertType(RetTy);
- if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
- switch (getEvaluationKind(RetTy)) {
- case TEK_Complex: {
- llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
- llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
- return RValue::getComplex(std::make_pair(Real, Imag));
- }
- case TEK_Aggregate: {
- Address DestPtr = ReturnValue.getValue();
- bool DestIsVolatile = ReturnValue.isVolatile();
-
- if (!DestPtr.isValid()) {
- DestPtr = CreateMemTemp(RetTy, "agg.tmp");
- DestIsVolatile = false;
- }
- BuildAggStore(*this, CI, DestPtr, DestIsVolatile);
- return RValue::getAggregate(DestPtr);
- }
- case TEK_Scalar: {
- // If the argument doesn't match, perform a bitcast to coerce it. This
- // can happen due to trivial type mismatches.
- llvm::Value *V = CI;
- if (V->getType() != RetIRTy)
- V = Builder.CreateBitCast(V, RetIRTy);
- return RValue::get(V);
- }
- }
- llvm_unreachable("bad evaluation kind");
- }
-
- Address DestPtr = ReturnValue.getValue();
- bool DestIsVolatile = ReturnValue.isVolatile();
-
- if (!DestPtr.isValid()) {
- DestPtr = CreateMemTemp(RetTy, "coerce");
- DestIsVolatile = false;
- }
-
- // If the value is offset in memory, apply the offset now.
- Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
- CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
-
- return convertTempToRValue(DestPtr, RetTy, SourceLocation());
- }
-
- case ABIArgInfo::Expand:
- llvm_unreachable("Invalid ABI kind for return argument");
- }
-
- llvm_unreachable("Unhandled ABIArgInfo::Kind");
- } ();
-
- // Emit the assume_aligned check on the return value.
- const Decl *TargetDecl = Callee.getAbstractInfo().getCalleeDecl().getDecl();
- if (Ret.isScalar() && TargetDecl) {
- if (const auto *AA = TargetDecl->getAttr<AssumeAlignedAttr>()) {
- llvm::Value *OffsetValue = nullptr;
- if (const auto *Offset = AA->getOffset())
- OffsetValue = EmitScalarExpr(Offset);
-
- llvm::Value *Alignment = EmitScalarExpr(AA->getAlignment());
- llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(Alignment);
- EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(),
- AlignmentCI->getZExtValue(), OffsetValue);
- } else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) {
- llvm::Value *AlignmentVal = CallArgs[AA->getParamIndex().getLLVMIndex()]
- .getRValue(*this)
- .getScalarVal();
- EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(),
- AlignmentVal);
- }
- }
-
- return Ret;
-}
-
-CGCallee CGCallee::prepareConcreteCallee(CodeGenFunction &CGF) const {
- if (isVirtual()) {
- const CallExpr *CE = getVirtualCallExpr();
- return CGF.CGM.getCXXABI().getVirtualFunctionPointer(
- CGF, getVirtualMethodDecl(), getThisAddress(), getFunctionType(),
- CE ? CE->getBeginLoc() : SourceLocation());
- }
-
- return *this;
-}
-
-/* VarArg handling */
-
-Address CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr) {
- VAListAddr = VE->isMicrosoftABI()
- ? EmitMSVAListRef(VE->getSubExpr())
- : EmitVAListRef(VE->getSubExpr());
- QualType Ty = VE->getType();
- if (VE->isMicrosoftABI())
- return CGM.getTypes().getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty);
- return CGM.getTypes().getABIInfo().EmitVAArg(*this, VAListAddr, Ty);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.h b/gnu/llvm/tools/clang/lib/CodeGen/CGCall.h
deleted file mode 100644
index c300808bea2..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.h
+++ /dev/null
@@ -1,388 +0,0 @@
-//===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes wrap the information about a call or function
-// definition used to handle ABI compliancy.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H
-#define LLVM_CLANG_LIB_CODEGEN_CGCALL_H
-
-#include "CGValue.h"
-#include "EHScopeStack.h"
-#include "clang/AST/CanonicalType.h"
-#include "clang/AST/GlobalDecl.h"
-#include "clang/AST/Type.h"
-#include "llvm/IR/Value.h"
-
-// FIXME: Restructure so we don't have to expose so much stuff.
-#include "ABIInfo.h"
-
-namespace llvm {
-class AttributeList;
-class Function;
-class Type;
-class Value;
-}
-
-namespace clang {
- class ASTContext;
- class Decl;
- class FunctionDecl;
- class ObjCMethodDecl;
- class VarDecl;
-
-namespace CodeGen {
-
-/// Abstract information about a function or function prototype.
-class CGCalleeInfo {
- /// The function prototype of the callee.
- const FunctionProtoType *CalleeProtoTy;
- /// The function declaration of the callee.
- GlobalDecl CalleeDecl;
-
-public:
- explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl() {}
- CGCalleeInfo(const FunctionProtoType *calleeProtoTy, GlobalDecl calleeDecl)
- : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
- CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
- : CalleeProtoTy(calleeProtoTy), CalleeDecl() {}
- CGCalleeInfo(GlobalDecl calleeDecl)
- : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
-
- const FunctionProtoType *getCalleeFunctionProtoType() const {
- return CalleeProtoTy;
- }
- const GlobalDecl getCalleeDecl() const { return CalleeDecl; }
- };
-
- /// All available information about a concrete callee.
- class CGCallee {
- enum class SpecialKind : uintptr_t {
- Invalid,
- Builtin,
- PseudoDestructor,
- Virtual,
-
- Last = Virtual
- };
-
- struct BuiltinInfoStorage {
- const FunctionDecl *Decl;
- unsigned ID;
- };
- struct PseudoDestructorInfoStorage {
- const CXXPseudoDestructorExpr *Expr;
- };
- struct VirtualInfoStorage {
- const CallExpr *CE;
- GlobalDecl MD;
- Address Addr;
- llvm::FunctionType *FTy;
- };
-
- SpecialKind KindOrFunctionPointer;
- union {
- CGCalleeInfo AbstractInfo;
- BuiltinInfoStorage BuiltinInfo;
- PseudoDestructorInfoStorage PseudoDestructorInfo;
- VirtualInfoStorage VirtualInfo;
- };
-
- explicit CGCallee(SpecialKind kind) : KindOrFunctionPointer(kind) {}
-
- CGCallee(const FunctionDecl *builtinDecl, unsigned builtinID)
- : KindOrFunctionPointer(SpecialKind::Builtin) {
- BuiltinInfo.Decl = builtinDecl;
- BuiltinInfo.ID = builtinID;
- }
-
- public:
- CGCallee() : KindOrFunctionPointer(SpecialKind::Invalid) {}
-
- /// Construct a callee. Call this constructor directly when this
- /// isn't a direct call.
- CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr)
- : KindOrFunctionPointer(SpecialKind(uintptr_t(functionPtr))) {
- AbstractInfo = abstractInfo;
- assert(functionPtr && "configuring callee without function pointer");
- assert(functionPtr->getType()->isPointerTy());
- assert(functionPtr->getType()->getPointerElementType()->isFunctionTy());
- }
-
- static CGCallee forBuiltin(unsigned builtinID,
- const FunctionDecl *builtinDecl) {
- CGCallee result(SpecialKind::Builtin);
- result.BuiltinInfo.Decl = builtinDecl;
- result.BuiltinInfo.ID = builtinID;
- return result;
- }
-
- static CGCallee forPseudoDestructor(const CXXPseudoDestructorExpr *E) {
- CGCallee result(SpecialKind::PseudoDestructor);
- result.PseudoDestructorInfo.Expr = E;
- return result;
- }
-
- static CGCallee forDirect(llvm::Constant *functionPtr,
- const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
- return CGCallee(abstractInfo, functionPtr);
- }
-
- static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr,
- llvm::FunctionType *FTy) {
- CGCallee result(SpecialKind::Virtual);
- result.VirtualInfo.CE = CE;
- result.VirtualInfo.MD = MD;
- result.VirtualInfo.Addr = Addr;
- result.VirtualInfo.FTy = FTy;
- return result;
- }
-
- bool isBuiltin() const {
- return KindOrFunctionPointer == SpecialKind::Builtin;
- }
- const FunctionDecl *getBuiltinDecl() const {
- assert(isBuiltin());
- return BuiltinInfo.Decl;
- }
- unsigned getBuiltinID() const {
- assert(isBuiltin());
- return BuiltinInfo.ID;
- }
-
- bool isPseudoDestructor() const {
- return KindOrFunctionPointer == SpecialKind::PseudoDestructor;
- }
- const CXXPseudoDestructorExpr *getPseudoDestructorExpr() const {
- assert(isPseudoDestructor());
- return PseudoDestructorInfo.Expr;
- }
-
- bool isOrdinary() const {
- return uintptr_t(KindOrFunctionPointer) > uintptr_t(SpecialKind::Last);
- }
- CGCalleeInfo getAbstractInfo() const {
- if (isVirtual())
- return VirtualInfo.MD;
- assert(isOrdinary());
- return AbstractInfo;
- }
- llvm::Value *getFunctionPointer() const {
- assert(isOrdinary());
- return reinterpret_cast<llvm::Value*>(uintptr_t(KindOrFunctionPointer));
- }
- void setFunctionPointer(llvm::Value *functionPtr) {
- assert(isOrdinary());
- KindOrFunctionPointer = SpecialKind(uintptr_t(functionPtr));
- }
-
- bool isVirtual() const {
- return KindOrFunctionPointer == SpecialKind::Virtual;
- }
- const CallExpr *getVirtualCallExpr() const {
- assert(isVirtual());
- return VirtualInfo.CE;
- }
- GlobalDecl getVirtualMethodDecl() const {
- assert(isVirtual());
- return VirtualInfo.MD;
- }
- Address getThisAddress() const {
- assert(isVirtual());
- return VirtualInfo.Addr;
- }
-
- llvm::FunctionType *getFunctionType() const {
- if (isVirtual())
- return VirtualInfo.FTy;
- return cast<llvm::FunctionType>(
- getFunctionPointer()->getType()->getPointerElementType());
- }
-
- /// If this is a delayed callee computation of some sort, prepare
- /// a concrete callee.
- CGCallee prepareConcreteCallee(CodeGenFunction &CGF) const;
- };
-
- struct CallArg {
- private:
- union {
- RValue RV;
- LValue LV; /// The argument is semantically a load from this l-value.
- };
- bool HasLV;
-
- /// A data-flow flag to make sure getRValue and/or copyInto are not
- /// called twice for duplicated IR emission.
- mutable bool IsUsed;
-
- public:
- QualType Ty;
- CallArg(RValue rv, QualType ty)
- : RV(rv), HasLV(false), IsUsed(false), Ty(ty) {}
- CallArg(LValue lv, QualType ty)
- : LV(lv), HasLV(true), IsUsed(false), Ty(ty) {}
- bool hasLValue() const { return HasLV; }
- QualType getType() const { return Ty; }
-
- /// \returns an independent RValue. If the CallArg contains an LValue,
- /// a temporary copy is returned.
- RValue getRValue(CodeGenFunction &CGF) const;
-
- LValue getKnownLValue() const {
- assert(HasLV && !IsUsed);
- return LV;
- }
- RValue getKnownRValue() const {
- assert(!HasLV && !IsUsed);
- return RV;
- }
- void setRValue(RValue _RV) {
- assert(!HasLV);
- RV = _RV;
- }
-
- bool isAggregate() const { return HasLV || RV.isAggregate(); }
-
- void copyInto(CodeGenFunction &CGF, Address A) const;
- };
-
- /// CallArgList - Type for representing both the value and type of
- /// arguments in a call.
- class CallArgList :
- public SmallVector<CallArg, 8> {
- public:
- CallArgList() : StackBase(nullptr) {}
-
- struct Writeback {
- /// The original argument. Note that the argument l-value
- /// is potentially null.
- LValue Source;
-
- /// The temporary alloca.
- Address Temporary;
-
- /// A value to "use" after the writeback, or null.
- llvm::Value *ToUse;
- };
-
- struct CallArgCleanup {
- EHScopeStack::stable_iterator Cleanup;
-
- /// The "is active" insertion point. This instruction is temporary and
- /// will be removed after insertion.
- llvm::Instruction *IsActiveIP;
- };
-
- void add(RValue rvalue, QualType type) { push_back(CallArg(rvalue, type)); }
-
- void addUncopiedAggregate(LValue LV, QualType type) {
- push_back(CallArg(LV, type));
- }
-
- /// Add all the arguments from another CallArgList to this one. After doing
- /// this, the old CallArgList retains its list of arguments, but must not
- /// be used to emit a call.
- void addFrom(const CallArgList &other) {
- insert(end(), other.begin(), other.end());
- Writebacks.insert(Writebacks.end(),
- other.Writebacks.begin(), other.Writebacks.end());
- CleanupsToDeactivate.insert(CleanupsToDeactivate.end(),
- other.CleanupsToDeactivate.begin(),
- other.CleanupsToDeactivate.end());
- assert(!(StackBase && other.StackBase) && "can't merge stackbases");
- if (!StackBase)
- StackBase = other.StackBase;
- }
-
- void addWriteback(LValue srcLV, Address temporary,
- llvm::Value *toUse) {
- Writeback writeback = { srcLV, temporary, toUse };
- Writebacks.push_back(writeback);
- }
-
- bool hasWritebacks() const { return !Writebacks.empty(); }
-
- typedef llvm::iterator_range<SmallVectorImpl<Writeback>::const_iterator>
- writeback_const_range;
-
- writeback_const_range writebacks() const {
- return writeback_const_range(Writebacks.begin(), Writebacks.end());
- }
-
- void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup,
- llvm::Instruction *IsActiveIP) {
- CallArgCleanup ArgCleanup;
- ArgCleanup.Cleanup = Cleanup;
- ArgCleanup.IsActiveIP = IsActiveIP;
- CleanupsToDeactivate.push_back(ArgCleanup);
- }
-
- ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const {
- return CleanupsToDeactivate;
- }
-
- void allocateArgumentMemory(CodeGenFunction &CGF);
- llvm::Instruction *getStackBase() const { return StackBase; }
- void freeArgumentMemory(CodeGenFunction &CGF) const;
-
- /// Returns if we're using an inalloca struct to pass arguments in
- /// memory.
- bool isUsingInAlloca() const { return StackBase; }
-
- private:
- SmallVector<Writeback, 1> Writebacks;
-
- /// Deactivate these cleanups immediately before making the call. This
- /// is used to cleanup objects that are owned by the callee once the call
- /// occurs.
- SmallVector<CallArgCleanup, 1> CleanupsToDeactivate;
-
- /// The stacksave call. It dominates all of the argument evaluation.
- llvm::CallInst *StackBase;
- };
-
- /// FunctionArgList - Type for representing both the decl and type
- /// of parameters to a function. The decl must be either a
- /// ParmVarDecl or ImplicitParamDecl.
- class FunctionArgList : public SmallVector<const VarDecl*, 16> {
- };
-
- /// ReturnValueSlot - Contains the address where the return value of a
- /// function can be stored, and whether the address is volatile or not.
- class ReturnValueSlot {
- llvm::PointerIntPair<llvm::Value *, 2, unsigned int> Value;
- CharUnits Alignment;
-
- // Return value slot flags
- enum Flags {
- IS_VOLATILE = 0x1,
- IS_UNUSED = 0x2,
- };
-
- public:
- ReturnValueSlot() {}
- ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false)
- : Value(Addr.isValid() ? Addr.getPointer() : nullptr,
- (IsVolatile ? IS_VOLATILE : 0) | (IsUnused ? IS_UNUSED : 0)),
- Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {}
-
- bool isNull() const { return !getValue().isValid(); }
-
- bool isVolatile() const { return Value.getInt() & IS_VOLATILE; }
- Address getValue() const { return Address(Value.getPointer(), Alignment); }
- bool isUnused() const { return Value.getInt() & IS_UNUSED; }
- };
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGClass.cpp
deleted file mode 100644
index ee150a792b7..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGClass.cpp
+++ /dev/null
@@ -1,2906 +0,0 @@
-//===--- CGClass.cpp - Emit LLVM Code for C++ classes -----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of classes
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGBlocks.h"
-#include "CGCXXABI.h"
-#include "CGDebugInfo.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "TargetInfo.h"
-#include "clang/AST/CXXInheritance.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/EvaluatedExprVisitor.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/TargetBuiltins.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Metadata.h"
-#include "llvm/Transforms/Utils/SanitizerStats.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-/// Return the best known alignment for an unknown pointer to a
-/// particular class.
-CharUnits CodeGenModule::getClassPointerAlignment(const CXXRecordDecl *RD) {
- if (!RD->isCompleteDefinition())
- return CharUnits::One(); // Hopefully won't be used anywhere.
-
- auto &layout = getContext().getASTRecordLayout(RD);
-
- // If the class is final, then we know that the pointer points to an
- // object of that type and can use the full alignment.
- if (RD->hasAttr<FinalAttr>()) {
- return layout.getAlignment();
-
- // Otherwise, we have to assume it could be a subclass.
- } else {
- return layout.getNonVirtualAlignment();
- }
-}
-
-/// Return the best known alignment for a pointer to a virtual base,
-/// given the alignment of a pointer to the derived class.
-CharUnits CodeGenModule::getVBaseAlignment(CharUnits actualDerivedAlign,
- const CXXRecordDecl *derivedClass,
- const CXXRecordDecl *vbaseClass) {
- // The basic idea here is that an underaligned derived pointer might
- // indicate an underaligned base pointer.
-
- assert(vbaseClass->isCompleteDefinition());
- auto &baseLayout = getContext().getASTRecordLayout(vbaseClass);
- CharUnits expectedVBaseAlign = baseLayout.getNonVirtualAlignment();
-
- return getDynamicOffsetAlignment(actualDerivedAlign, derivedClass,
- expectedVBaseAlign);
-}
-
-CharUnits
-CodeGenModule::getDynamicOffsetAlignment(CharUnits actualBaseAlign,
- const CXXRecordDecl *baseDecl,
- CharUnits expectedTargetAlign) {
- // If the base is an incomplete type (which is, alas, possible with
- // member pointers), be pessimistic.
- if (!baseDecl->isCompleteDefinition())
- return std::min(actualBaseAlign, expectedTargetAlign);
-
- auto &baseLayout = getContext().getASTRecordLayout(baseDecl);
- CharUnits expectedBaseAlign = baseLayout.getNonVirtualAlignment();
-
- // If the class is properly aligned, assume the target offset is, too.
- //
- // This actually isn't necessarily the right thing to do --- if the
- // class is a complete object, but it's only properly aligned for a
- // base subobject, then the alignments of things relative to it are
- // probably off as well. (Note that this requires the alignment of
- // the target to be greater than the NV alignment of the derived
- // class.)
- //
- // However, our approach to this kind of under-alignment can only
- // ever be best effort; after all, we're never going to propagate
- // alignments through variables or parameters. Note, in particular,
- // that constructing a polymorphic type in an address that's less
- // than pointer-aligned will generally trap in the constructor,
- // unless we someday add some sort of attribute to change the
- // assumed alignment of 'this'. So our goal here is pretty much
- // just to allow the user to explicitly say that a pointer is
- // under-aligned and then safely access its fields and vtables.
- if (actualBaseAlign >= expectedBaseAlign) {
- return expectedTargetAlign;
- }
-
- // Otherwise, we might be offset by an arbitrary multiple of the
- // actual alignment. The correct adjustment is to take the min of
- // the two alignments.
- return std::min(actualBaseAlign, expectedTargetAlign);
-}
-
-Address CodeGenFunction::LoadCXXThisAddress() {
- assert(CurFuncDecl && "loading 'this' without a func declaration?");
- assert(isa<CXXMethodDecl>(CurFuncDecl));
-
- // Lazily compute CXXThisAlignment.
- if (CXXThisAlignment.isZero()) {
- // Just use the best known alignment for the parent.
- // TODO: if we're currently emitting a complete-object ctor/dtor,
- // we can always use the complete-object alignment.
- auto RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent();
- CXXThisAlignment = CGM.getClassPointerAlignment(RD);
- }
-
- return Address(LoadCXXThis(), CXXThisAlignment);
-}
-
-/// Emit the address of a field using a member data pointer.
-///
-/// \param E Only used for emergency diagnostics
-Address
-CodeGenFunction::EmitCXXMemberDataPointerAddress(const Expr *E, Address base,
- llvm::Value *memberPtr,
- const MemberPointerType *memberPtrType,
- LValueBaseInfo *BaseInfo,
- TBAAAccessInfo *TBAAInfo) {
- // Ask the ABI to compute the actual address.
- llvm::Value *ptr =
- CGM.getCXXABI().EmitMemberDataPointerAddress(*this, E, base,
- memberPtr, memberPtrType);
-
- QualType memberType = memberPtrType->getPointeeType();
- CharUnits memberAlign = getNaturalTypeAlignment(memberType, BaseInfo,
- TBAAInfo);
- memberAlign =
- CGM.getDynamicOffsetAlignment(base.getAlignment(),
- memberPtrType->getClass()->getAsCXXRecordDecl(),
- memberAlign);
- return Address(ptr, memberAlign);
-}
-
-CharUnits CodeGenModule::computeNonVirtualBaseClassOffset(
- const CXXRecordDecl *DerivedClass, CastExpr::path_const_iterator Start,
- CastExpr::path_const_iterator End) {
- CharUnits Offset = CharUnits::Zero();
-
- const ASTContext &Context = getContext();
- const CXXRecordDecl *RD = DerivedClass;
-
- for (CastExpr::path_const_iterator I = Start; I != End; ++I) {
- const CXXBaseSpecifier *Base = *I;
- assert(!Base->isVirtual() && "Should not see virtual bases here!");
-
- // Get the layout.
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- // Add the offset.
- Offset += Layout.getBaseClassOffset(BaseDecl);
-
- RD = BaseDecl;
- }
-
- return Offset;
-}
-
-llvm::Constant *
-CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd) {
- assert(PathBegin != PathEnd && "Base path should not be empty!");
-
- CharUnits Offset =
- computeNonVirtualBaseClassOffset(ClassDecl, PathBegin, PathEnd);
- if (Offset.isZero())
- return nullptr;
-
- llvm::Type *PtrDiffTy =
- Types.ConvertType(getContext().getPointerDiffType());
-
- return llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity());
-}
-
-/// Gets the address of a direct base class within a complete object.
-/// This should only be used for (1) non-virtual bases or (2) virtual bases
-/// when the type is known to be complete (e.g. in complete destructors).
-///
-/// The object pointed to by 'This' is assumed to be non-null.
-Address
-CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(Address This,
- const CXXRecordDecl *Derived,
- const CXXRecordDecl *Base,
- bool BaseIsVirtual) {
- // 'this' must be a pointer (in some address space) to Derived.
- assert(This.getElementType() == ConvertType(Derived));
-
- // Compute the offset of the virtual base.
- CharUnits Offset;
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
- if (BaseIsVirtual)
- Offset = Layout.getVBaseClassOffset(Base);
- else
- Offset = Layout.getBaseClassOffset(Base);
-
- // Shift and cast down to the base type.
- // TODO: for complete types, this should be possible with a GEP.
- Address V = This;
- if (!Offset.isZero()) {
- V = Builder.CreateElementBitCast(V, Int8Ty);
- V = Builder.CreateConstInBoundsByteGEP(V, Offset);
- }
- V = Builder.CreateElementBitCast(V, ConvertType(Base));
-
- return V;
-}
-
-static Address
-ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, Address addr,
- CharUnits nonVirtualOffset,
- llvm::Value *virtualOffset,
- const CXXRecordDecl *derivedClass,
- const CXXRecordDecl *nearestVBase) {
- // Assert that we have something to do.
- assert(!nonVirtualOffset.isZero() || virtualOffset != nullptr);
-
- // Compute the offset from the static and dynamic components.
- llvm::Value *baseOffset;
- if (!nonVirtualOffset.isZero()) {
- baseOffset = llvm::ConstantInt::get(CGF.PtrDiffTy,
- nonVirtualOffset.getQuantity());
- if (virtualOffset) {
- baseOffset = CGF.Builder.CreateAdd(virtualOffset, baseOffset);
- }
- } else {
- baseOffset = virtualOffset;
- }
-
- // Apply the base offset.
- llvm::Value *ptr = addr.getPointer();
- ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
- ptr = CGF.Builder.CreateInBoundsGEP(ptr, baseOffset, "add.ptr");
-
- // If we have a virtual component, the alignment of the result will
- // be relative only to the known alignment of that vbase.
- CharUnits alignment;
- if (virtualOffset) {
- assert(nearestVBase && "virtual offset without vbase?");
- alignment = CGF.CGM.getVBaseAlignment(addr.getAlignment(),
- derivedClass, nearestVBase);
- } else {
- alignment = addr.getAlignment();
- }
- alignment = alignment.alignmentAtOffset(nonVirtualOffset);
-
- return Address(ptr, alignment);
-}
-
-Address CodeGenFunction::GetAddressOfBaseClass(
- Address Value, const CXXRecordDecl *Derived,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd, bool NullCheckValue,
- SourceLocation Loc) {
- assert(PathBegin != PathEnd && "Base path should not be empty!");
-
- CastExpr::path_const_iterator Start = PathBegin;
- const CXXRecordDecl *VBase = nullptr;
-
- // Sema has done some convenient canonicalization here: if the
- // access path involved any virtual steps, the conversion path will
- // *start* with a step down to the correct virtual base subobject,
- // and hence will not require any further steps.
- if ((*Start)->isVirtual()) {
- VBase =
- cast<CXXRecordDecl>((*Start)->getType()->getAs<RecordType>()->getDecl());
- ++Start;
- }
-
- // Compute the static offset of the ultimate destination within its
- // allocating subobject (the virtual base, if there is one, or else
- // the "complete" object that we see).
- CharUnits NonVirtualOffset = CGM.computeNonVirtualBaseClassOffset(
- VBase ? VBase : Derived, Start, PathEnd);
-
- // If there's a virtual step, we can sometimes "devirtualize" it.
- // For now, that's limited to when the derived type is final.
- // TODO: "devirtualize" this for accesses to known-complete objects.
- if (VBase && Derived->hasAttr<FinalAttr>()) {
- const ASTRecordLayout &layout = getContext().getASTRecordLayout(Derived);
- CharUnits vBaseOffset = layout.getVBaseClassOffset(VBase);
- NonVirtualOffset += vBaseOffset;
- VBase = nullptr; // we no longer have a virtual step
- }
-
- // Get the base pointer type.
- llvm::Type *BasePtrTy =
- ConvertType((PathEnd[-1])->getType())->getPointerTo();
-
- QualType DerivedTy = getContext().getRecordType(Derived);
- CharUnits DerivedAlign = CGM.getClassPointerAlignment(Derived);
-
- // If the static offset is zero and we don't have a virtual step,
- // just do a bitcast; null checks are unnecessary.
- if (NonVirtualOffset.isZero() && !VBase) {
- if (sanitizePerformTypeCheck()) {
- SanitizerSet SkippedChecks;
- SkippedChecks.set(SanitizerKind::Null, !NullCheckValue);
- EmitTypeCheck(TCK_Upcast, Loc, Value.getPointer(),
- DerivedTy, DerivedAlign, SkippedChecks);
- }
- return Builder.CreateBitCast(Value, BasePtrTy);
- }
-
- llvm::BasicBlock *origBB = nullptr;
- llvm::BasicBlock *endBB = nullptr;
-
- // Skip over the offset (and the vtable load) if we're supposed to
- // null-check the pointer.
- if (NullCheckValue) {
- origBB = Builder.GetInsertBlock();
- llvm::BasicBlock *notNullBB = createBasicBlock("cast.notnull");
- endBB = createBasicBlock("cast.end");
-
- llvm::Value *isNull = Builder.CreateIsNull(Value.getPointer());
- Builder.CreateCondBr(isNull, endBB, notNullBB);
- EmitBlock(notNullBB);
- }
-
- if (sanitizePerformTypeCheck()) {
- SanitizerSet SkippedChecks;
- SkippedChecks.set(SanitizerKind::Null, true);
- EmitTypeCheck(VBase ? TCK_UpcastToVirtualBase : TCK_Upcast, Loc,
- Value.getPointer(), DerivedTy, DerivedAlign, SkippedChecks);
- }
-
- // Compute the virtual offset.
- llvm::Value *VirtualOffset = nullptr;
- if (VBase) {
- VirtualOffset =
- CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase);
- }
-
- // Apply both offsets.
- Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset,
- VirtualOffset, Derived, VBase);
-
- // Cast to the destination type.
- Value = Builder.CreateBitCast(Value, BasePtrTy);
-
- // Build a phi if we needed a null check.
- if (NullCheckValue) {
- llvm::BasicBlock *notNullBB = Builder.GetInsertBlock();
- Builder.CreateBr(endBB);
- EmitBlock(endBB);
-
- llvm::PHINode *PHI = Builder.CreatePHI(BasePtrTy, 2, "cast.result");
- PHI->addIncoming(Value.getPointer(), notNullBB);
- PHI->addIncoming(llvm::Constant::getNullValue(BasePtrTy), origBB);
- Value = Address(PHI, Value.getAlignment());
- }
-
- return Value;
-}
-
-Address
-CodeGenFunction::GetAddressOfDerivedClass(Address BaseAddr,
- const CXXRecordDecl *Derived,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd,
- bool NullCheckValue) {
- assert(PathBegin != PathEnd && "Base path should not be empty!");
-
- QualType DerivedTy =
- getContext().getCanonicalType(getContext().getTagDeclType(Derived));
- llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
-
- llvm::Value *NonVirtualOffset =
- CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd);
-
- if (!NonVirtualOffset) {
- // No offset, we can just cast back.
- return Builder.CreateBitCast(BaseAddr, DerivedPtrTy);
- }
-
- llvm::BasicBlock *CastNull = nullptr;
- llvm::BasicBlock *CastNotNull = nullptr;
- llvm::BasicBlock *CastEnd = nullptr;
-
- if (NullCheckValue) {
- CastNull = createBasicBlock("cast.null");
- CastNotNull = createBasicBlock("cast.notnull");
- CastEnd = createBasicBlock("cast.end");
-
- llvm::Value *IsNull = Builder.CreateIsNull(BaseAddr.getPointer());
- Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
- EmitBlock(CastNotNull);
- }
-
- // Apply the offset.
- llvm::Value *Value = Builder.CreateBitCast(BaseAddr.getPointer(), Int8PtrTy);
- Value = Builder.CreateInBoundsGEP(Value, Builder.CreateNeg(NonVirtualOffset),
- "sub.ptr");
-
- // Just cast.
- Value = Builder.CreateBitCast(Value, DerivedPtrTy);
-
- // Produce a PHI if we had a null-check.
- if (NullCheckValue) {
- Builder.CreateBr(CastEnd);
- EmitBlock(CastNull);
- Builder.CreateBr(CastEnd);
- EmitBlock(CastEnd);
-
- llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2);
- PHI->addIncoming(Value, CastNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull);
- Value = PHI;
- }
-
- return Address(Value, CGM.getClassPointerAlignment(Derived));
-}
-
-llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
- bool ForVirtualBase,
- bool Delegating) {
- if (!CGM.getCXXABI().NeedsVTTParameter(GD)) {
- // This constructor/destructor does not need a VTT parameter.
- return nullptr;
- }
-
- const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurCodeDecl)->getParent();
- const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
-
- llvm::Value *VTT;
-
- uint64_t SubVTTIndex;
-
- if (Delegating) {
- // If this is a delegating constructor call, just load the VTT.
- return LoadCXXVTT();
- } else if (RD == Base) {
- // If the record matches the base, this is the complete ctor/dtor
- // variant calling the base variant in a class with virtual bases.
- assert(!CGM.getCXXABI().NeedsVTTParameter(CurGD) &&
- "doing no-op VTT offset in base dtor/ctor?");
- assert(!ForVirtualBase && "Can't have same class as virtual base!");
- SubVTTIndex = 0;
- } else {
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
- CharUnits BaseOffset = ForVirtualBase ?
- Layout.getVBaseClassOffset(Base) :
- Layout.getBaseClassOffset(Base);
-
- SubVTTIndex =
- CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
- assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
- }
-
- if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) {
- // A VTT parameter was passed to the constructor, use it.
- VTT = LoadCXXVTT();
- VTT = Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
- } else {
- // We're the complete constructor, so get the VTT by name.
- VTT = CGM.getVTables().GetAddrOfVTT(RD);
- VTT = Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
- }
-
- return VTT;
-}
-
-namespace {
- /// Call the destructor for a direct base class.
- struct CallBaseDtor final : EHScopeStack::Cleanup {
- const CXXRecordDecl *BaseClass;
- bool BaseIsVirtual;
- CallBaseDtor(const CXXRecordDecl *Base, bool BaseIsVirtual)
- : BaseClass(Base), BaseIsVirtual(BaseIsVirtual) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- const CXXRecordDecl *DerivedClass =
- cast<CXXMethodDecl>(CGF.CurCodeDecl)->getParent();
-
- const CXXDestructorDecl *D = BaseClass->getDestructor();
- Address Addr =
- CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThisAddress(),
- DerivedClass, BaseClass,
- BaseIsVirtual);
- CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual,
- /*Delegating=*/false, Addr);
- }
- };
-
- /// A visitor which checks whether an initializer uses 'this' in a
- /// way which requires the vtable to be properly set.
- struct DynamicThisUseChecker : ConstEvaluatedExprVisitor<DynamicThisUseChecker> {
- typedef ConstEvaluatedExprVisitor<DynamicThisUseChecker> super;
-
- bool UsesThis;
-
- DynamicThisUseChecker(const ASTContext &C) : super(C), UsesThis(false) {}
-
- // Black-list all explicit and implicit references to 'this'.
- //
- // Do we need to worry about external references to 'this' derived
- // from arbitrary code? If so, then anything which runs arbitrary
- // external code might potentially access the vtable.
- void VisitCXXThisExpr(const CXXThisExpr *E) { UsesThis = true; }
- };
-} // end anonymous namespace
-
-static bool BaseInitializerUsesThis(ASTContext &C, const Expr *Init) {
- DynamicThisUseChecker Checker(C);
- Checker.Visit(Init);
- return Checker.UsesThis;
-}
-
-static void EmitBaseInitializer(CodeGenFunction &CGF,
- const CXXRecordDecl *ClassDecl,
- CXXCtorInitializer *BaseInit,
- CXXCtorType CtorType) {
- assert(BaseInit->isBaseInitializer() &&
- "Must have base initializer!");
-
- Address ThisPtr = CGF.LoadCXXThisAddress();
-
- const Type *BaseType = BaseInit->getBaseClass();
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
-
- bool isBaseVirtual = BaseInit->isBaseVirtual();
-
- // The base constructor doesn't construct virtual bases.
- if (CtorType == Ctor_Base && isBaseVirtual)
- return;
-
- // If the initializer for the base (other than the constructor
- // itself) accesses 'this' in any way, we need to initialize the
- // vtables.
- if (BaseInitializerUsesThis(CGF.getContext(), BaseInit->getInit()))
- CGF.InitializeVTablePointers(ClassDecl);
-
- // We can pretend to be a complete class because it only matters for
- // virtual bases, and we only do virtual bases for complete ctors.
- Address V =
- CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl,
- BaseClassDecl,
- isBaseVirtual);
- AggValueSlot AggSlot =
- AggValueSlot::forAddr(
- V, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- CGF.overlapForBaseInit(ClassDecl, BaseClassDecl, isBaseVirtual));
-
- CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
-
- if (CGF.CGM.getLangOpts().Exceptions &&
- !BaseClassDecl->hasTrivialDestructor())
- CGF.EHStack.pushCleanup<CallBaseDtor>(EHCleanup, BaseClassDecl,
- isBaseVirtual);
-}
-
-static bool isMemcpyEquivalentSpecialMember(const CXXMethodDecl *D) {
- auto *CD = dyn_cast<CXXConstructorDecl>(D);
- if (!(CD && CD->isCopyOrMoveConstructor()) &&
- !D->isCopyAssignmentOperator() && !D->isMoveAssignmentOperator())
- return false;
-
- // We can emit a memcpy for a trivial copy or move constructor/assignment.
- if (D->isTrivial() && !D->getParent()->mayInsertExtraPadding())
- return true;
-
- // We *must* emit a memcpy for a defaulted union copy or move op.
- if (D->getParent()->isUnion() && D->isDefaulted())
- return true;
-
- return false;
-}
-
-static void EmitLValueForAnyFieldInitialization(CodeGenFunction &CGF,
- CXXCtorInitializer *MemberInit,
- LValue &LHS) {
- FieldDecl *Field = MemberInit->getAnyMember();
- if (MemberInit->isIndirectMemberInitializer()) {
- // If we are initializing an anonymous union field, drill down to the field.
- IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember();
- for (const auto *I : IndirectField->chain())
- LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I));
- } else {
- LHS = CGF.EmitLValueForFieldInitialization(LHS, Field);
- }
-}
-
-static void EmitMemberInitializer(CodeGenFunction &CGF,
- const CXXRecordDecl *ClassDecl,
- CXXCtorInitializer *MemberInit,
- const CXXConstructorDecl *Constructor,
- FunctionArgList &Args) {
- ApplyDebugLocation Loc(CGF, MemberInit->getSourceLocation());
- assert(MemberInit->isAnyMemberInitializer() &&
- "Must have member initializer!");
- assert(MemberInit->getInit() && "Must have initializer!");
-
- // non-static data member initializers.
- FieldDecl *Field = MemberInit->getAnyMember();
- QualType FieldType = Field->getType();
-
- llvm::Value *ThisPtr = CGF.LoadCXXThis();
- QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
- LValue LHS;
-
- // If a base constructor is being emitted, create an LValue that has the
- // non-virtual alignment.
- if (CGF.CurGD.getCtorType() == Ctor_Base)
- LHS = CGF.MakeNaturalAlignPointeeAddrLValue(ThisPtr, RecordTy);
- else
- LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
-
- EmitLValueForAnyFieldInitialization(CGF, MemberInit, LHS);
-
- // Special case: if we are in a copy or move constructor, and we are copying
- // an array of PODs or classes with trivial copy constructors, ignore the
- // AST and perform the copy we know is equivalent.
- // FIXME: This is hacky at best... if we had a bit more explicit information
- // in the AST, we could generalize it more easily.
- const ConstantArrayType *Array
- = CGF.getContext().getAsConstantArrayType(FieldType);
- if (Array && Constructor->isDefaulted() &&
- Constructor->isCopyOrMoveConstructor()) {
- QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
- CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
- if (BaseElementTy.isPODType(CGF.getContext()) ||
- (CE && isMemcpyEquivalentSpecialMember(CE->getConstructor()))) {
- unsigned SrcArgIndex =
- CGF.CGM.getCXXABI().getSrcArgforCopyCtor(Constructor, Args);
- llvm::Value *SrcPtr
- = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
- LValue ThisRHSLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
- LValue Src = CGF.EmitLValueForFieldInitialization(ThisRHSLV, Field);
-
- // Copy the aggregate.
- CGF.EmitAggregateCopy(LHS, Src, FieldType, CGF.overlapForFieldInit(Field),
- LHS.isVolatileQualified());
- // Ensure that we destroy the objects if an exception is thrown later in
- // the constructor.
- QualType::DestructionKind dtorKind = FieldType.isDestructedType();
- if (CGF.needsEHCleanup(dtorKind))
- CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
- return;
- }
- }
-
- CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit());
-}
-
-void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS,
- Expr *Init) {
- QualType FieldType = Field->getType();
- switch (getEvaluationKind(FieldType)) {
- case TEK_Scalar:
- if (LHS.isSimple()) {
- EmitExprAsInit(Init, Field, LHS, false);
- } else {
- RValue RHS = RValue::get(EmitScalarExpr(Init));
- EmitStoreThroughLValue(RHS, LHS);
- }
- break;
- case TEK_Complex:
- EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
- break;
- case TEK_Aggregate: {
- AggValueSlot Slot =
- AggValueSlot::forLValue(
- LHS,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- overlapForFieldInit(Field),
- AggValueSlot::IsNotZeroed,
- // Checks are made by the code that calls constructor.
- AggValueSlot::IsSanitizerChecked);
- EmitAggExpr(Init, Slot);
- break;
- }
- }
-
- // Ensure that we destroy this object if an exception is thrown
- // later in the constructor.
- QualType::DestructionKind dtorKind = FieldType.isDestructedType();
- if (needsEHCleanup(dtorKind))
- pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
-}
-
-/// Checks whether the given constructor is a valid subject for the
-/// complete-to-base constructor delegation optimization, i.e.
-/// emitting the complete constructor as a simple call to the base
-/// constructor.
-bool CodeGenFunction::IsConstructorDelegationValid(
- const CXXConstructorDecl *Ctor) {
-
- // Currently we disable the optimization for classes with virtual
- // bases because (1) the addresses of parameter variables need to be
- // consistent across all initializers but (2) the delegate function
- // call necessarily creates a second copy of the parameter variable.
- //
- // The limiting example (purely theoretical AFAIK):
- // struct A { A(int &c) { c++; } };
- // struct B : virtual A {
- // B(int count) : A(count) { printf("%d\n", count); }
- // };
- // ...although even this example could in principle be emitted as a
- // delegation since the address of the parameter doesn't escape.
- if (Ctor->getParent()->getNumVBases()) {
- // TODO: white-list trivial vbase initializers. This case wouldn't
- // be subject to the restrictions below.
-
- // TODO: white-list cases where:
- // - there are no non-reference parameters to the constructor
- // - the initializers don't access any non-reference parameters
- // - the initializers don't take the address of non-reference
- // parameters
- // - etc.
- // If we ever add any of the above cases, remember that:
- // - function-try-blocks will always blacklist this optimization
- // - we need to perform the constructor prologue and cleanup in
- // EmitConstructorBody.
-
- return false;
- }
-
- // We also disable the optimization for variadic functions because
- // it's impossible to "re-pass" varargs.
- if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic())
- return false;
-
- // FIXME: Decide if we can do a delegation of a delegating constructor.
- if (Ctor->isDelegatingConstructor())
- return false;
-
- return true;
-}
-
-// Emit code in ctor (Prologue==true) or dtor (Prologue==false)
-// to poison the extra field paddings inserted under
-// -fsanitize-address-field-padding=1|2.
-void CodeGenFunction::EmitAsanPrologueOrEpilogue(bool Prologue) {
- ASTContext &Context = getContext();
- const CXXRecordDecl *ClassDecl =
- Prologue ? cast<CXXConstructorDecl>(CurGD.getDecl())->getParent()
- : cast<CXXDestructorDecl>(CurGD.getDecl())->getParent();
- if (!ClassDecl->mayInsertExtraPadding()) return;
-
- struct SizeAndOffset {
- uint64_t Size;
- uint64_t Offset;
- };
-
- unsigned PtrSize = CGM.getDataLayout().getPointerSizeInBits();
- const ASTRecordLayout &Info = Context.getASTRecordLayout(ClassDecl);
-
- // Populate sizes and offsets of fields.
- SmallVector<SizeAndOffset, 16> SSV(Info.getFieldCount());
- for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i)
- SSV[i].Offset =
- Context.toCharUnitsFromBits(Info.getFieldOffset(i)).getQuantity();
-
- size_t NumFields = 0;
- for (const auto *Field : ClassDecl->fields()) {
- const FieldDecl *D = Field;
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(D->getType());
- CharUnits FieldSize = FieldInfo.first;
- assert(NumFields < SSV.size());
- SSV[NumFields].Size = D->isBitField() ? 0 : FieldSize.getQuantity();
- NumFields++;
- }
- assert(NumFields == SSV.size());
- if (SSV.size() <= 1) return;
-
- // We will insert calls to __asan_* run-time functions.
- // LLVM AddressSanitizer pass may decide to inline them later.
- llvm::Type *Args[2] = {IntPtrTy, IntPtrTy};
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, Args, false);
- llvm::Constant *F = CGM.CreateRuntimeFunction(
- FTy, Prologue ? "__asan_poison_intra_object_redzone"
- : "__asan_unpoison_intra_object_redzone");
-
- llvm::Value *ThisPtr = LoadCXXThis();
- ThisPtr = Builder.CreatePtrToInt(ThisPtr, IntPtrTy);
- uint64_t TypeSize = Info.getNonVirtualSize().getQuantity();
- // For each field check if it has sufficient padding,
- // if so (un)poison it with a call.
- for (size_t i = 0; i < SSV.size(); i++) {
- uint64_t AsanAlignment = 8;
- uint64_t NextField = i == SSV.size() - 1 ? TypeSize : SSV[i + 1].Offset;
- uint64_t PoisonSize = NextField - SSV[i].Offset - SSV[i].Size;
- uint64_t EndOffset = SSV[i].Offset + SSV[i].Size;
- if (PoisonSize < AsanAlignment || !SSV[i].Size ||
- (NextField % AsanAlignment) != 0)
- continue;
- Builder.CreateCall(
- F, {Builder.CreateAdd(ThisPtr, Builder.getIntN(PtrSize, EndOffset)),
- Builder.getIntN(PtrSize, PoisonSize)});
- }
-}
-
-/// EmitConstructorBody - Emits the body of the current constructor.
-void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
- EmitAsanPrologueOrEpilogue(true);
- const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
- CXXCtorType CtorType = CurGD.getCtorType();
-
- assert((CGM.getTarget().getCXXABI().hasConstructorVariants() ||
- CtorType == Ctor_Complete) &&
- "can only generate complete ctor for this ABI");
-
- // Before we go any further, try the complete->base constructor
- // delegation optimization.
- if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
- CGM.getTarget().getCXXABI().hasConstructorVariants()) {
- EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args, Ctor->getEndLoc());
- return;
- }
-
- const FunctionDecl *Definition = nullptr;
- Stmt *Body = Ctor->getBody(Definition);
- assert(Definition == Ctor && "emitting wrong constructor body");
-
- // Enter the function-try-block before the constructor prologue if
- // applicable.
- bool IsTryBody = (Body && isa<CXXTryStmt>(Body));
- if (IsTryBody)
- EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
-
- incrementProfileCounter(Body);
-
- RunCleanupsScope RunCleanups(*this);
-
- // TODO: in restricted cases, we can emit the vbase initializers of
- // a complete ctor and then delegate to the base ctor.
-
- // Emit the constructor prologue, i.e. the base and member
- // initializers.
- EmitCtorPrologue(Ctor, CtorType, Args);
-
- // Emit the body of the statement.
- if (IsTryBody)
- EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
- else if (Body)
- EmitStmt(Body);
-
- // Emit any cleanup blocks associated with the member or base
- // initializers, which includes (along the exceptional path) the
- // destructors for those members and bases that were fully
- // constructed.
- RunCleanups.ForceCleanup();
-
- if (IsTryBody)
- ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
-}
-
-namespace {
- /// RAII object to indicate that codegen is copying the value representation
- /// instead of the object representation. Useful when copying a struct or
- /// class which has uninitialized members and we're only performing
- /// lvalue-to-rvalue conversion on the object but not its members.
- class CopyingValueRepresentation {
- public:
- explicit CopyingValueRepresentation(CodeGenFunction &CGF)
- : CGF(CGF), OldSanOpts(CGF.SanOpts) {
- CGF.SanOpts.set(SanitizerKind::Bool, false);
- CGF.SanOpts.set(SanitizerKind::Enum, false);
- }
- ~CopyingValueRepresentation() {
- CGF.SanOpts = OldSanOpts;
- }
- private:
- CodeGenFunction &CGF;
- SanitizerSet OldSanOpts;
- };
-} // end anonymous namespace
-
-namespace {
- class FieldMemcpyizer {
- public:
- FieldMemcpyizer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl,
- const VarDecl *SrcRec)
- : CGF(CGF), ClassDecl(ClassDecl), SrcRec(SrcRec),
- RecLayout(CGF.getContext().getASTRecordLayout(ClassDecl)),
- FirstField(nullptr), LastField(nullptr), FirstFieldOffset(0),
- LastFieldOffset(0), LastAddedFieldIndex(0) {}
-
- bool isMemcpyableField(FieldDecl *F) const {
- // Never memcpy fields when we are adding poisoned paddings.
- if (CGF.getContext().getLangOpts().SanitizeAddressFieldPadding)
- return false;
- Qualifiers Qual = F->getType().getQualifiers();
- if (Qual.hasVolatile() || Qual.hasObjCLifetime())
- return false;
- return true;
- }
-
- void addMemcpyableField(FieldDecl *F) {
- if (!FirstField)
- addInitialField(F);
- else
- addNextField(F);
- }
-
- CharUnits getMemcpySize(uint64_t FirstByteOffset) const {
- ASTContext &Ctx = CGF.getContext();
- unsigned LastFieldSize =
- LastField->isBitField()
- ? LastField->getBitWidthValue(Ctx)
- : Ctx.toBits(
- Ctx.getTypeInfoDataSizeInChars(LastField->getType()).first);
- uint64_t MemcpySizeBits = LastFieldOffset + LastFieldSize -
- FirstByteOffset + Ctx.getCharWidth() - 1;
- CharUnits MemcpySize = Ctx.toCharUnitsFromBits(MemcpySizeBits);
- return MemcpySize;
- }
-
- void emitMemcpy() {
- // Give the subclass a chance to bail out if it feels the memcpy isn't
- // worth it (e.g. Hasn't aggregated enough data).
- if (!FirstField) {
- return;
- }
-
- uint64_t FirstByteOffset;
- if (FirstField->isBitField()) {
- const CGRecordLayout &RL =
- CGF.getTypes().getCGRecordLayout(FirstField->getParent());
- const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField);
- // FirstFieldOffset is not appropriate for bitfields,
- // we need to use the storage offset instead.
- FirstByteOffset = CGF.getContext().toBits(BFInfo.StorageOffset);
- } else {
- FirstByteOffset = FirstFieldOffset;
- }
-
- CharUnits MemcpySize = getMemcpySize(FirstByteOffset);
- QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
- Address ThisPtr = CGF.LoadCXXThisAddress();
- LValue DestLV = CGF.MakeAddrLValue(ThisPtr, RecordTy);
- LValue Dest = CGF.EmitLValueForFieldInitialization(DestLV, FirstField);
- llvm::Value *SrcPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(SrcRec));
- LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
- LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField);
-
- emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddress() : Dest.getAddress(),
- Src.isBitField() ? Src.getBitFieldAddress() : Src.getAddress(),
- MemcpySize);
- reset();
- }
-
- void reset() {
- FirstField = nullptr;
- }
-
- protected:
- CodeGenFunction &CGF;
- const CXXRecordDecl *ClassDecl;
-
- private:
- void emitMemcpyIR(Address DestPtr, Address SrcPtr, CharUnits Size) {
- llvm::PointerType *DPT = DestPtr.getType();
- llvm::Type *DBP =
- llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), DPT->getAddressSpace());
- DestPtr = CGF.Builder.CreateBitCast(DestPtr, DBP);
-
- llvm::PointerType *SPT = SrcPtr.getType();
- llvm::Type *SBP =
- llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), SPT->getAddressSpace());
- SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, SBP);
-
- CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, Size.getQuantity());
- }
-
- void addInitialField(FieldDecl *F) {
- FirstField = F;
- LastField = F;
- FirstFieldOffset = RecLayout.getFieldOffset(F->getFieldIndex());
- LastFieldOffset = FirstFieldOffset;
- LastAddedFieldIndex = F->getFieldIndex();
- }
-
- void addNextField(FieldDecl *F) {
- // For the most part, the following invariant will hold:
- // F->getFieldIndex() == LastAddedFieldIndex + 1
- // The one exception is that Sema won't add a copy-initializer for an
- // unnamed bitfield, which will show up here as a gap in the sequence.
- assert(F->getFieldIndex() >= LastAddedFieldIndex + 1 &&
- "Cannot aggregate fields out of order.");
- LastAddedFieldIndex = F->getFieldIndex();
-
- // The 'first' and 'last' fields are chosen by offset, rather than field
- // index. This allows the code to support bitfields, as well as regular
- // fields.
- uint64_t FOffset = RecLayout.getFieldOffset(F->getFieldIndex());
- if (FOffset < FirstFieldOffset) {
- FirstField = F;
- FirstFieldOffset = FOffset;
- } else if (FOffset > LastFieldOffset) {
- LastField = F;
- LastFieldOffset = FOffset;
- }
- }
-
- const VarDecl *SrcRec;
- const ASTRecordLayout &RecLayout;
- FieldDecl *FirstField;
- FieldDecl *LastField;
- uint64_t FirstFieldOffset, LastFieldOffset;
- unsigned LastAddedFieldIndex;
- };
-
- class ConstructorMemcpyizer : public FieldMemcpyizer {
- private:
- /// Get source argument for copy constructor. Returns null if not a copy
- /// constructor.
- static const VarDecl *getTrivialCopySource(CodeGenFunction &CGF,
- const CXXConstructorDecl *CD,
- FunctionArgList &Args) {
- if (CD->isCopyOrMoveConstructor() && CD->isDefaulted())
- return Args[CGF.CGM.getCXXABI().getSrcArgforCopyCtor(CD, Args)];
- return nullptr;
- }
-
- // Returns true if a CXXCtorInitializer represents a member initialization
- // that can be rolled into a memcpy.
- bool isMemberInitMemcpyable(CXXCtorInitializer *MemberInit) const {
- if (!MemcpyableCtor)
- return false;
- FieldDecl *Field = MemberInit->getMember();
- assert(Field && "No field for member init.");
- QualType FieldType = Field->getType();
- CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
-
- // Bail out on non-memcpyable, not-trivially-copyable members.
- if (!(CE && isMemcpyEquivalentSpecialMember(CE->getConstructor())) &&
- !(FieldType.isTriviallyCopyableType(CGF.getContext()) ||
- FieldType->isReferenceType()))
- return false;
-
- // Bail out on volatile fields.
- if (!isMemcpyableField(Field))
- return false;
-
- // Otherwise we're good.
- return true;
- }
-
- public:
- ConstructorMemcpyizer(CodeGenFunction &CGF, const CXXConstructorDecl *CD,
- FunctionArgList &Args)
- : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CGF, CD, Args)),
- ConstructorDecl(CD),
- MemcpyableCtor(CD->isDefaulted() &&
- CD->isCopyOrMoveConstructor() &&
- CGF.getLangOpts().getGC() == LangOptions::NonGC),
- Args(Args) { }
-
- void addMemberInitializer(CXXCtorInitializer *MemberInit) {
- if (isMemberInitMemcpyable(MemberInit)) {
- AggregatedInits.push_back(MemberInit);
- addMemcpyableField(MemberInit->getMember());
- } else {
- emitAggregatedInits();
- EmitMemberInitializer(CGF, ConstructorDecl->getParent(), MemberInit,
- ConstructorDecl, Args);
- }
- }
-
- void emitAggregatedInits() {
- if (AggregatedInits.size() <= 1) {
- // This memcpy is too small to be worthwhile. Fall back on default
- // codegen.
- if (!AggregatedInits.empty()) {
- CopyingValueRepresentation CVR(CGF);
- EmitMemberInitializer(CGF, ConstructorDecl->getParent(),
- AggregatedInits[0], ConstructorDecl, Args);
- AggregatedInits.clear();
- }
- reset();
- return;
- }
-
- pushEHDestructors();
- emitMemcpy();
- AggregatedInits.clear();
- }
-
- void pushEHDestructors() {
- Address ThisPtr = CGF.LoadCXXThisAddress();
- QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
- LValue LHS = CGF.MakeAddrLValue(ThisPtr, RecordTy);
-
- for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
- CXXCtorInitializer *MemberInit = AggregatedInits[i];
- QualType FieldType = MemberInit->getAnyMember()->getType();
- QualType::DestructionKind dtorKind = FieldType.isDestructedType();
- if (!CGF.needsEHCleanup(dtorKind))
- continue;
- LValue FieldLHS = LHS;
- EmitLValueForAnyFieldInitialization(CGF, MemberInit, FieldLHS);
- CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType);
- }
- }
-
- void finish() {
- emitAggregatedInits();
- }
-
- private:
- const CXXConstructorDecl *ConstructorDecl;
- bool MemcpyableCtor;
- FunctionArgList &Args;
- SmallVector<CXXCtorInitializer*, 16> AggregatedInits;
- };
-
- class AssignmentMemcpyizer : public FieldMemcpyizer {
- private:
- // Returns the memcpyable field copied by the given statement, if one
- // exists. Otherwise returns null.
- FieldDecl *getMemcpyableField(Stmt *S) {
- if (!AssignmentsMemcpyable)
- return nullptr;
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
- // Recognise trivial assignments.
- if (BO->getOpcode() != BO_Assign)
- return nullptr;
- MemberExpr *ME = dyn_cast<MemberExpr>(BO->getLHS());
- if (!ME)
- return nullptr;
- FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (!Field || !isMemcpyableField(Field))
- return nullptr;
- Stmt *RHS = BO->getRHS();
- if (ImplicitCastExpr *EC = dyn_cast<ImplicitCastExpr>(RHS))
- RHS = EC->getSubExpr();
- if (!RHS)
- return nullptr;
- if (MemberExpr *ME2 = dyn_cast<MemberExpr>(RHS)) {
- if (ME2->getMemberDecl() == Field)
- return Field;
- }
- return nullptr;
- } else if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(S)) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MCE->getCalleeDecl());
- if (!(MD && isMemcpyEquivalentSpecialMember(MD)))
- return nullptr;
- MemberExpr *IOA = dyn_cast<MemberExpr>(MCE->getImplicitObjectArgument());
- if (!IOA)
- return nullptr;
- FieldDecl *Field = dyn_cast<FieldDecl>(IOA->getMemberDecl());
- if (!Field || !isMemcpyableField(Field))
- return nullptr;
- MemberExpr *Arg0 = dyn_cast<MemberExpr>(MCE->getArg(0));
- if (!Arg0 || Field != dyn_cast<FieldDecl>(Arg0->getMemberDecl()))
- return nullptr;
- return Field;
- } else if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
- FunctionDecl *FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
- if (!FD || FD->getBuiltinID() != Builtin::BI__builtin_memcpy)
- return nullptr;
- Expr *DstPtr = CE->getArg(0);
- if (ImplicitCastExpr *DC = dyn_cast<ImplicitCastExpr>(DstPtr))
- DstPtr = DC->getSubExpr();
- UnaryOperator *DUO = dyn_cast<UnaryOperator>(DstPtr);
- if (!DUO || DUO->getOpcode() != UO_AddrOf)
- return nullptr;
- MemberExpr *ME = dyn_cast<MemberExpr>(DUO->getSubExpr());
- if (!ME)
- return nullptr;
- FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (!Field || !isMemcpyableField(Field))
- return nullptr;
- Expr *SrcPtr = CE->getArg(1);
- if (ImplicitCastExpr *SC = dyn_cast<ImplicitCastExpr>(SrcPtr))
- SrcPtr = SC->getSubExpr();
- UnaryOperator *SUO = dyn_cast<UnaryOperator>(SrcPtr);
- if (!SUO || SUO->getOpcode() != UO_AddrOf)
- return nullptr;
- MemberExpr *ME2 = dyn_cast<MemberExpr>(SUO->getSubExpr());
- if (!ME2 || Field != dyn_cast<FieldDecl>(ME2->getMemberDecl()))
- return nullptr;
- return Field;
- }
-
- return nullptr;
- }
-
- bool AssignmentsMemcpyable;
- SmallVector<Stmt*, 16> AggregatedStmts;
-
- public:
- AssignmentMemcpyizer(CodeGenFunction &CGF, const CXXMethodDecl *AD,
- FunctionArgList &Args)
- : FieldMemcpyizer(CGF, AD->getParent(), Args[Args.size() - 1]),
- AssignmentsMemcpyable(CGF.getLangOpts().getGC() == LangOptions::NonGC) {
- assert(Args.size() == 2);
- }
-
- void emitAssignment(Stmt *S) {
- FieldDecl *F = getMemcpyableField(S);
- if (F) {
- addMemcpyableField(F);
- AggregatedStmts.push_back(S);
- } else {
- emitAggregatedStmts();
- CGF.EmitStmt(S);
- }
- }
-
- void emitAggregatedStmts() {
- if (AggregatedStmts.size() <= 1) {
- if (!AggregatedStmts.empty()) {
- CopyingValueRepresentation CVR(CGF);
- CGF.EmitStmt(AggregatedStmts[0]);
- }
- reset();
- }
-
- emitMemcpy();
- AggregatedStmts.clear();
- }
-
- void finish() {
- emitAggregatedStmts();
- }
- };
-} // end anonymous namespace
-
-static bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) {
- const Type *BaseType = BaseInit->getBaseClass();
- const auto *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- return BaseClassDecl->isDynamicClass();
-}
-
-/// EmitCtorPrologue - This routine generates necessary code to initialize
-/// base classes and non-static data members belonging to this constructor.
-void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
- CXXCtorType CtorType,
- FunctionArgList &Args) {
- if (CD->isDelegatingConstructor())
- return EmitDelegatingCXXConstructorCall(CD, Args);
-
- const CXXRecordDecl *ClassDecl = CD->getParent();
-
- CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
- E = CD->init_end();
-
- llvm::BasicBlock *BaseCtorContinueBB = nullptr;
- if (ClassDecl->getNumVBases() &&
- !CGM.getTarget().getCXXABI().hasConstructorVariants()) {
- // The ABIs that don't have constructor variants need to put a branch
- // before the virtual base initialization code.
- BaseCtorContinueBB =
- CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this, ClassDecl);
- assert(BaseCtorContinueBB);
- }
-
- llvm::Value *const OldThis = CXXThisValue;
- // Virtual base initializers first.
- for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) {
- if (CGM.getCodeGenOpts().StrictVTablePointers &&
- CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- isInitializerOfDynamicClass(*B))
- CXXThisValue = Builder.CreateLaunderInvariantGroup(LoadCXXThis());
- EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
- }
-
- if (BaseCtorContinueBB) {
- // Complete object handler should continue to the remaining initializers.
- Builder.CreateBr(BaseCtorContinueBB);
- EmitBlock(BaseCtorContinueBB);
- }
-
- // Then, non-virtual base initializers.
- for (; B != E && (*B)->isBaseInitializer(); B++) {
- assert(!(*B)->isBaseVirtual());
-
- if (CGM.getCodeGenOpts().StrictVTablePointers &&
- CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- isInitializerOfDynamicClass(*B))
- CXXThisValue = Builder.CreateLaunderInvariantGroup(LoadCXXThis());
- EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
- }
-
- CXXThisValue = OldThis;
-
- InitializeVTablePointers(ClassDecl);
-
- // And finally, initialize class members.
- FieldConstructionScope FCS(*this, LoadCXXThisAddress());
- ConstructorMemcpyizer CM(*this, CD, Args);
- for (; B != E; B++) {
- CXXCtorInitializer *Member = (*B);
- assert(!Member->isBaseInitializer());
- assert(Member->isAnyMemberInitializer() &&
- "Delegating initializer on non-delegating constructor");
- CM.addMemberInitializer(Member);
- }
- CM.finish();
-}
-
-static bool
-FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field);
-
-static bool
-HasTrivialDestructorBody(ASTContext &Context,
- const CXXRecordDecl *BaseClassDecl,
- const CXXRecordDecl *MostDerivedClassDecl)
-{
- // If the destructor is trivial we don't have to check anything else.
- if (BaseClassDecl->hasTrivialDestructor())
- return true;
-
- if (!BaseClassDecl->getDestructor()->hasTrivialBody())
- return false;
-
- // Check fields.
- for (const auto *Field : BaseClassDecl->fields())
- if (!FieldHasTrivialDestructorBody(Context, Field))
- return false;
-
- // Check non-virtual bases.
- for (const auto &I : BaseClassDecl->bases()) {
- if (I.isVirtual())
- continue;
-
- const CXXRecordDecl *NonVirtualBase =
- cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
- if (!HasTrivialDestructorBody(Context, NonVirtualBase,
- MostDerivedClassDecl))
- return false;
- }
-
- if (BaseClassDecl == MostDerivedClassDecl) {
- // Check virtual bases.
- for (const auto &I : BaseClassDecl->vbases()) {
- const CXXRecordDecl *VirtualBase =
- cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
- if (!HasTrivialDestructorBody(Context, VirtualBase,
- MostDerivedClassDecl))
- return false;
- }
- }
-
- return true;
-}
-
-static bool
-FieldHasTrivialDestructorBody(ASTContext &Context,
- const FieldDecl *Field)
-{
- QualType FieldBaseElementType = Context.getBaseElementType(Field->getType());
-
- const RecordType *RT = FieldBaseElementType->getAs<RecordType>();
- if (!RT)
- return true;
-
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
-
- // The destructor for an implicit anonymous union member is never invoked.
- if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
- return false;
-
- return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
-}
-
-/// CanSkipVTablePointerInitialization - Check whether we need to initialize
-/// any vtable pointers before calling this destructor.
-static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor) {
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- if (!ClassDecl->isDynamicClass())
- return true;
-
- if (!Dtor->hasTrivialBody())
- return false;
-
- // Check the fields.
- for (const auto *Field : ClassDecl->fields())
- if (!FieldHasTrivialDestructorBody(CGF.getContext(), Field))
- return false;
-
- return true;
-}
-
-/// EmitDestructorBody - Emits the body of the current destructor.
-void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
- const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
- CXXDtorType DtorType = CurGD.getDtorType();
-
- // For an abstract class, non-base destructors are never used (and can't
- // be emitted in general, because vbase dtors may not have been validated
- // by Sema), but the Itanium ABI doesn't make them optional and Clang may
- // in fact emit references to them from other compilations, so emit them
- // as functions containing a trap instruction.
- if (DtorType != Dtor_Base && Dtor->getParent()->isAbstract()) {
- llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
- TrapCall->setDoesNotReturn();
- TrapCall->setDoesNotThrow();
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
- return;
- }
-
- Stmt *Body = Dtor->getBody();
- if (Body)
- incrementProfileCounter(Body);
-
- // The call to operator delete in a deleting destructor happens
- // outside of the function-try-block, which means it's always
- // possible to delegate the destructor body to the complete
- // destructor. Do so.
- if (DtorType == Dtor_Deleting) {
- RunCleanupsScope DtorEpilogue(*this);
- EnterDtorCleanups(Dtor, Dtor_Deleting);
- if (HaveInsertPoint())
- EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- /*Delegating=*/false, LoadCXXThisAddress());
- return;
- }
-
- // If the body is a function-try-block, enter the try before
- // anything else.
- bool isTryBody = (Body && isa<CXXTryStmt>(Body));
- if (isTryBody)
- EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
- EmitAsanPrologueOrEpilogue(false);
-
- // Enter the epilogue cleanups.
- RunCleanupsScope DtorEpilogue(*this);
-
- // If this is the complete variant, just invoke the base variant;
- // the epilogue will destruct the virtual bases. But we can't do
- // this optimization if the body is a function-try-block, because
- // we'd introduce *two* handler blocks. In the Microsoft ABI, we
- // always delegate because we might not have a definition in this TU.
- switch (DtorType) {
- case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
- case Dtor_Deleting: llvm_unreachable("already handled deleting case");
-
- case Dtor_Complete:
- assert((Body || getTarget().getCXXABI().isMicrosoft()) &&
- "can't emit a dtor without a body for non-Microsoft ABIs");
-
- // Enter the cleanup scopes for virtual bases.
- EnterDtorCleanups(Dtor, Dtor_Complete);
-
- if (!isTryBody) {
- EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
- /*Delegating=*/false, LoadCXXThisAddress());
- break;
- }
-
- // Fallthrough: act like we're in the base variant.
- LLVM_FALLTHROUGH;
-
- case Dtor_Base:
- assert(Body);
-
- // Enter the cleanup scopes for fields and non-virtual bases.
- EnterDtorCleanups(Dtor, Dtor_Base);
-
- // Initialize the vtable pointers before entering the body.
- if (!CanSkipVTablePointerInitialization(*this, Dtor)) {
- // Insert the llvm.launder.invariant.group intrinsic before initializing
- // the vptrs to cancel any previous assumptions we might have made.
- if (CGM.getCodeGenOpts().StrictVTablePointers &&
- CGM.getCodeGenOpts().OptimizationLevel > 0)
- CXXThisValue = Builder.CreateLaunderInvariantGroup(LoadCXXThis());
- InitializeVTablePointers(Dtor->getParent());
- }
-
- if (isTryBody)
- EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
- else if (Body)
- EmitStmt(Body);
- else {
- assert(Dtor->isImplicit() && "bodyless dtor not implicit");
- // nothing to do besides what's in the epilogue
- }
- // -fapple-kext must inline any call to this dtor into
- // the caller's body.
- if (getLangOpts().AppleKext)
- CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
-
- break;
- }
-
- // Jump out through the epilogue cleanups.
- DtorEpilogue.ForceCleanup();
-
- // Exit the try if applicable.
- if (isTryBody)
- ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
-}
-
-void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) {
- const CXXMethodDecl *AssignOp = cast<CXXMethodDecl>(CurGD.getDecl());
- const Stmt *RootS = AssignOp->getBody();
- assert(isa<CompoundStmt>(RootS) &&
- "Body of an implicit assignment operator should be compound stmt.");
- const CompoundStmt *RootCS = cast<CompoundStmt>(RootS);
-
- LexicalScope Scope(*this, RootCS->getSourceRange());
-
- incrementProfileCounter(RootCS);
- AssignmentMemcpyizer AM(*this, AssignOp, Args);
- for (auto *I : RootCS->body())
- AM.emitAssignment(I);
- AM.finish();
-}
-
-namespace {
- llvm::Value *LoadThisForDtorDelete(CodeGenFunction &CGF,
- const CXXDestructorDecl *DD) {
- if (Expr *ThisArg = DD->getOperatorDeleteThisArg())
- return CGF.EmitScalarExpr(ThisArg);
- return CGF.LoadCXXThis();
- }
-
- /// Call the operator delete associated with the current destructor.
- struct CallDtorDelete final : EHScopeStack::Cleanup {
- CallDtorDelete() {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- CGF.EmitDeleteCall(Dtor->getOperatorDelete(),
- LoadThisForDtorDelete(CGF, Dtor),
- CGF.getContext().getTagDeclType(ClassDecl));
- }
- };
-
- void EmitConditionalDtorDeleteCall(CodeGenFunction &CGF,
- llvm::Value *ShouldDeleteCondition,
- bool ReturnAfterDelete) {
- llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
- llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
- llvm::Value *ShouldCallDelete
- = CGF.Builder.CreateIsNull(ShouldDeleteCondition);
- CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);
-
- CGF.EmitBlock(callDeleteBB);
- const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- CGF.EmitDeleteCall(Dtor->getOperatorDelete(),
- LoadThisForDtorDelete(CGF, Dtor),
- CGF.getContext().getTagDeclType(ClassDecl));
- assert(Dtor->getOperatorDelete()->isDestroyingOperatorDelete() ==
- ReturnAfterDelete &&
- "unexpected value for ReturnAfterDelete");
- if (ReturnAfterDelete)
- CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
- else
- CGF.Builder.CreateBr(continueBB);
-
- CGF.EmitBlock(continueBB);
- }
-
- struct CallDtorDeleteConditional final : EHScopeStack::Cleanup {
- llvm::Value *ShouldDeleteCondition;
-
- public:
- CallDtorDeleteConditional(llvm::Value *ShouldDeleteCondition)
- : ShouldDeleteCondition(ShouldDeleteCondition) {
- assert(ShouldDeleteCondition != nullptr);
- }
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- EmitConditionalDtorDeleteCall(CGF, ShouldDeleteCondition,
- /*ReturnAfterDelete*/false);
- }
- };
-
- class DestroyField final : public EHScopeStack::Cleanup {
- const FieldDecl *field;
- CodeGenFunction::Destroyer *destroyer;
- bool useEHCleanupForArray;
-
- public:
- DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer,
- bool useEHCleanupForArray)
- : field(field), destroyer(destroyer),
- useEHCleanupForArray(useEHCleanupForArray) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Find the address of the field.
- Address thisValue = CGF.LoadCXXThisAddress();
- QualType RecordTy = CGF.getContext().getTagDeclType(field->getParent());
- LValue ThisLV = CGF.MakeAddrLValue(thisValue, RecordTy);
- LValue LV = CGF.EmitLValueForField(ThisLV, field);
- assert(LV.isSimple());
-
- CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer,
- flags.isForNormalCleanup() && useEHCleanupForArray);
- }
- };
-
- static void EmitSanitizerDtorCallback(CodeGenFunction &CGF, llvm::Value *Ptr,
- CharUnits::QuantityType PoisonSize) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
- // Pass in void pointer and size of region as arguments to runtime
- // function
- llvm::Value *Args[] = {CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy),
- llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)};
-
- llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy};
-
- llvm::FunctionType *FnType =
- llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false);
- llvm::Value *Fn =
- CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback");
- CGF.EmitNounwindRuntimeCall(Fn, Args);
- }
-
- class SanitizeDtorMembers final : public EHScopeStack::Cleanup {
- const CXXDestructorDecl *Dtor;
-
- public:
- SanitizeDtorMembers(const CXXDestructorDecl *Dtor) : Dtor(Dtor) {}
-
- // Generate function call for handling object poisoning.
- // Disables tail call elimination, to prevent the current stack frame
- // from disappearing from the stack trace.
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- const ASTRecordLayout &Layout =
- CGF.getContext().getASTRecordLayout(Dtor->getParent());
-
- // Nothing to poison.
- if (Layout.getFieldCount() == 0)
- return;
-
- // Prevent the current stack frame from disappearing from the stack trace.
- CGF.CurFn->addFnAttr("disable-tail-calls", "true");
-
- // Construct pointer to region to begin poisoning, and calculate poison
- // size, so that only members declared in this class are poisoned.
- ASTContext &Context = CGF.getContext();
- unsigned fieldIndex = 0;
- int startIndex = -1;
- // RecordDecl::field_iterator Field;
- for (const FieldDecl *Field : Dtor->getParent()->fields()) {
- // Poison field if it is trivial
- if (FieldHasTrivialDestructorBody(Context, Field)) {
- // Start sanitizing at this field
- if (startIndex < 0)
- startIndex = fieldIndex;
-
- // Currently on the last field, and it must be poisoned with the
- // current block.
- if (fieldIndex == Layout.getFieldCount() - 1) {
- PoisonMembers(CGF, startIndex, Layout.getFieldCount());
- }
- } else if (startIndex >= 0) {
- // No longer within a block of memory to poison, so poison the block
- PoisonMembers(CGF, startIndex, fieldIndex);
- // Re-set the start index
- startIndex = -1;
- }
- fieldIndex += 1;
- }
- }
-
- private:
- /// \param layoutStartOffset index of the ASTRecordLayout field to
- /// start poisoning (inclusive)
- /// \param layoutEndOffset index of the ASTRecordLayout field to
- /// end poisoning (exclusive)
- void PoisonMembers(CodeGenFunction &CGF, unsigned layoutStartOffset,
- unsigned layoutEndOffset) {
- ASTContext &Context = CGF.getContext();
- const ASTRecordLayout &Layout =
- Context.getASTRecordLayout(Dtor->getParent());
-
- llvm::ConstantInt *OffsetSizePtr = llvm::ConstantInt::get(
- CGF.SizeTy,
- Context.toCharUnitsFromBits(Layout.getFieldOffset(layoutStartOffset))
- .getQuantity());
-
- llvm::Value *OffsetPtr = CGF.Builder.CreateGEP(
- CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.Int8PtrTy),
- OffsetSizePtr);
-
- CharUnits::QuantityType PoisonSize;
- if (layoutEndOffset >= Layout.getFieldCount()) {
- PoisonSize = Layout.getNonVirtualSize().getQuantity() -
- Context.toCharUnitsFromBits(
- Layout.getFieldOffset(layoutStartOffset))
- .getQuantity();
- } else {
- PoisonSize = Context.toCharUnitsFromBits(
- Layout.getFieldOffset(layoutEndOffset) -
- Layout.getFieldOffset(layoutStartOffset))
- .getQuantity();
- }
-
- if (PoisonSize == 0)
- return;
-
- EmitSanitizerDtorCallback(CGF, OffsetPtr, PoisonSize);
- }
- };
-
- class SanitizeDtorVTable final : public EHScopeStack::Cleanup {
- const CXXDestructorDecl *Dtor;
-
- public:
- SanitizeDtorVTable(const CXXDestructorDecl *Dtor) : Dtor(Dtor) {}
-
- // Generate function call for handling vtable pointer poisoning.
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- assert(Dtor->getParent()->isDynamicClass());
- (void)Dtor;
- ASTContext &Context = CGF.getContext();
- // Poison vtable and vtable ptr if they exist for this class.
- llvm::Value *VTablePtr = CGF.LoadCXXThis();
-
- CharUnits::QuantityType PoisonSize =
- Context.toCharUnitsFromBits(CGF.PointerWidthInBits).getQuantity();
- // Pass in void pointer and size of region as arguments to runtime
- // function
- EmitSanitizerDtorCallback(CGF, VTablePtr, PoisonSize);
- }
- };
-} // end anonymous namespace
-
-/// Emit all code that comes at the end of class's
-/// destructor. This is to call destructors on members and base classes
-/// in reverse order of their construction.
-///
-/// For a deleting destructor, this also handles the case where a destroying
-/// operator delete completely overrides the definition.
-void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
- CXXDtorType DtorType) {
- assert((!DD->isTrivial() || DD->hasAttr<DLLExportAttr>()) &&
- "Should not emit dtor epilogue for non-exported trivial dtor!");
-
- // The deleting-destructor phase just needs to call the appropriate
- // operator delete that Sema picked up.
- if (DtorType == Dtor_Deleting) {
- assert(DD->getOperatorDelete() &&
- "operator delete missing - EnterDtorCleanups");
- if (CXXStructorImplicitParamValue) {
- // If there is an implicit param to the deleting dtor, it's a boolean
- // telling whether this is a deleting destructor.
- if (DD->getOperatorDelete()->isDestroyingOperatorDelete())
- EmitConditionalDtorDeleteCall(*this, CXXStructorImplicitParamValue,
- /*ReturnAfterDelete*/true);
- else
- EHStack.pushCleanup<CallDtorDeleteConditional>(
- NormalAndEHCleanup, CXXStructorImplicitParamValue);
- } else {
- if (DD->getOperatorDelete()->isDestroyingOperatorDelete()) {
- const CXXRecordDecl *ClassDecl = DD->getParent();
- EmitDeleteCall(DD->getOperatorDelete(),
- LoadThisForDtorDelete(*this, DD),
- getContext().getTagDeclType(ClassDecl));
- EmitBranchThroughCleanup(ReturnBlock);
- } else {
- EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
- }
- }
- return;
- }
-
- const CXXRecordDecl *ClassDecl = DD->getParent();
-
- // Unions have no bases and do not call field destructors.
- if (ClassDecl->isUnion())
- return;
-
- // The complete-destructor phase just destructs all the virtual bases.
- if (DtorType == Dtor_Complete) {
- // Poison the vtable pointer such that access after the base
- // and member destructors are invoked is invalid.
- if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
- SanOpts.has(SanitizerKind::Memory) && ClassDecl->getNumVBases() &&
- ClassDecl->isPolymorphic())
- EHStack.pushCleanup<SanitizeDtorVTable>(NormalAndEHCleanup, DD);
-
- // We push them in the forward order so that they'll be popped in
- // the reverse order.
- for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
-
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
-
- EHStack.pushCleanup<CallBaseDtor>(NormalAndEHCleanup,
- BaseClassDecl,
- /*BaseIsVirtual*/ true);
- }
-
- return;
- }
-
- assert(DtorType == Dtor_Base);
- // Poison the vtable pointer if it has no virtual bases, but inherits
- // virtual functions.
- if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
- SanOpts.has(SanitizerKind::Memory) && !ClassDecl->getNumVBases() &&
- ClassDecl->isPolymorphic())
- EHStack.pushCleanup<SanitizeDtorVTable>(NormalAndEHCleanup, DD);
-
- // Destroy non-virtual bases.
- for (const auto &Base : ClassDecl->bases()) {
- // Ignore virtual bases.
- if (Base.isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl = Base.getType()->getAsCXXRecordDecl();
-
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
-
- EHStack.pushCleanup<CallBaseDtor>(NormalAndEHCleanup,
- BaseClassDecl,
- /*BaseIsVirtual*/ false);
- }
-
- // Poison fields such that access after their destructors are
- // invoked, and before the base class destructor runs, is invalid.
- if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
- SanOpts.has(SanitizerKind::Memory))
- EHStack.pushCleanup<SanitizeDtorMembers>(NormalAndEHCleanup, DD);
-
- // Destroy direct fields.
- for (const auto *Field : ClassDecl->fields()) {
- QualType type = Field->getType();
- QualType::DestructionKind dtorKind = type.isDestructedType();
- if (!dtorKind) continue;
-
- // Anonymous union members do not have their destructors called.
- const RecordType *RT = type->getAsUnionType();
- if (RT && RT->getDecl()->isAnonymousStructOrUnion()) continue;
-
- CleanupKind cleanupKind = getCleanupKind(dtorKind);
- EHStack.pushCleanup<DestroyField>(cleanupKind, Field,
- getDestroyer(dtorKind),
- cleanupKind & EHCleanup);
- }
-}
-
-/// EmitCXXAggrConstructorCall - Emit a loop to call a particular
-/// constructor for each of several members of an array.
-///
-/// \param ctor the constructor to call for each element
-/// \param arrayType the type of the array to initialize
-/// \param arrayBegin an arrayType*
-/// \param zeroInitialize true if each element should be
-/// zero-initialized before it is constructed
-void CodeGenFunction::EmitCXXAggrConstructorCall(
- const CXXConstructorDecl *ctor, const ArrayType *arrayType,
- Address arrayBegin, const CXXConstructExpr *E, bool NewPointerIsChecked,
- bool zeroInitialize) {
- QualType elementType;
- llvm::Value *numElements =
- emitArrayLength(arrayType, elementType, arrayBegin);
-
- EmitCXXAggrConstructorCall(ctor, numElements, arrayBegin, E,
- NewPointerIsChecked, zeroInitialize);
-}
-
-/// EmitCXXAggrConstructorCall - Emit a loop to call a particular
-/// constructor for each of several members of an array.
-///
-/// \param ctor the constructor to call for each element
-/// \param numElements the number of elements in the array;
-/// may be zero
-/// \param arrayBase a T*, where T is the type constructed by ctor
-/// \param zeroInitialize true if each element should be
-/// zero-initialized before it is constructed
-void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
- llvm::Value *numElements,
- Address arrayBase,
- const CXXConstructExpr *E,
- bool NewPointerIsChecked,
- bool zeroInitialize) {
- // It's legal for numElements to be zero. This can happen both
- // dynamically, because x can be zero in 'new A[x]', and statically,
- // because of GCC extensions that permit zero-length arrays. There
- // are probably legitimate places where we could assume that this
- // doesn't happen, but it's not clear that it's worth it.
- llvm::BranchInst *zeroCheckBranch = nullptr;
-
- // Optimize for a constant count.
- llvm::ConstantInt *constantCount
- = dyn_cast<llvm::ConstantInt>(numElements);
- if (constantCount) {
- // Just skip out if the constant count is zero.
- if (constantCount->isZero()) return;
-
- // Otherwise, emit the check.
- } else {
- llvm::BasicBlock *loopBB = createBasicBlock("new.ctorloop");
- llvm::Value *iszero = Builder.CreateIsNull(numElements, "isempty");
- zeroCheckBranch = Builder.CreateCondBr(iszero, loopBB, loopBB);
- EmitBlock(loopBB);
- }
-
- // Find the end of the array.
- llvm::Value *arrayBegin = arrayBase.getPointer();
- llvm::Value *arrayEnd = Builder.CreateInBoundsGEP(arrayBegin, numElements,
- "arrayctor.end");
-
- // Enter the loop, setting up a phi for the current location to initialize.
- llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
- llvm::BasicBlock *loopBB = createBasicBlock("arrayctor.loop");
- EmitBlock(loopBB);
- llvm::PHINode *cur = Builder.CreatePHI(arrayBegin->getType(), 2,
- "arrayctor.cur");
- cur->addIncoming(arrayBegin, entryBB);
-
- // Inside the loop body, emit the constructor call on the array element.
-
- // The alignment of the base, adjusted by the size of a single element,
- // provides a conservative estimate of the alignment of every element.
- // (This assumes we never start tracking offsetted alignments.)
- //
- // Note that these are complete objects and so we don't need to
- // use the non-virtual size or alignment.
- QualType type = getContext().getTypeDeclType(ctor->getParent());
- CharUnits eltAlignment =
- arrayBase.getAlignment()
- .alignmentOfArrayElement(getContext().getTypeSizeInChars(type));
- Address curAddr = Address(cur, eltAlignment);
-
- // Zero initialize the storage, if requested.
- if (zeroInitialize)
- EmitNullInitialization(curAddr, type);
-
- // C++ [class.temporary]p4:
- // There are two contexts in which temporaries are destroyed at a different
- // point than the end of the full-expression. The first context is when a
- // default constructor is called to initialize an element of an array.
- // If the constructor has one or more default arguments, the destruction of
- // every temporary created in a default argument expression is sequenced
- // before the construction of the next array element, if any.
-
- {
- RunCleanupsScope Scope(*this);
-
- // Evaluate the constructor and its arguments in a regular
- // partial-destroy cleanup.
- if (getLangOpts().Exceptions &&
- !ctor->getParent()->hasTrivialDestructor()) {
- Destroyer *destroyer = destroyCXXObject;
- pushRegularPartialArrayCleanup(arrayBegin, cur, type, eltAlignment,
- *destroyer);
- }
-
- EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/false,
- /*Delegating=*/false, curAddr, E,
- AggValueSlot::DoesNotOverlap, NewPointerIsChecked);
- }
-
- // Go to the next element.
- llvm::Value *next =
- Builder.CreateInBoundsGEP(cur, llvm::ConstantInt::get(SizeTy, 1),
- "arrayctor.next");
- cur->addIncoming(next, Builder.GetInsertBlock());
-
- // Check whether that's the end of the loop.
- llvm::Value *done = Builder.CreateICmpEQ(next, arrayEnd, "arrayctor.done");
- llvm::BasicBlock *contBB = createBasicBlock("arrayctor.cont");
- Builder.CreateCondBr(done, contBB, loopBB);
-
- // Patch the earlier check to skip over the loop.
- if (zeroCheckBranch) zeroCheckBranch->setSuccessor(0, contBB);
-
- EmitBlock(contBB);
-}
-
-void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
- Address addr,
- QualType type) {
- const RecordType *rtype = type->castAs<RecordType>();
- const CXXRecordDecl *record = cast<CXXRecordDecl>(rtype->getDecl());
- const CXXDestructorDecl *dtor = record->getDestructor();
- assert(!dtor->isTrivial());
- CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
- /*Delegating=*/false, addr);
-}
-
-void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type,
- bool ForVirtualBase,
- bool Delegating, Address This,
- const CXXConstructExpr *E,
- AggValueSlot::Overlap_t Overlap,
- bool NewPointerIsChecked) {
- CallArgList Args;
-
- LangAS SlotAS = E->getType().getAddressSpace();
- QualType ThisType = D->getThisType();
- LangAS ThisAS = ThisType.getTypePtr()->getPointeeType().getAddressSpace();
- llvm::Value *ThisPtr = This.getPointer();
- if (SlotAS != ThisAS) {
- unsigned TargetThisAS = getContext().getTargetAddressSpace(ThisAS);
- llvm::Type *NewType =
- ThisPtr->getType()->getPointerElementType()->getPointerTo(TargetThisAS);
- ThisPtr = getTargetHooks().performAddrSpaceCast(*this, This.getPointer(),
- ThisAS, SlotAS, NewType);
- }
- // Push the this ptr.
- Args.add(RValue::get(ThisPtr), D->getThisType());
-
- // If this is a trivial constructor, emit a memcpy now before we lose
- // the alignment information on the argument.
- // FIXME: It would be better to preserve alignment information into CallArg.
- if (isMemcpyEquivalentSpecialMember(D)) {
- assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
-
- const Expr *Arg = E->getArg(0);
- LValue Src = EmitLValue(Arg);
- QualType DestTy = getContext().getTypeDeclType(D->getParent());
- LValue Dest = MakeAddrLValue(This, DestTy);
- EmitAggregateCopyCtor(Dest, Src, Overlap);
- return;
- }
-
- // Add the rest of the user-supplied arguments.
- const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
- EvaluationOrder Order = E->isListInitialization()
- ? EvaluationOrder::ForceLeftToRight
- : EvaluationOrder::Default;
- EmitCallArgs(Args, FPT, E->arguments(), E->getConstructor(),
- /*ParamsToSkip*/ 0, Order);
-
- EmitCXXConstructorCall(D, Type, ForVirtualBase, Delegating, This, Args,
- Overlap, E->getExprLoc(), NewPointerIsChecked);
-}
-
-static bool canEmitDelegateCallArgs(CodeGenFunction &CGF,
- const CXXConstructorDecl *Ctor,
- CXXCtorType Type, CallArgList &Args) {
- // We can't forward a variadic call.
- if (Ctor->isVariadic())
- return false;
-
- if (CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
- // If the parameters are callee-cleanup, it's not safe to forward.
- for (auto *P : Ctor->parameters())
- if (P->getType().isDestructedType())
- return false;
-
- // Likewise if they're inalloca.
- const CGFunctionInfo &Info =
- CGF.CGM.getTypes().arrangeCXXConstructorCall(Args, Ctor, Type, 0, 0);
- if (Info.usesInAlloca())
- return false;
- }
-
- // Anything else should be OK.
- return true;
-}
-
-void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type,
- bool ForVirtualBase,
- bool Delegating,
- Address This,
- CallArgList &Args,
- AggValueSlot::Overlap_t Overlap,
- SourceLocation Loc,
- bool NewPointerIsChecked) {
- const CXXRecordDecl *ClassDecl = D->getParent();
-
- if (!NewPointerIsChecked)
- EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc, This.getPointer(),
- getContext().getRecordType(ClassDecl), CharUnits::Zero());
-
- if (D->isTrivial() && D->isDefaultConstructor()) {
- assert(Args.size() == 1 && "trivial default ctor with args");
- return;
- }
-
- // If this is a trivial constructor, just emit what's needed. If this is a
- // union copy constructor, we must emit a memcpy, because the AST does not
- // model that copy.
- if (isMemcpyEquivalentSpecialMember(D)) {
- assert(Args.size() == 2 && "unexpected argcount for trivial ctor");
-
- QualType SrcTy = D->getParamDecl(0)->getType().getNonReferenceType();
- Address Src(Args[1].getRValue(*this).getScalarVal(),
- getNaturalTypeAlignment(SrcTy));
- LValue SrcLVal = MakeAddrLValue(Src, SrcTy);
- QualType DestTy = getContext().getTypeDeclType(ClassDecl);
- LValue DestLVal = MakeAddrLValue(This, DestTy);
- EmitAggregateCopyCtor(DestLVal, SrcLVal, Overlap);
- return;
- }
-
- bool PassPrototypeArgs = true;
- // Check whether we can actually emit the constructor before trying to do so.
- if (auto Inherited = D->getInheritedConstructor()) {
- PassPrototypeArgs = getTypes().inheritingCtorHasParams(Inherited, Type);
- if (PassPrototypeArgs && !canEmitDelegateCallArgs(*this, D, Type, Args)) {
- EmitInlinedInheritingCXXConstructorCall(D, Type, ForVirtualBase,
- Delegating, Args);
- return;
- }
- }
-
- // Insert any ABI-specific implicit constructor arguments.
- CGCXXABI::AddedStructorArgs ExtraArgs =
- CGM.getCXXABI().addImplicitConstructorArgs(*this, D, Type, ForVirtualBase,
- Delegating, Args);
-
- // Emit the call.
- llvm::Constant *CalleePtr =
- CGM.getAddrOfCXXStructor(D, getFromCtorType(Type));
- const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
- Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs);
- CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(D, Type));
- EmitCall(Info, Callee, ReturnValueSlot(), Args);
-
- // Generate vtable assumptions if we're constructing a complete object
- // with a vtable. We don't do this for base subobjects for two reasons:
- // first, it's incorrect for classes with virtual bases, and second, we're
- // about to overwrite the vptrs anyway.
- // We also have to make sure if we can refer to vtable:
- // - Otherwise we can refer to vtable if it's safe to speculatively emit.
- // FIXME: If vtable is used by ctor/dtor, or if vtable is external and we are
- // sure that definition of vtable is not hidden,
- // then we are always safe to refer to it.
- // FIXME: It looks like InstCombine is very inefficient on dealing with
- // assumes. Make assumption loads require -fstrict-vtable-pointers temporarily.
- if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- ClassDecl->isDynamicClass() && Type != Ctor_Base &&
- CGM.getCXXABI().canSpeculativelyEmitVTable(ClassDecl) &&
- CGM.getCodeGenOpts().StrictVTablePointers)
- EmitVTableAssumptionLoads(ClassDecl, This);
-}
-
-void CodeGenFunction::EmitInheritedCXXConstructorCall(
- const CXXConstructorDecl *D, bool ForVirtualBase, Address This,
- bool InheritedFromVBase, const CXXInheritedCtorInitExpr *E) {
- CallArgList Args;
- CallArg ThisArg(RValue::get(This.getPointer()), D->getThisType());
-
- // Forward the parameters.
- if (InheritedFromVBase &&
- CGM.getTarget().getCXXABI().hasConstructorVariants()) {
- // Nothing to do; this construction is not responsible for constructing
- // the base class containing the inherited constructor.
- // FIXME: Can we just pass undef's for the remaining arguments if we don't
- // have constructor variants?
- Args.push_back(ThisArg);
- } else if (!CXXInheritedCtorInitExprArgs.empty()) {
- // The inheriting constructor was inlined; just inject its arguments.
- assert(CXXInheritedCtorInitExprArgs.size() >= D->getNumParams() &&
- "wrong number of parameters for inherited constructor call");
- Args = CXXInheritedCtorInitExprArgs;
- Args[0] = ThisArg;
- } else {
- // The inheriting constructor was not inlined. Emit delegating arguments.
- Args.push_back(ThisArg);
- const auto *OuterCtor = cast<CXXConstructorDecl>(CurCodeDecl);
- assert(OuterCtor->getNumParams() == D->getNumParams());
- assert(!OuterCtor->isVariadic() && "should have been inlined");
-
- for (const auto *Param : OuterCtor->parameters()) {
- assert(getContext().hasSameUnqualifiedType(
- OuterCtor->getParamDecl(Param->getFunctionScopeIndex())->getType(),
- Param->getType()));
- EmitDelegateCallArg(Args, Param, E->getLocation());
-
- // Forward __attribute__(pass_object_size).
- if (Param->hasAttr<PassObjectSizeAttr>()) {
- auto *POSParam = SizeArguments[Param];
- assert(POSParam && "missing pass_object_size value for forwarding");
- EmitDelegateCallArg(Args, POSParam, E->getLocation());
- }
- }
- }
-
- EmitCXXConstructorCall(D, Ctor_Base, ForVirtualBase, /*Delegating*/false,
- This, Args, AggValueSlot::MayOverlap,
- E->getLocation(), /*NewPointerIsChecked*/true);
-}
-
-void CodeGenFunction::EmitInlinedInheritingCXXConstructorCall(
- const CXXConstructorDecl *Ctor, CXXCtorType CtorType, bool ForVirtualBase,
- bool Delegating, CallArgList &Args) {
- GlobalDecl GD(Ctor, CtorType);
- InlinedInheritingConstructorScope Scope(*this, GD);
- ApplyInlineDebugLocation DebugScope(*this, GD);
- RunCleanupsScope RunCleanups(*this);
-
- // Save the arguments to be passed to the inherited constructor.
- CXXInheritedCtorInitExprArgs = Args;
-
- FunctionArgList Params;
- QualType RetType = BuildFunctionArgList(CurGD, Params);
- FnRetTy = RetType;
-
- // Insert any ABI-specific implicit constructor arguments.
- CGM.getCXXABI().addImplicitConstructorArgs(*this, Ctor, CtorType,
- ForVirtualBase, Delegating, Args);
-
- // Emit a simplified prolog. We only need to emit the implicit params.
- assert(Args.size() >= Params.size() && "too few arguments for call");
- for (unsigned I = 0, N = Args.size(); I != N; ++I) {
- if (I < Params.size() && isa<ImplicitParamDecl>(Params[I])) {
- const RValue &RV = Args[I].getRValue(*this);
- assert(!RV.isComplex() && "complex indirect params not supported");
- ParamValue Val = RV.isScalar()
- ? ParamValue::forDirect(RV.getScalarVal())
- : ParamValue::forIndirect(RV.getAggregateAddress());
- EmitParmDecl(*Params[I], Val, I + 1);
- }
- }
-
- // Create a return value slot if the ABI implementation wants one.
- // FIXME: This is dumb, we should ask the ABI not to try to set the return
- // value instead.
- if (!RetType->isVoidType())
- ReturnValue = CreateIRTemp(RetType, "retval.inhctor");
-
- CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
- CXXThisValue = CXXABIThisValue;
-
- // Directly emit the constructor initializers.
- EmitCtorPrologue(Ctor, CtorType, Params);
-}
-
-void CodeGenFunction::EmitVTableAssumptionLoad(const VPtr &Vptr, Address This) {
- llvm::Value *VTableGlobal =
- CGM.getCXXABI().getVTableAddressPoint(Vptr.Base, Vptr.VTableClass);
- if (!VTableGlobal)
- return;
-
- // We can just use the base offset in the complete class.
- CharUnits NonVirtualOffset = Vptr.Base.getBaseOffset();
-
- if (!NonVirtualOffset.isZero())
- This =
- ApplyNonVirtualAndVirtualOffset(*this, This, NonVirtualOffset, nullptr,
- Vptr.VTableClass, Vptr.NearestVBase);
-
- llvm::Value *VPtrValue =
- GetVTablePtr(This, VTableGlobal->getType(), Vptr.VTableClass);
- llvm::Value *Cmp =
- Builder.CreateICmpEQ(VPtrValue, VTableGlobal, "cmp.vtables");
- Builder.CreateAssumption(Cmp);
-}
-
-void CodeGenFunction::EmitVTableAssumptionLoads(const CXXRecordDecl *ClassDecl,
- Address This) {
- if (CGM.getCXXABI().doStructorsInitializeVPtrs(ClassDecl))
- for (const VPtr &Vptr : getVTablePointers(ClassDecl))
- EmitVTableAssumptionLoad(Vptr, This);
-}
-
-void
-CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
- Address This, Address Src,
- const CXXConstructExpr *E) {
- const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
-
- CallArgList Args;
-
- // Push the this ptr.
- Args.add(RValue::get(This.getPointer()), D->getThisType());
-
- // Push the src ptr.
- QualType QT = *(FPT->param_type_begin());
- llvm::Type *t = CGM.getTypes().ConvertType(QT);
- Src = Builder.CreateBitCast(Src, t);
- Args.add(RValue::get(Src.getPointer()), QT);
-
- // Skip over first argument (Src).
- EmitCallArgs(Args, FPT, drop_begin(E->arguments(), 1), E->getConstructor(),
- /*ParamsToSkip*/ 1);
-
- EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase*/false,
- /*Delegating*/false, This, Args,
- AggValueSlot::MayOverlap, E->getExprLoc(),
- /*NewPointerIsChecked*/false);
-}
-
-void
-CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
- CXXCtorType CtorType,
- const FunctionArgList &Args,
- SourceLocation Loc) {
- CallArgList DelegateArgs;
-
- FunctionArgList::const_iterator I = Args.begin(), E = Args.end();
- assert(I != E && "no parameters to constructor");
-
- // this
- Address This = LoadCXXThisAddress();
- DelegateArgs.add(RValue::get(This.getPointer()), (*I)->getType());
- ++I;
-
- // FIXME: The location of the VTT parameter in the parameter list is
- // specific to the Itanium ABI and shouldn't be hardcoded here.
- if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) {
- assert(I != E && "cannot skip vtt parameter, already done with args");
- assert((*I)->getType()->isPointerType() &&
- "skipping parameter not of vtt type");
- ++I;
- }
-
- // Explicit arguments.
- for (; I != E; ++I) {
- const VarDecl *param = *I;
- // FIXME: per-argument source location
- EmitDelegateCallArg(DelegateArgs, param, Loc);
- }
-
- EmitCXXConstructorCall(Ctor, CtorType, /*ForVirtualBase=*/false,
- /*Delegating=*/true, This, DelegateArgs,
- AggValueSlot::MayOverlap, Loc,
- /*NewPointerIsChecked=*/true);
-}
-
-namespace {
- struct CallDelegatingCtorDtor final : EHScopeStack::Cleanup {
- const CXXDestructorDecl *Dtor;
- Address Addr;
- CXXDtorType Type;
-
- CallDelegatingCtorDtor(const CXXDestructorDecl *D, Address Addr,
- CXXDtorType Type)
- : Dtor(D), Addr(Addr), Type(Type) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
- /*Delegating=*/true, Addr);
- }
- };
-} // end anonymous namespace
-
-void
-CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
- const FunctionArgList &Args) {
- assert(Ctor->isDelegatingConstructor());
-
- Address ThisPtr = LoadCXXThisAddress();
-
- AggValueSlot AggSlot =
- AggValueSlot::forAddr(ThisPtr, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::MayOverlap,
- AggValueSlot::IsNotZeroed,
- // Checks are made by the code that calls constructor.
- AggValueSlot::IsSanitizerChecked);
-
- EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
-
- const CXXRecordDecl *ClassDecl = Ctor->getParent();
- if (CGM.getLangOpts().Exceptions && !ClassDecl->hasTrivialDestructor()) {
- CXXDtorType Type =
- CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base;
-
- EHStack.pushCleanup<CallDelegatingCtorDtor>(EHCleanup,
- ClassDecl->getDestructor(),
- ThisPtr, Type);
- }
-}
-
-void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- bool ForVirtualBase,
- bool Delegating,
- Address This) {
- CGM.getCXXABI().EmitDestructorCall(*this, DD, Type, ForVirtualBase,
- Delegating, This);
-}
-
-namespace {
- struct CallLocalDtor final : EHScopeStack::Cleanup {
- const CXXDestructorDecl *Dtor;
- Address Addr;
-
- CallLocalDtor(const CXXDestructorDecl *D, Address Addr)
- : Dtor(D), Addr(Addr) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false,
- /*Delegating=*/false, Addr);
- }
- };
-} // end anonymous namespace
-
-void CodeGenFunction::PushDestructorCleanup(const CXXDestructorDecl *D,
- Address Addr) {
- EHStack.pushCleanup<CallLocalDtor>(NormalAndEHCleanup, D, Addr);
-}
-
-void CodeGenFunction::PushDestructorCleanup(QualType T, Address Addr) {
- CXXRecordDecl *ClassDecl = T->getAsCXXRecordDecl();
- if (!ClassDecl) return;
- if (ClassDecl->hasTrivialDestructor()) return;
-
- const CXXDestructorDecl *D = ClassDecl->getDestructor();
- assert(D && D->isUsed() && "destructor not marked as used!");
- PushDestructorCleanup(D, Addr);
-}
-
-void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
- // Compute the address point.
- llvm::Value *VTableAddressPoint =
- CGM.getCXXABI().getVTableAddressPointInStructor(
- *this, Vptr.VTableClass, Vptr.Base, Vptr.NearestVBase);
-
- if (!VTableAddressPoint)
- return;
-
- // Compute where to store the address point.
- llvm::Value *VirtualOffset = nullptr;
- CharUnits NonVirtualOffset = CharUnits::Zero();
-
- if (CGM.getCXXABI().isVirtualOffsetNeededForVTableField(*this, Vptr)) {
- // We need to use the virtual base offset offset because the virtual base
- // might have a different offset in the most derived class.
-
- VirtualOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(
- *this, LoadCXXThisAddress(), Vptr.VTableClass, Vptr.NearestVBase);
- NonVirtualOffset = Vptr.OffsetFromNearestVBase;
- } else {
- // We can just use the base offset in the complete class.
- NonVirtualOffset = Vptr.Base.getBaseOffset();
- }
-
- // Apply the offsets.
- Address VTableField = LoadCXXThisAddress();
-
- if (!NonVirtualOffset.isZero() || VirtualOffset)
- VTableField = ApplyNonVirtualAndVirtualOffset(
- *this, VTableField, NonVirtualOffset, VirtualOffset, Vptr.VTableClass,
- Vptr.NearestVBase);
-
- // Finally, store the address point. Use the same LLVM types as the field to
- // support optimization.
- llvm::Type *VTablePtrTy =
- llvm::FunctionType::get(CGM.Int32Ty, /*isVarArg=*/true)
- ->getPointerTo()
- ->getPointerTo();
- VTableField = Builder.CreateBitCast(VTableField, VTablePtrTy->getPointerTo());
- VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy);
-
- llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField);
- TBAAAccessInfo TBAAInfo = CGM.getTBAAVTablePtrAccessInfo(VTablePtrTy);
- CGM.DecorateInstructionWithTBAA(Store, TBAAInfo);
- if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- CGM.getCodeGenOpts().StrictVTablePointers)
- CGM.DecorateInstructionWithInvariantGroup(Store, Vptr.VTableClass);
-}
-
-CodeGenFunction::VPtrsVector
-CodeGenFunction::getVTablePointers(const CXXRecordDecl *VTableClass) {
- CodeGenFunction::VPtrsVector VPtrsResult;
- VisitedVirtualBasesSetTy VBases;
- getVTablePointers(BaseSubobject(VTableClass, CharUnits::Zero()),
- /*NearestVBase=*/nullptr,
- /*OffsetFromNearestVBase=*/CharUnits::Zero(),
- /*BaseIsNonVirtualPrimaryBase=*/false, VTableClass, VBases,
- VPtrsResult);
- return VPtrsResult;
-}
-
-void CodeGenFunction::getVTablePointers(BaseSubobject Base,
- const CXXRecordDecl *NearestVBase,
- CharUnits OffsetFromNearestVBase,
- bool BaseIsNonVirtualPrimaryBase,
- const CXXRecordDecl *VTableClass,
- VisitedVirtualBasesSetTy &VBases,
- VPtrsVector &Vptrs) {
- // If this base is a non-virtual primary base the address point has already
- // been set.
- if (!BaseIsNonVirtualPrimaryBase) {
- // Initialize the vtable pointer for this base.
- VPtr Vptr = {Base, NearestVBase, OffsetFromNearestVBase, VTableClass};
- Vptrs.push_back(Vptr);
- }
-
- const CXXRecordDecl *RD = Base.getBase();
-
- // Traverse bases.
- for (const auto &I : RD->bases()) {
- CXXRecordDecl *BaseDecl
- = cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
- // Ignore classes without a vtable.
- if (!BaseDecl->isDynamicClass())
- continue;
-
- CharUnits BaseOffset;
- CharUnits BaseOffsetFromNearestVBase;
- bool BaseDeclIsNonVirtualPrimaryBase;
-
- if (I.isVirtual()) {
- // Check if we've visited this virtual base before.
- if (!VBases.insert(BaseDecl).second)
- continue;
-
- const ASTRecordLayout &Layout =
- getContext().getASTRecordLayout(VTableClass);
-
- BaseOffset = Layout.getVBaseClassOffset(BaseDecl);
- BaseOffsetFromNearestVBase = CharUnits::Zero();
- BaseDeclIsNonVirtualPrimaryBase = false;
- } else {
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
-
- BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
- BaseOffsetFromNearestVBase =
- OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl);
- BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
- }
-
- getVTablePointers(
- BaseSubobject(BaseDecl, BaseOffset),
- I.isVirtual() ? BaseDecl : NearestVBase, BaseOffsetFromNearestVBase,
- BaseDeclIsNonVirtualPrimaryBase, VTableClass, VBases, Vptrs);
- }
-}
-
-void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
- // Ignore classes without a vtable.
- if (!RD->isDynamicClass())
- return;
-
- // Initialize the vtable pointers for this class and all of its bases.
- if (CGM.getCXXABI().doStructorsInitializeVPtrs(RD))
- for (const VPtr &Vptr : getVTablePointers(RD))
- InitializeVTablePointer(Vptr);
-
- if (RD->getNumVBases())
- CGM.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, RD);
-}
-
-llvm::Value *CodeGenFunction::GetVTablePtr(Address This,
- llvm::Type *VTableTy,
- const CXXRecordDecl *RD) {
- Address VTablePtrSrc = Builder.CreateElementBitCast(This, VTableTy);
- llvm::Instruction *VTable = Builder.CreateLoad(VTablePtrSrc, "vtable");
- TBAAAccessInfo TBAAInfo = CGM.getTBAAVTablePtrAccessInfo(VTableTy);
- CGM.DecorateInstructionWithTBAA(VTable, TBAAInfo);
-
- if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- CGM.getCodeGenOpts().StrictVTablePointers)
- CGM.DecorateInstructionWithInvariantGroup(VTable, RD);
-
- return VTable;
-}
-
-// If a class has a single non-virtual base and does not introduce or override
-// virtual member functions or fields, it will have the same layout as its base.
-// This function returns the least derived such class.
-//
-// Casting an instance of a base class to such a derived class is technically
-// undefined behavior, but it is a relatively common hack for introducing member
-// functions on class instances with specific properties (e.g. llvm::Operator)
-// that works under most compilers and should not have security implications, so
-// we allow it by default. It can be disabled with -fsanitize=cfi-cast-strict.
-static const CXXRecordDecl *
-LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) {
- if (!RD->field_empty())
- return RD;
-
- if (RD->getNumVBases() != 0)
- return RD;
-
- if (RD->getNumBases() != 1)
- return RD;
-
- for (const CXXMethodDecl *MD : RD->methods()) {
- if (MD->isVirtual()) {
- // Virtual member functions are only ok if they are implicit destructors
- // because the implicit destructor will have the same semantics as the
- // base class's destructor if no fields are added.
- if (isa<CXXDestructorDecl>(MD) && MD->isImplicit())
- continue;
- return RD;
- }
- }
-
- return LeastDerivedClassWithSameLayout(
- RD->bases_begin()->getType()->getAsCXXRecordDecl());
-}
-
-void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
- llvm::Value *VTable,
- SourceLocation Loc) {
- if (SanOpts.has(SanitizerKind::CFIVCall))
- EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc);
- else if (CGM.getCodeGenOpts().WholeProgramVTables &&
- CGM.HasHiddenLTOVisibility(RD)) {
- llvm::Metadata *MD =
- CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
- llvm::Value *TypeId =
- llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
-
- llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
- llvm::Value *TypeTest =
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
- {CastedVTable, TypeId});
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
- }
-}
-
-void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
- llvm::Value *VTable,
- CFITypeCheckKind TCK,
- SourceLocation Loc) {
- if (!SanOpts.has(SanitizerKind::CFICastStrict))
- RD = LeastDerivedClassWithSameLayout(RD);
-
- EmitVTablePtrCheck(RD, VTable, TCK, Loc);
-}
-
-void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
- llvm::Value *Derived,
- bool MayBeNull,
- CFITypeCheckKind TCK,
- SourceLocation Loc) {
- if (!getLangOpts().CPlusPlus)
- return;
-
- auto *ClassTy = T->getAs<RecordType>();
- if (!ClassTy)
- return;
-
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassTy->getDecl());
-
- if (!ClassDecl->isCompleteDefinition() || !ClassDecl->isDynamicClass())
- return;
-
- if (!SanOpts.has(SanitizerKind::CFICastStrict))
- ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
-
- llvm::BasicBlock *ContBlock = nullptr;
-
- if (MayBeNull) {
- llvm::Value *DerivedNotNull =
- Builder.CreateIsNotNull(Derived, "cast.nonnull");
-
- llvm::BasicBlock *CheckBlock = createBasicBlock("cast.check");
- ContBlock = createBasicBlock("cast.cont");
-
- Builder.CreateCondBr(DerivedNotNull, CheckBlock, ContBlock);
-
- EmitBlock(CheckBlock);
- }
-
- llvm::Value *VTable;
- std::tie(VTable, ClassDecl) = CGM.getCXXABI().LoadVTablePtr(
- *this, Address(Derived, getPointerAlign()), ClassDecl);
-
- EmitVTablePtrCheck(ClassDecl, VTable, TCK, Loc);
-
- if (MayBeNull) {
- Builder.CreateBr(ContBlock);
- EmitBlock(ContBlock);
- }
-}
-
-void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
- llvm::Value *VTable,
- CFITypeCheckKind TCK,
- SourceLocation Loc) {
- if (!CGM.getCodeGenOpts().SanitizeCfiCrossDso &&
- !CGM.HasHiddenLTOVisibility(RD))
- return;
-
- SanitizerMask M;
- llvm::SanitizerStatKind SSK;
- switch (TCK) {
- case CFITCK_VCall:
- M = SanitizerKind::CFIVCall;
- SSK = llvm::SanStat_CFI_VCall;
- break;
- case CFITCK_NVCall:
- M = SanitizerKind::CFINVCall;
- SSK = llvm::SanStat_CFI_NVCall;
- break;
- case CFITCK_DerivedCast:
- M = SanitizerKind::CFIDerivedCast;
- SSK = llvm::SanStat_CFI_DerivedCast;
- break;
- case CFITCK_UnrelatedCast:
- M = SanitizerKind::CFIUnrelatedCast;
- SSK = llvm::SanStat_CFI_UnrelatedCast;
- break;
- case CFITCK_ICall:
- case CFITCK_NVMFCall:
- case CFITCK_VMFCall:
- llvm_unreachable("unexpected sanitizer kind");
- }
-
- std::string TypeName = RD->getQualifiedNameAsString();
- if (getContext().getSanitizerBlacklist().isBlacklistedType(M, TypeName))
- return;
-
- SanitizerScope SanScope(this);
- EmitSanitizerStatReport(SSK);
-
- llvm::Metadata *MD =
- CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
- llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
-
- llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
- llvm::Value *TypeTest = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId});
-
- llvm::Constant *StaticData[] = {
- llvm::ConstantInt::get(Int8Ty, TCK),
- EmitCheckSourceLocation(Loc),
- EmitCheckTypeDescriptor(QualType(RD->getTypeForDecl(), 0)),
- };
-
- auto CrossDsoTypeId = CGM.CreateCrossDsoCfiTypeId(MD);
- if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) {
- EmitCfiSlowPathCheck(M, TypeTest, CrossDsoTypeId, CastedVTable, StaticData);
- return;
- }
-
- if (CGM.getCodeGenOpts().SanitizeTrap.has(M)) {
- EmitTrapCheck(TypeTest);
- return;
- }
-
- llvm::Value *AllVtables = llvm::MetadataAsValue::get(
- CGM.getLLVMContext(),
- llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
- llvm::Value *ValidVtable = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, AllVtables});
- EmitCheck(std::make_pair(TypeTest, M), SanitizerHandler::CFICheckFail,
- StaticData, {CastedVTable, ValidVtable});
-}
-
-bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
- if (!CGM.getCodeGenOpts().WholeProgramVTables ||
- !SanOpts.has(SanitizerKind::CFIVCall) ||
- !CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall) ||
- !CGM.HasHiddenLTOVisibility(RD))
- return false;
-
- std::string TypeName = RD->getQualifiedNameAsString();
- return !getContext().getSanitizerBlacklist().isBlacklistedType(
- SanitizerKind::CFIVCall, TypeName);
-}
-
-llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
- const CXXRecordDecl *RD, llvm::Value *VTable, uint64_t VTableByteOffset) {
- SanitizerScope SanScope(this);
-
- EmitSanitizerStatReport(llvm::SanStat_CFI_VCall);
-
- llvm::Metadata *MD =
- CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
- llvm::Value *TypeId = llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
-
- llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
- llvm::Value *CheckedLoad = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_checked_load),
- {CastedVTable, llvm::ConstantInt::get(Int32Ty, VTableByteOffset),
- TypeId});
- llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
-
- EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall),
- SanitizerHandler::CFICheckFail, nullptr, nullptr);
-
- return Builder.CreateBitCast(
- Builder.CreateExtractValue(CheckedLoad, 0),
- cast<llvm::PointerType>(VTable->getType())->getElementType());
-}
-
-void CodeGenFunction::EmitForwardingCallToLambda(
- const CXXMethodDecl *callOperator,
- CallArgList &callArgs) {
- // Get the address of the call operator.
- const CGFunctionInfo &calleeFnInfo =
- CGM.getTypes().arrangeCXXMethodDeclaration(callOperator);
- llvm::Constant *calleePtr =
- CGM.GetAddrOfFunction(GlobalDecl(callOperator),
- CGM.getTypes().GetFunctionType(calleeFnInfo));
-
- // Prepare the return slot.
- const FunctionProtoType *FPT =
- callOperator->getType()->castAs<FunctionProtoType>();
- QualType resultType = FPT->getReturnType();
- ReturnValueSlot returnSlot;
- if (!resultType->isVoidType() &&
- calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- !hasScalarEvaluationKind(calleeFnInfo.getReturnType()))
- returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified());
-
- // We don't need to separately arrange the call arguments because
- // the call can't be variadic anyway --- it's impossible to forward
- // variadic arguments.
-
- // Now emit our call.
- auto callee = CGCallee::forDirect(calleePtr, GlobalDecl(callOperator));
- RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs);
-
- // If necessary, copy the returned value into the slot.
- if (!resultType->isVoidType() && returnSlot.isNull()) {
- if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) {
- RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal()));
- }
- EmitReturnOfRValue(RV, resultType);
- } else
- EmitBranchThroughCleanup(ReturnBlock);
-}
-
-void CodeGenFunction::EmitLambdaBlockInvokeBody() {
- const BlockDecl *BD = BlockInfo->getBlockDecl();
- const VarDecl *variable = BD->capture_begin()->getVariable();
- const CXXRecordDecl *Lambda = variable->getType()->getAsCXXRecordDecl();
- const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
-
- if (CallOp->isVariadic()) {
- // FIXME: Making this work correctly is nasty because it requires either
- // cloning the body of the call operator or making the call operator
- // forward.
- CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function");
- return;
- }
-
- // Start building arguments for forwarding call
- CallArgList CallArgs;
-
- QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda));
- Address ThisPtr = GetAddrOfBlockDecl(variable);
- CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType);
-
- // Add the rest of the parameters.
- for (auto param : BD->parameters())
- EmitDelegateCallArg(CallArgs, param, param->getBeginLoc());
-
- assert(!Lambda->isGenericLambda() &&
- "generic lambda interconversion to block not implemented");
- EmitForwardingCallToLambda(CallOp, CallArgs);
-}
-
-void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
- const CXXRecordDecl *Lambda = MD->getParent();
-
- // Start building arguments for forwarding call
- CallArgList CallArgs;
-
- QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda));
- llvm::Value *ThisPtr = llvm::UndefValue::get(getTypes().ConvertType(ThisType));
- CallArgs.add(RValue::get(ThisPtr), ThisType);
-
- // Add the rest of the parameters.
- for (auto Param : MD->parameters())
- EmitDelegateCallArg(CallArgs, Param, Param->getBeginLoc());
-
- const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
- // For a generic lambda, find the corresponding call operator specialization
- // to which the call to the static-invoker shall be forwarded.
- if (Lambda->isGenericLambda()) {
- assert(MD->isFunctionTemplateSpecialization());
- const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
- FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate();
- void *InsertPos = nullptr;
- FunctionDecl *CorrespondingCallOpSpecialization =
- CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos);
- assert(CorrespondingCallOpSpecialization);
- CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
- }
- EmitForwardingCallToLambda(CallOp, CallArgs);
-}
-
-void CodeGenFunction::EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD) {
- if (MD->isVariadic()) {
- // FIXME: Making this work correctly is nasty because it requires either
- // cloning the body of the call operator or making the call operator forward.
- CGM.ErrorUnsupported(MD, "lambda conversion to variadic function");
- return;
- }
-
- EmitLambdaDelegatingInvokeBody(MD);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp
deleted file mode 100644
index 3743d24f11f..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp
+++ /dev/null
@@ -1,1283 +0,0 @@
-//===--- CGCleanup.cpp - Bookkeeping and code emission for cleanups -------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains code dealing with the IR generation for cleanups
-// and related information.
-//
-// A "cleanup" is a piece of code which needs to be executed whenever
-// control transfers out of a particular scope. This can be
-// conditionalized to occur only on exceptional control flow, only on
-// normal control flow, or both.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCleanup.h"
-#include "CodeGenFunction.h"
-#include "llvm/Support/SaveAndRestore.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-bool DominatingValue<RValue>::saved_type::needsSaving(RValue rv) {
- if (rv.isScalar())
- return DominatingLLVMValue::needsSaving(rv.getScalarVal());
- if (rv.isAggregate())
- return DominatingLLVMValue::needsSaving(rv.getAggregatePointer());
- return true;
-}
-
-DominatingValue<RValue>::saved_type
-DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
- if (rv.isScalar()) {
- llvm::Value *V = rv.getScalarVal();
-
- // These automatically dominate and don't need to be saved.
- if (!DominatingLLVMValue::needsSaving(V))
- return saved_type(V, ScalarLiteral);
-
- // Everything else needs an alloca.
- Address addr =
- CGF.CreateDefaultAlignTempAlloca(V->getType(), "saved-rvalue");
- CGF.Builder.CreateStore(V, addr);
- return saved_type(addr.getPointer(), ScalarAddress);
- }
-
- if (rv.isComplex()) {
- CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
- llvm::Type *ComplexTy =
- llvm::StructType::get(V.first->getType(), V.second->getType());
- Address addr = CGF.CreateDefaultAlignTempAlloca(ComplexTy, "saved-complex");
- CGF.Builder.CreateStore(V.first,
- CGF.Builder.CreateStructGEP(addr, 0, CharUnits()));
- CharUnits offset = CharUnits::fromQuantity(
- CGF.CGM.getDataLayout().getTypeAllocSize(V.first->getType()));
- CGF.Builder.CreateStore(V.second,
- CGF.Builder.CreateStructGEP(addr, 1, offset));
- return saved_type(addr.getPointer(), ComplexAddress);
- }
-
- assert(rv.isAggregate());
- Address V = rv.getAggregateAddress(); // TODO: volatile?
- if (!DominatingLLVMValue::needsSaving(V.getPointer()))
- return saved_type(V.getPointer(), AggregateLiteral,
- V.getAlignment().getQuantity());
-
- Address addr =
- CGF.CreateTempAlloca(V.getType(), CGF.getPointerAlign(), "saved-rvalue");
- CGF.Builder.CreateStore(V.getPointer(), addr);
- return saved_type(addr.getPointer(), AggregateAddress,
- V.getAlignment().getQuantity());
-}
-
-/// Given a saved r-value produced by SaveRValue, perform the code
-/// necessary to restore it to usability at the current insertion
-/// point.
-RValue DominatingValue<RValue>::saved_type::restore(CodeGenFunction &CGF) {
- auto getSavingAddress = [&](llvm::Value *value) {
- auto alignment = cast<llvm::AllocaInst>(value)->getAlignment();
- return Address(value, CharUnits::fromQuantity(alignment));
- };
- switch (K) {
- case ScalarLiteral:
- return RValue::get(Value);
- case ScalarAddress:
- return RValue::get(CGF.Builder.CreateLoad(getSavingAddress(Value)));
- case AggregateLiteral:
- return RValue::getAggregate(Address(Value, CharUnits::fromQuantity(Align)));
- case AggregateAddress: {
- auto addr = CGF.Builder.CreateLoad(getSavingAddress(Value));
- return RValue::getAggregate(Address(addr, CharUnits::fromQuantity(Align)));
- }
- case ComplexAddress: {
- Address address = getSavingAddress(Value);
- llvm::Value *real = CGF.Builder.CreateLoad(
- CGF.Builder.CreateStructGEP(address, 0, CharUnits()));
- CharUnits offset = CharUnits::fromQuantity(
- CGF.CGM.getDataLayout().getTypeAllocSize(real->getType()));
- llvm::Value *imag = CGF.Builder.CreateLoad(
- CGF.Builder.CreateStructGEP(address, 1, offset));
- return RValue::getComplex(real, imag);
- }
- }
-
- llvm_unreachable("bad saved r-value kind");
-}
-
-/// Push an entry of the given size onto this protected-scope stack.
-char *EHScopeStack::allocate(size_t Size) {
- Size = llvm::alignTo(Size, ScopeStackAlignment);
- if (!StartOfBuffer) {
- unsigned Capacity = 1024;
- while (Capacity < Size) Capacity *= 2;
- StartOfBuffer = new char[Capacity];
- StartOfData = EndOfBuffer = StartOfBuffer + Capacity;
- } else if (static_cast<size_t>(StartOfData - StartOfBuffer) < Size) {
- unsigned CurrentCapacity = EndOfBuffer - StartOfBuffer;
- unsigned UsedCapacity = CurrentCapacity - (StartOfData - StartOfBuffer);
-
- unsigned NewCapacity = CurrentCapacity;
- do {
- NewCapacity *= 2;
- } while (NewCapacity < UsedCapacity + Size);
-
- char *NewStartOfBuffer = new char[NewCapacity];
- char *NewEndOfBuffer = NewStartOfBuffer + NewCapacity;
- char *NewStartOfData = NewEndOfBuffer - UsedCapacity;
- memcpy(NewStartOfData, StartOfData, UsedCapacity);
- delete [] StartOfBuffer;
- StartOfBuffer = NewStartOfBuffer;
- EndOfBuffer = NewEndOfBuffer;
- StartOfData = NewStartOfData;
- }
-
- assert(StartOfBuffer + Size <= StartOfData);
- StartOfData -= Size;
- return StartOfData;
-}
-
-void EHScopeStack::deallocate(size_t Size) {
- StartOfData += llvm::alignTo(Size, ScopeStackAlignment);
-}
-
-bool EHScopeStack::containsOnlyLifetimeMarkers(
- EHScopeStack::stable_iterator Old) const {
- for (EHScopeStack::iterator it = begin(); stabilize(it) != Old; it++) {
- EHCleanupScope *cleanup = dyn_cast<EHCleanupScope>(&*it);
- if (!cleanup || !cleanup->isLifetimeMarker())
- return false;
- }
-
- return true;
-}
-
-bool EHScopeStack::requiresLandingPad() const {
- for (stable_iterator si = getInnermostEHScope(); si != stable_end(); ) {
- // Skip lifetime markers.
- if (auto *cleanup = dyn_cast<EHCleanupScope>(&*find(si)))
- if (cleanup->isLifetimeMarker()) {
- si = cleanup->getEnclosingEHScope();
- continue;
- }
- return true;
- }
-
- return false;
-}
-
-EHScopeStack::stable_iterator
-EHScopeStack::getInnermostActiveNormalCleanup() const {
- for (stable_iterator si = getInnermostNormalCleanup(), se = stable_end();
- si != se; ) {
- EHCleanupScope &cleanup = cast<EHCleanupScope>(*find(si));
- if (cleanup.isActive()) return si;
- si = cleanup.getEnclosingNormalCleanup();
- }
- return stable_end();
-}
-
-
-void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
- char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size));
- bool IsNormalCleanup = Kind & NormalCleanup;
- bool IsEHCleanup = Kind & EHCleanup;
- bool IsActive = !(Kind & InactiveCleanup);
- bool IsLifetimeMarker = Kind & LifetimeMarker;
- EHCleanupScope *Scope =
- new (Buffer) EHCleanupScope(IsNormalCleanup,
- IsEHCleanup,
- IsActive,
- Size,
- BranchFixups.size(),
- InnermostNormalCleanup,
- InnermostEHScope);
- if (IsNormalCleanup)
- InnermostNormalCleanup = stable_begin();
- if (IsEHCleanup)
- InnermostEHScope = stable_begin();
- if (IsLifetimeMarker)
- Scope->setLifetimeMarker();
-
- return Scope->getCleanupBuffer();
-}
-
-void EHScopeStack::popCleanup() {
- assert(!empty() && "popping exception stack when not empty");
-
- assert(isa<EHCleanupScope>(*begin()));
- EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin());
- InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup();
- InnermostEHScope = Cleanup.getEnclosingEHScope();
- deallocate(Cleanup.getAllocatedSize());
-
- // Destroy the cleanup.
- Cleanup.Destroy();
-
- // Check whether we can shrink the branch-fixups stack.
- if (!BranchFixups.empty()) {
- // If we no longer have any normal cleanups, all the fixups are
- // complete.
- if (!hasNormalCleanups())
- BranchFixups.clear();
-
- // Otherwise we can still trim out unnecessary nulls.
- else
- popNullFixups();
- }
-}
-
-EHFilterScope *EHScopeStack::pushFilter(unsigned numFilters) {
- assert(getInnermostEHScope() == stable_end());
- char *buffer = allocate(EHFilterScope::getSizeForNumFilters(numFilters));
- EHFilterScope *filter = new (buffer) EHFilterScope(numFilters);
- InnermostEHScope = stable_begin();
- return filter;
-}
-
-void EHScopeStack::popFilter() {
- assert(!empty() && "popping exception stack when not empty");
-
- EHFilterScope &filter = cast<EHFilterScope>(*begin());
- deallocate(EHFilterScope::getSizeForNumFilters(filter.getNumFilters()));
-
- InnermostEHScope = filter.getEnclosingEHScope();
-}
-
-EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
- char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
- EHCatchScope *scope =
- new (buffer) EHCatchScope(numHandlers, InnermostEHScope);
- InnermostEHScope = stable_begin();
- return scope;
-}
-
-void EHScopeStack::pushTerminate() {
- char *Buffer = allocate(EHTerminateScope::getSize());
- new (Buffer) EHTerminateScope(InnermostEHScope);
- InnermostEHScope = stable_begin();
-}
-
-/// Remove any 'null' fixups on the stack. However, we can't pop more
-/// fixups than the fixup depth on the innermost normal cleanup, or
-/// else fixups that we try to add to that cleanup will end up in the
-/// wrong place. We *could* try to shrink fixup depths, but that's
-/// actually a lot of work for little benefit.
-void EHScopeStack::popNullFixups() {
- // We expect this to only be called when there's still an innermost
- // normal cleanup; otherwise there really shouldn't be any fixups.
- assert(hasNormalCleanups());
-
- EHScopeStack::iterator it = find(InnermostNormalCleanup);
- unsigned MinSize = cast<EHCleanupScope>(*it).getFixupDepth();
- assert(BranchFixups.size() >= MinSize && "fixup stack out of order");
-
- while (BranchFixups.size() > MinSize &&
- BranchFixups.back().Destination == nullptr)
- BranchFixups.pop_back();
-}
-
-Address CodeGenFunction::createCleanupActiveFlag() {
- // Create a variable to decide whether the cleanup needs to be run.
- Address active = CreateTempAllocaWithoutCast(
- Builder.getInt1Ty(), CharUnits::One(), "cleanup.cond");
-
- // Initialize it to false at a site that's guaranteed to be run
- // before each evaluation.
- setBeforeOutermostConditional(Builder.getFalse(), active);
-
- // Initialize it to true at the current location.
- Builder.CreateStore(Builder.getTrue(), active);
-
- return active;
-}
-
-void CodeGenFunction::initFullExprCleanupWithFlag(Address ActiveFlag) {
- // Set that as the active flag in the cleanup.
- EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());
- assert(!cleanup.hasActiveFlag() && "cleanup already has active flag?");
- cleanup.setActiveFlag(ActiveFlag);
-
- if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup();
- if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup();
-}
-
-void EHScopeStack::Cleanup::anchor() {}
-
-static void createStoreInstBefore(llvm::Value *value, Address addr,
- llvm::Instruction *beforeInst) {
- auto store = new llvm::StoreInst(value, addr.getPointer(), beforeInst);
- store->setAlignment(addr.getAlignment().getQuantity());
-}
-
-static llvm::LoadInst *createLoadInstBefore(Address addr, const Twine &name,
- llvm::Instruction *beforeInst) {
- auto load = new llvm::LoadInst(addr.getPointer(), name, beforeInst);
- load->setAlignment(addr.getAlignment().getQuantity());
- return load;
-}
-
-/// All the branch fixups on the EH stack have propagated out past the
-/// outermost normal cleanup; resolve them all by adding cases to the
-/// given switch instruction.
-static void ResolveAllBranchFixups(CodeGenFunction &CGF,
- llvm::SwitchInst *Switch,
- llvm::BasicBlock *CleanupEntry) {
- llvm::SmallPtrSet<llvm::BasicBlock*, 4> CasesAdded;
-
- for (unsigned I = 0, E = CGF.EHStack.getNumBranchFixups(); I != E; ++I) {
- // Skip this fixup if its destination isn't set.
- BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I);
- if (Fixup.Destination == nullptr) continue;
-
- // If there isn't an OptimisticBranchBlock, then InitialBranch is
- // still pointing directly to its destination; forward it to the
- // appropriate cleanup entry. This is required in the specific
- // case of
- // { std::string s; goto lbl; }
- // lbl:
- // i.e. where there's an unresolved fixup inside a single cleanup
- // entry which we're currently popping.
- if (Fixup.OptimisticBranchBlock == nullptr) {
- createStoreInstBefore(CGF.Builder.getInt32(Fixup.DestinationIndex),
- CGF.getNormalCleanupDestSlot(),
- Fixup.InitialBranch);
- Fixup.InitialBranch->setSuccessor(0, CleanupEntry);
- }
-
- // Don't add this case to the switch statement twice.
- if (!CasesAdded.insert(Fixup.Destination).second)
- continue;
-
- Switch->addCase(CGF.Builder.getInt32(Fixup.DestinationIndex),
- Fixup.Destination);
- }
-
- CGF.EHStack.clearFixups();
-}
-
-/// Transitions the terminator of the given exit-block of a cleanup to
-/// be a cleanup switch.
-static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF,
- llvm::BasicBlock *Block) {
- // If it's a branch, turn it into a switch whose default
- // destination is its original target.
- llvm::Instruction *Term = Block->getTerminator();
- assert(Term && "can't transition block without terminator");
-
- if (llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Term)) {
- assert(Br->isUnconditional());
- auto Load = createLoadInstBefore(CGF.getNormalCleanupDestSlot(),
- "cleanup.dest", Term);
- llvm::SwitchInst *Switch =
- llvm::SwitchInst::Create(Load, Br->getSuccessor(0), 4, Block);
- Br->eraseFromParent();
- return Switch;
- } else {
- return cast<llvm::SwitchInst>(Term);
- }
-}
-
-void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) {
- assert(Block && "resolving a null target block");
- if (!EHStack.getNumBranchFixups()) return;
-
- assert(EHStack.hasNormalCleanups() &&
- "branch fixups exist with no normal cleanups on stack");
-
- llvm::SmallPtrSet<llvm::BasicBlock*, 4> ModifiedOptimisticBlocks;
- bool ResolvedAny = false;
-
- for (unsigned I = 0, E = EHStack.getNumBranchFixups(); I != E; ++I) {
- // Skip this fixup if its destination doesn't match.
- BranchFixup &Fixup = EHStack.getBranchFixup(I);
- if (Fixup.Destination != Block) continue;
-
- Fixup.Destination = nullptr;
- ResolvedAny = true;
-
- // If it doesn't have an optimistic branch block, LatestBranch is
- // already pointing to the right place.
- llvm::BasicBlock *BranchBB = Fixup.OptimisticBranchBlock;
- if (!BranchBB)
- continue;
-
- // Don't process the same optimistic branch block twice.
- if (!ModifiedOptimisticBlocks.insert(BranchBB).second)
- continue;
-
- llvm::SwitchInst *Switch = TransitionToCleanupSwitch(*this, BranchBB);
-
- // Add a case to the switch.
- Switch->addCase(Builder.getInt32(Fixup.DestinationIndex), Block);
- }
-
- if (ResolvedAny)
- EHStack.popNullFixups();
-}
-
-/// Pops cleanup blocks until the given savepoint is reached.
-void CodeGenFunction::PopCleanupBlocks(
- EHScopeStack::stable_iterator Old,
- std::initializer_list<llvm::Value **> ValuesToReload) {
- assert(Old.isValid());
-
- bool HadBranches = false;
- while (EHStack.stable_begin() != Old) {
- EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
- HadBranches |= Scope.hasBranches();
-
- // As long as Old strictly encloses the scope's enclosing normal
- // cleanup, we're going to emit another normal cleanup which
- // fallthrough can propagate through.
- bool FallThroughIsBranchThrough =
- Old.strictlyEncloses(Scope.getEnclosingNormalCleanup());
-
- PopCleanupBlock(FallThroughIsBranchThrough);
- }
-
- // If we didn't have any branches, the insertion point before cleanups must
- // dominate the current insertion point and we don't need to reload any
- // values.
- if (!HadBranches)
- return;
-
- // Spill and reload all values that the caller wants to be live at the current
- // insertion point.
- for (llvm::Value **ReloadedValue : ValuesToReload) {
- auto *Inst = dyn_cast_or_null<llvm::Instruction>(*ReloadedValue);
- if (!Inst)
- continue;
-
- // Don't spill static allocas, they dominate all cleanups. These are created
- // by binding a reference to a local variable or temporary.
- auto *AI = dyn_cast<llvm::AllocaInst>(Inst);
- if (AI && AI->isStaticAlloca())
- continue;
-
- Address Tmp =
- CreateDefaultAlignTempAlloca(Inst->getType(), "tmp.exprcleanup");
-
- // Find an insertion point after Inst and spill it to the temporary.
- llvm::BasicBlock::iterator InsertBefore;
- if (auto *Invoke = dyn_cast<llvm::InvokeInst>(Inst))
- InsertBefore = Invoke->getNormalDest()->getFirstInsertionPt();
- else
- InsertBefore = std::next(Inst->getIterator());
- CGBuilderTy(CGM, &*InsertBefore).CreateStore(Inst, Tmp);
-
- // Reload the value at the current insertion point.
- *ReloadedValue = Builder.CreateLoad(Tmp);
- }
-}
-
-/// Pops cleanup blocks until the given savepoint is reached, then add the
-/// cleanups from the given savepoint in the lifetime-extended cleanups stack.
-void CodeGenFunction::PopCleanupBlocks(
- EHScopeStack::stable_iterator Old, size_t OldLifetimeExtendedSize,
- std::initializer_list<llvm::Value **> ValuesToReload) {
- PopCleanupBlocks(Old, ValuesToReload);
-
- // Move our deferred cleanups onto the EH stack.
- for (size_t I = OldLifetimeExtendedSize,
- E = LifetimeExtendedCleanupStack.size(); I != E; /**/) {
- // Alignment should be guaranteed by the vptrs in the individual cleanups.
- assert((I % alignof(LifetimeExtendedCleanupHeader) == 0) &&
- "misaligned cleanup stack entry");
-
- LifetimeExtendedCleanupHeader &Header =
- reinterpret_cast<LifetimeExtendedCleanupHeader&>(
- LifetimeExtendedCleanupStack[I]);
- I += sizeof(Header);
-
- EHStack.pushCopyOfCleanup(Header.getKind(),
- &LifetimeExtendedCleanupStack[I],
- Header.getSize());
- I += Header.getSize();
-
- if (Header.isConditional()) {
- Address ActiveFlag =
- reinterpret_cast<Address &>(LifetimeExtendedCleanupStack[I]);
- initFullExprCleanupWithFlag(ActiveFlag);
- I += sizeof(ActiveFlag);
- }
- }
- LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize);
-}
-
-static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF,
- EHCleanupScope &Scope) {
- assert(Scope.isNormalCleanup());
- llvm::BasicBlock *Entry = Scope.getNormalBlock();
- if (!Entry) {
- Entry = CGF.createBasicBlock("cleanup");
- Scope.setNormalBlock(Entry);
- }
- return Entry;
-}
-
-/// Attempts to reduce a cleanup's entry block to a fallthrough. This
-/// is basically llvm::MergeBlockIntoPredecessor, except
-/// simplified/optimized for the tighter constraints on cleanup blocks.
-///
-/// Returns the new block, whatever it is.
-static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF,
- llvm::BasicBlock *Entry) {
- llvm::BasicBlock *Pred = Entry->getSinglePredecessor();
- if (!Pred) return Entry;
-
- llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Pred->getTerminator());
- if (!Br || Br->isConditional()) return Entry;
- assert(Br->getSuccessor(0) == Entry);
-
- // If we were previously inserting at the end of the cleanup entry
- // block, we'll need to continue inserting at the end of the
- // predecessor.
- bool WasInsertBlock = CGF.Builder.GetInsertBlock() == Entry;
- assert(!WasInsertBlock || CGF.Builder.GetInsertPoint() == Entry->end());
-
- // Kill the branch.
- Br->eraseFromParent();
-
- // Replace all uses of the entry with the predecessor, in case there
- // are phis in the cleanup.
- Entry->replaceAllUsesWith(Pred);
-
- // Merge the blocks.
- Pred->getInstList().splice(Pred->end(), Entry->getInstList());
-
- // Kill the entry block.
- Entry->eraseFromParent();
-
- if (WasInsertBlock)
- CGF.Builder.SetInsertPoint(Pred);
-
- return Pred;
-}
-
-static void EmitCleanup(CodeGenFunction &CGF,
- EHScopeStack::Cleanup *Fn,
- EHScopeStack::Cleanup::Flags flags,
- Address ActiveFlag) {
- // If there's an active flag, load it and skip the cleanup if it's
- // false.
- llvm::BasicBlock *ContBB = nullptr;
- if (ActiveFlag.isValid()) {
- ContBB = CGF.createBasicBlock("cleanup.done");
- llvm::BasicBlock *CleanupBB = CGF.createBasicBlock("cleanup.action");
- llvm::Value *IsActive
- = CGF.Builder.CreateLoad(ActiveFlag, "cleanup.is_active");
- CGF.Builder.CreateCondBr(IsActive, CleanupBB, ContBB);
- CGF.EmitBlock(CleanupBB);
- }
-
- // Ask the cleanup to emit itself.
- Fn->Emit(CGF, flags);
- assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?");
-
- // Emit the continuation block if there was an active flag.
- if (ActiveFlag.isValid())
- CGF.EmitBlock(ContBB);
-}
-
-static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
- llvm::BasicBlock *From,
- llvm::BasicBlock *To) {
- // Exit is the exit block of a cleanup, so it always terminates in
- // an unconditional branch or a switch.
- llvm::Instruction *Term = Exit->getTerminator();
-
- if (llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Term)) {
- assert(Br->isUnconditional() && Br->getSuccessor(0) == From);
- Br->setSuccessor(0, To);
- } else {
- llvm::SwitchInst *Switch = cast<llvm::SwitchInst>(Term);
- for (unsigned I = 0, E = Switch->getNumSuccessors(); I != E; ++I)
- if (Switch->getSuccessor(I) == From)
- Switch->setSuccessor(I, To);
- }
-}
-
-/// We don't need a normal entry block for the given cleanup.
-/// Optimistic fixup branches can cause these blocks to come into
-/// existence anyway; if so, destroy it.
-///
-/// The validity of this transformation is very much specific to the
-/// exact ways in which we form branches to cleanup entries.
-static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
- EHCleanupScope &scope) {
- llvm::BasicBlock *entry = scope.getNormalBlock();
- if (!entry) return;
-
- // Replace all the uses with unreachable.
- llvm::BasicBlock *unreachableBB = CGF.getUnreachableBlock();
- for (llvm::BasicBlock::use_iterator
- i = entry->use_begin(), e = entry->use_end(); i != e; ) {
- llvm::Use &use = *i;
- ++i;
-
- use.set(unreachableBB);
-
- // The only uses should be fixup switches.
- llvm::SwitchInst *si = cast<llvm::SwitchInst>(use.getUser());
- if (si->getNumCases() == 1 && si->getDefaultDest() == unreachableBB) {
- // Replace the switch with a branch.
- llvm::BranchInst::Create(si->case_begin()->getCaseSuccessor(), si);
-
- // The switch operand is a load from the cleanup-dest alloca.
- llvm::LoadInst *condition = cast<llvm::LoadInst>(si->getCondition());
-
- // Destroy the switch.
- si->eraseFromParent();
-
- // Destroy the load.
- assert(condition->getOperand(0) == CGF.NormalCleanupDest.getPointer());
- assert(condition->use_empty());
- condition->eraseFromParent();
- }
- }
-
- assert(entry->use_empty());
- delete entry;
-}
-
-/// Pops a cleanup block. If the block includes a normal cleanup, the
-/// current insertion point is threaded through the cleanup, as are
-/// any branch fixups on the cleanup.
-void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
- assert(!EHStack.empty() && "cleanup stack is empty!");
- assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!");
- EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
- assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups());
-
- // Remember activation information.
- bool IsActive = Scope.isActive();
- Address NormalActiveFlag =
- Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag()
- : Address::invalid();
- Address EHActiveFlag =
- Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag()
- : Address::invalid();
-
- // Check whether we need an EH cleanup. This is only true if we've
- // generated a lazy EH cleanup block.
- llvm::BasicBlock *EHEntry = Scope.getCachedEHDispatchBlock();
- assert(Scope.hasEHBranches() == (EHEntry != nullptr));
- bool RequiresEHCleanup = (EHEntry != nullptr);
- EHScopeStack::stable_iterator EHParent = Scope.getEnclosingEHScope();
-
- // Check the three conditions which might require a normal cleanup:
-
- // - whether there are branch fix-ups through this cleanup
- unsigned FixupDepth = Scope.getFixupDepth();
- bool HasFixups = EHStack.getNumBranchFixups() != FixupDepth;
-
- // - whether there are branch-throughs or branch-afters
- bool HasExistingBranches = Scope.hasBranches();
-
- // - whether there's a fallthrough
- llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock();
- bool HasFallthrough = (FallthroughSource != nullptr && IsActive);
-
- // Branch-through fall-throughs leave the insertion point set to the
- // end of the last cleanup, which points to the current scope. The
- // rest of IR gen doesn't need to worry about this; it only happens
- // during the execution of PopCleanupBlocks().
- bool HasPrebranchedFallthrough =
- (FallthroughSource && FallthroughSource->getTerminator());
-
- // If this is a normal cleanup, then having a prebranched
- // fallthrough implies that the fallthrough source unconditionally
- // jumps here.
- assert(!Scope.isNormalCleanup() || !HasPrebranchedFallthrough ||
- (Scope.getNormalBlock() &&
- FallthroughSource->getTerminator()->getSuccessor(0)
- == Scope.getNormalBlock()));
-
- bool RequiresNormalCleanup = false;
- if (Scope.isNormalCleanup() &&
- (HasFixups || HasExistingBranches || HasFallthrough)) {
- RequiresNormalCleanup = true;
- }
-
- // If we have a prebranched fallthrough into an inactive normal
- // cleanup, rewrite it so that it leads to the appropriate place.
- if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) {
- llvm::BasicBlock *prebranchDest;
-
- // If the prebranch is semantically branching through the next
- // cleanup, just forward it to the next block, leaving the
- // insertion point in the prebranched block.
- if (FallthroughIsBranchThrough) {
- EHScope &enclosing = *EHStack.find(Scope.getEnclosingNormalCleanup());
- prebranchDest = CreateNormalEntry(*this, cast<EHCleanupScope>(enclosing));
-
- // Otherwise, we need to make a new block. If the normal cleanup
- // isn't being used at all, we could actually reuse the normal
- // entry block, but this is simpler, and it avoids conflicts with
- // dead optimistic fixup branches.
- } else {
- prebranchDest = createBasicBlock("forwarded-prebranch");
- EmitBlock(prebranchDest);
- }
-
- llvm::BasicBlock *normalEntry = Scope.getNormalBlock();
- assert(normalEntry && !normalEntry->use_empty());
-
- ForwardPrebranchedFallthrough(FallthroughSource,
- normalEntry, prebranchDest);
- }
-
- // If we don't need the cleanup at all, we're done.
- if (!RequiresNormalCleanup && !RequiresEHCleanup) {
- destroyOptimisticNormalEntry(*this, Scope);
- EHStack.popCleanup(); // safe because there are no fixups
- assert(EHStack.getNumBranchFixups() == 0 ||
- EHStack.hasNormalCleanups());
- return;
- }
-
- // Copy the cleanup emission data out. This uses either a stack
- // array or malloc'd memory, depending on the size, which is
- // behavior that SmallVector would provide, if we could use it
- // here. Unfortunately, if you ask for a SmallVector<char>, the
- // alignment isn't sufficient.
- auto *CleanupSource = reinterpret_cast<char *>(Scope.getCleanupBuffer());
- llvm::AlignedCharArray<EHScopeStack::ScopeStackAlignment, 8 * sizeof(void *)> CleanupBufferStack;
- std::unique_ptr<char[]> CleanupBufferHeap;
- size_t CleanupSize = Scope.getCleanupSize();
- EHScopeStack::Cleanup *Fn;
-
- if (CleanupSize <= sizeof(CleanupBufferStack)) {
- memcpy(CleanupBufferStack.buffer, CleanupSource, CleanupSize);
- Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferStack.buffer);
- } else {
- CleanupBufferHeap.reset(new char[CleanupSize]);
- memcpy(CleanupBufferHeap.get(), CleanupSource, CleanupSize);
- Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferHeap.get());
- }
-
- EHScopeStack::Cleanup::Flags cleanupFlags;
- if (Scope.isNormalCleanup())
- cleanupFlags.setIsNormalCleanupKind();
- if (Scope.isEHCleanup())
- cleanupFlags.setIsEHCleanupKind();
-
- if (!RequiresNormalCleanup) {
- destroyOptimisticNormalEntry(*this, Scope);
- EHStack.popCleanup();
- } else {
- // If we have a fallthrough and no other need for the cleanup,
- // emit it directly.
- if (HasFallthrough && !HasPrebranchedFallthrough &&
- !HasFixups && !HasExistingBranches) {
-
- destroyOptimisticNormalEntry(*this, Scope);
- EHStack.popCleanup();
-
- EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
-
- // Otherwise, the best approach is to thread everything through
- // the cleanup block and then try to clean up after ourselves.
- } else {
- // Force the entry block to exist.
- llvm::BasicBlock *NormalEntry = CreateNormalEntry(*this, Scope);
-
- // I. Set up the fallthrough edge in.
-
- CGBuilderTy::InsertPoint savedInactiveFallthroughIP;
-
- // If there's a fallthrough, we need to store the cleanup
- // destination index. For fall-throughs this is always zero.
- if (HasFallthrough) {
- if (!HasPrebranchedFallthrough)
- Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot());
-
- // Otherwise, save and clear the IP if we don't have fallthrough
- // because the cleanup is inactive.
- } else if (FallthroughSource) {
- assert(!IsActive && "source without fallthrough for active cleanup");
- savedInactiveFallthroughIP = Builder.saveAndClearIP();
- }
-
- // II. Emit the entry block. This implicitly branches to it if
- // we have fallthrough. All the fixups and existing branches
- // should already be branched to it.
- EmitBlock(NormalEntry);
-
- // III. Figure out where we're going and build the cleanup
- // epilogue.
-
- bool HasEnclosingCleanups =
- (Scope.getEnclosingNormalCleanup() != EHStack.stable_end());
-
- // Compute the branch-through dest if we need it:
- // - if there are branch-throughs threaded through the scope
- // - if fall-through is a branch-through
- // - if there are fixups that will be optimistically forwarded
- // to the enclosing cleanup
- llvm::BasicBlock *BranchThroughDest = nullptr;
- if (Scope.hasBranchThroughs() ||
- (FallthroughSource && FallthroughIsBranchThrough) ||
- (HasFixups && HasEnclosingCleanups)) {
- assert(HasEnclosingCleanups);
- EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup());
- BranchThroughDest = CreateNormalEntry(*this, cast<EHCleanupScope>(S));
- }
-
- llvm::BasicBlock *FallthroughDest = nullptr;
- SmallVector<llvm::Instruction*, 2> InstsToAppend;
-
- // If there's exactly one branch-after and no other threads,
- // we can route it without a switch.
- if (!Scope.hasBranchThroughs() && !HasFixups && !HasFallthrough &&
- Scope.getNumBranchAfters() == 1) {
- assert(!BranchThroughDest || !IsActive);
-
- // Clean up the possibly dead store to the cleanup dest slot.
- llvm::Instruction *NormalCleanupDestSlot =
- cast<llvm::Instruction>(getNormalCleanupDestSlot().getPointer());
- if (NormalCleanupDestSlot->hasOneUse()) {
- NormalCleanupDestSlot->user_back()->eraseFromParent();
- NormalCleanupDestSlot->eraseFromParent();
- NormalCleanupDest = Address::invalid();
- }
-
- llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0);
- InstsToAppend.push_back(llvm::BranchInst::Create(BranchAfter));
-
- // Build a switch-out if we need it:
- // - if there are branch-afters threaded through the scope
- // - if fall-through is a branch-after
- // - if there are fixups that have nowhere left to go and
- // so must be immediately resolved
- } else if (Scope.getNumBranchAfters() ||
- (HasFallthrough && !FallthroughIsBranchThrough) ||
- (HasFixups && !HasEnclosingCleanups)) {
-
- llvm::BasicBlock *Default =
- (BranchThroughDest ? BranchThroughDest : getUnreachableBlock());
-
- // TODO: base this on the number of branch-afters and fixups
- const unsigned SwitchCapacity = 10;
-
- llvm::LoadInst *Load =
- createLoadInstBefore(getNormalCleanupDestSlot(), "cleanup.dest",
- nullptr);
- llvm::SwitchInst *Switch =
- llvm::SwitchInst::Create(Load, Default, SwitchCapacity);
-
- InstsToAppend.push_back(Load);
- InstsToAppend.push_back(Switch);
-
- // Branch-after fallthrough.
- if (FallthroughSource && !FallthroughIsBranchThrough) {
- FallthroughDest = createBasicBlock("cleanup.cont");
- if (HasFallthrough)
- Switch->addCase(Builder.getInt32(0), FallthroughDest);
- }
-
- for (unsigned I = 0, E = Scope.getNumBranchAfters(); I != E; ++I) {
- Switch->addCase(Scope.getBranchAfterIndex(I),
- Scope.getBranchAfterBlock(I));
- }
-
- // If there aren't any enclosing cleanups, we can resolve all
- // the fixups now.
- if (HasFixups && !HasEnclosingCleanups)
- ResolveAllBranchFixups(*this, Switch, NormalEntry);
- } else {
- // We should always have a branch-through destination in this case.
- assert(BranchThroughDest);
- InstsToAppend.push_back(llvm::BranchInst::Create(BranchThroughDest));
- }
-
- // IV. Pop the cleanup and emit it.
- EHStack.popCleanup();
- assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);
-
- EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
-
- // Append the prepared cleanup prologue from above.
- llvm::BasicBlock *NormalExit = Builder.GetInsertBlock();
- for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I)
- NormalExit->getInstList().push_back(InstsToAppend[I]);
-
- // Optimistically hope that any fixups will continue falling through.
- for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups();
- I < E; ++I) {
- BranchFixup &Fixup = EHStack.getBranchFixup(I);
- if (!Fixup.Destination) continue;
- if (!Fixup.OptimisticBranchBlock) {
- createStoreInstBefore(Builder.getInt32(Fixup.DestinationIndex),
- getNormalCleanupDestSlot(),
- Fixup.InitialBranch);
- Fixup.InitialBranch->setSuccessor(0, NormalEntry);
- }
- Fixup.OptimisticBranchBlock = NormalExit;
- }
-
- // V. Set up the fallthrough edge out.
-
- // Case 1: a fallthrough source exists but doesn't branch to the
- // cleanup because the cleanup is inactive.
- if (!HasFallthrough && FallthroughSource) {
- // Prebranched fallthrough was forwarded earlier.
- // Non-prebranched fallthrough doesn't need to be forwarded.
- // Either way, all we need to do is restore the IP we cleared before.
- assert(!IsActive);
- Builder.restoreIP(savedInactiveFallthroughIP);
-
- // Case 2: a fallthrough source exists and should branch to the
- // cleanup, but we're not supposed to branch through to the next
- // cleanup.
- } else if (HasFallthrough && FallthroughDest) {
- assert(!FallthroughIsBranchThrough);
- EmitBlock(FallthroughDest);
-
- // Case 3: a fallthrough source exists and should branch to the
- // cleanup and then through to the next.
- } else if (HasFallthrough) {
- // Everything is already set up for this.
-
- // Case 4: no fallthrough source exists.
- } else {
- Builder.ClearInsertionPoint();
- }
-
- // VI. Assorted cleaning.
-
- // Check whether we can merge NormalEntry into a single predecessor.
- // This might invalidate (non-IR) pointers to NormalEntry.
- llvm::BasicBlock *NewNormalEntry =
- SimplifyCleanupEntry(*this, NormalEntry);
-
- // If it did invalidate those pointers, and NormalEntry was the same
- // as NormalExit, go back and patch up the fixups.
- if (NewNormalEntry != NormalEntry && NormalEntry == NormalExit)
- for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups();
- I < E; ++I)
- EHStack.getBranchFixup(I).OptimisticBranchBlock = NewNormalEntry;
- }
- }
-
- assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0);
-
- // Emit the EH cleanup if required.
- if (RequiresEHCleanup) {
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
-
- EmitBlock(EHEntry);
-
- llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent);
-
- // Push a terminate scope or cleanupendpad scope around the potentially
- // throwing cleanups. For funclet EH personalities, the cleanupendpad models
- // program termination when cleanups throw.
- bool PushedTerminate = false;
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
- llvm::CleanupPadInst *CPI = nullptr;
-
- const EHPersonality &Personality = EHPersonality::get(*this);
- if (Personality.usesFuncletPads()) {
- llvm::Value *ParentPad = CurrentFuncletPad;
- if (!ParentPad)
- ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
- CurrentFuncletPad = CPI = Builder.CreateCleanupPad(ParentPad);
- }
-
- // Non-MSVC personalities need to terminate when an EH cleanup throws.
- if (!Personality.isMSVCPersonality()) {
- EHStack.pushTerminate();
- PushedTerminate = true;
- }
-
- // We only actually emit the cleanup code if the cleanup is either
- // active or was used before it was deactivated.
- if (EHActiveFlag.isValid() || IsActive) {
- cleanupFlags.setIsForEHCleanup();
- EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag);
- }
-
- if (CPI)
- Builder.CreateCleanupRet(CPI, NextAction);
- else
- Builder.CreateBr(NextAction);
-
- // Leave the terminate scope.
- if (PushedTerminate)
- EHStack.popTerminate();
-
- Builder.restoreIP(SavedIP);
-
- SimplifyCleanupEntry(*this, EHEntry);
- }
-}
-
-/// isObviouslyBranchWithoutCleanups - Return true if a branch to the
-/// specified destination obviously has no cleanups to run. 'false' is always
-/// a conservatively correct answer for this method.
-bool CodeGenFunction::isObviouslyBranchWithoutCleanups(JumpDest Dest) const {
- assert(Dest.getScopeDepth().encloses(EHStack.stable_begin())
- && "stale jump destination");
-
- // Calculate the innermost active normal cleanup.
- EHScopeStack::stable_iterator TopCleanup =
- EHStack.getInnermostActiveNormalCleanup();
-
- // If we're not in an active normal cleanup scope, or if the
- // destination scope is within the innermost active normal cleanup
- // scope, we don't need to worry about fixups.
- if (TopCleanup == EHStack.stable_end() ||
- TopCleanup.encloses(Dest.getScopeDepth())) // works for invalid
- return true;
-
- // Otherwise, we might need some cleanups.
- return false;
-}
-
-
-/// Terminate the current block by emitting a branch which might leave
-/// the current cleanup-protected scope. The target scope may not yet
-/// be known, in which case this will require a fixup.
-///
-/// As a side-effect, this method clears the insertion point.
-void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
- assert(Dest.getScopeDepth().encloses(EHStack.stable_begin())
- && "stale jump destination");
-
- if (!HaveInsertPoint())
- return;
-
- // Create the branch.
- llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock());
-
- // Calculate the innermost active normal cleanup.
- EHScopeStack::stable_iterator
- TopCleanup = EHStack.getInnermostActiveNormalCleanup();
-
- // If we're not in an active normal cleanup scope, or if the
- // destination scope is within the innermost active normal cleanup
- // scope, we don't need to worry about fixups.
- if (TopCleanup == EHStack.stable_end() ||
- TopCleanup.encloses(Dest.getScopeDepth())) { // works for invalid
- Builder.ClearInsertionPoint();
- return;
- }
-
- // If we can't resolve the destination cleanup scope, just add this
- // to the current cleanup scope as a branch fixup.
- if (!Dest.getScopeDepth().isValid()) {
- BranchFixup &Fixup = EHStack.addBranchFixup();
- Fixup.Destination = Dest.getBlock();
- Fixup.DestinationIndex = Dest.getDestIndex();
- Fixup.InitialBranch = BI;
- Fixup.OptimisticBranchBlock = nullptr;
-
- Builder.ClearInsertionPoint();
- return;
- }
-
- // Otherwise, thread through all the normal cleanups in scope.
-
- // Store the index at the start.
- llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex());
- createStoreInstBefore(Index, getNormalCleanupDestSlot(), BI);
-
- // Adjust BI to point to the first cleanup block.
- {
- EHCleanupScope &Scope =
- cast<EHCleanupScope>(*EHStack.find(TopCleanup));
- BI->setSuccessor(0, CreateNormalEntry(*this, Scope));
- }
-
- // Add this destination to all the scopes involved.
- EHScopeStack::stable_iterator I = TopCleanup;
- EHScopeStack::stable_iterator E = Dest.getScopeDepth();
- if (E.strictlyEncloses(I)) {
- while (true) {
- EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(I));
- assert(Scope.isNormalCleanup());
- I = Scope.getEnclosingNormalCleanup();
-
- // If this is the last cleanup we're propagating through, tell it
- // that there's a resolved jump moving through it.
- if (!E.strictlyEncloses(I)) {
- Scope.addBranchAfter(Index, Dest.getBlock());
- break;
- }
-
- // Otherwise, tell the scope that there's a jump propagating
- // through it. If this isn't new information, all the rest of
- // the work has been done before.
- if (!Scope.addBranchThrough(Dest.getBlock()))
- break;
- }
- }
-
- Builder.ClearInsertionPoint();
-}
-
-static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack,
- EHScopeStack::stable_iterator C) {
- // If we needed a normal block for any reason, that counts.
- if (cast<EHCleanupScope>(*EHStack.find(C)).getNormalBlock())
- return true;
-
- // Check whether any enclosed cleanups were needed.
- for (EHScopeStack::stable_iterator
- I = EHStack.getInnermostNormalCleanup();
- I != C; ) {
- assert(C.strictlyEncloses(I));
- EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I));
- if (S.getNormalBlock()) return true;
- I = S.getEnclosingNormalCleanup();
- }
-
- return false;
-}
-
-static bool IsUsedAsEHCleanup(EHScopeStack &EHStack,
- EHScopeStack::stable_iterator cleanup) {
- // If we needed an EH block for any reason, that counts.
- if (EHStack.find(cleanup)->hasEHBranches())
- return true;
-
- // Check whether any enclosed cleanups were needed.
- for (EHScopeStack::stable_iterator
- i = EHStack.getInnermostEHScope(); i != cleanup; ) {
- assert(cleanup.strictlyEncloses(i));
-
- EHScope &scope = *EHStack.find(i);
- if (scope.hasEHBranches())
- return true;
-
- i = scope.getEnclosingEHScope();
- }
-
- return false;
-}
-
-enum ForActivation_t {
- ForActivation,
- ForDeactivation
-};
-
-/// The given cleanup block is changing activation state. Configure a
-/// cleanup variable if necessary.
-///
-/// It would be good if we had some way of determining if there were
-/// extra uses *after* the change-over point.
-static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
- EHScopeStack::stable_iterator C,
- ForActivation_t kind,
- llvm::Instruction *dominatingIP) {
- EHCleanupScope &Scope = cast<EHCleanupScope>(*CGF.EHStack.find(C));
-
- // We always need the flag if we're activating the cleanup in a
- // conditional context, because we have to assume that the current
- // location doesn't necessarily dominate the cleanup's code.
- bool isActivatedInConditional =
- (kind == ForActivation && CGF.isInConditionalBranch());
-
- bool needFlag = false;
-
- // Calculate whether the cleanup was used:
-
- // - as a normal cleanup
- if (Scope.isNormalCleanup() &&
- (isActivatedInConditional || IsUsedAsNormalCleanup(CGF.EHStack, C))) {
- Scope.setTestFlagInNormalCleanup();
- needFlag = true;
- }
-
- // - as an EH cleanup
- if (Scope.isEHCleanup() &&
- (isActivatedInConditional || IsUsedAsEHCleanup(CGF.EHStack, C))) {
- Scope.setTestFlagInEHCleanup();
- needFlag = true;
- }
-
- // If it hasn't yet been used as either, we're done.
- if (!needFlag) return;
-
- Address var = Scope.getActiveFlag();
- if (!var.isValid()) {
- var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), CharUnits::One(),
- "cleanup.isactive");
- Scope.setActiveFlag(var);
-
- assert(dominatingIP && "no existing variable and no dominating IP!");
-
- // Initialize to true or false depending on whether it was
- // active up to this point.
- llvm::Constant *value = CGF.Builder.getInt1(kind == ForDeactivation);
-
- // If we're in a conditional block, ignore the dominating IP and
- // use the outermost conditional branch.
- if (CGF.isInConditionalBranch()) {
- CGF.setBeforeOutermostConditional(value, var);
- } else {
- createStoreInstBefore(value, var, dominatingIP);
- }
- }
-
- CGF.Builder.CreateStore(CGF.Builder.getInt1(kind == ForActivation), var);
-}
-
-/// Activate a cleanup that was created in an inactivated state.
-void CodeGenFunction::ActivateCleanupBlock(EHScopeStack::stable_iterator C,
- llvm::Instruction *dominatingIP) {
- assert(C != EHStack.stable_end() && "activating bottom of stack?");
- EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
- assert(!Scope.isActive() && "double activation");
-
- SetupCleanupBlockActivation(*this, C, ForActivation, dominatingIP);
-
- Scope.setActive(true);
-}
-
-/// Deactive a cleanup that was created in an active state.
-void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
- llvm::Instruction *dominatingIP) {
- assert(C != EHStack.stable_end() && "deactivating bottom of stack?");
- EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
- assert(Scope.isActive() && "double deactivation");
-
- // If it's the top of the stack, just pop it, but do so only if it belongs
- // to the current RunCleanupsScope.
- if (C == EHStack.stable_begin() &&
- CurrentCleanupScopeDepth.strictlyEncloses(C)) {
- // If it's a normal cleanup, we need to pretend that the
- // fallthrough is unreachable.
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
- PopCleanupBlock();
- Builder.restoreIP(SavedIP);
- return;
- }
-
- // Otherwise, follow the general case.
- SetupCleanupBlockActivation(*this, C, ForDeactivation, dominatingIP);
-
- Scope.setActive(false);
-}
-
-Address CodeGenFunction::getNormalCleanupDestSlot() {
- if (!NormalCleanupDest.isValid())
- NormalCleanupDest =
- CreateDefaultAlignTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot");
- return NormalCleanupDest;
-}
-
-/// Emits all the code to cause the given temporary to be cleaned up.
-void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
- QualType TempType,
- Address Ptr) {
- pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
- /*useEHCleanup*/ true);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h b/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h
deleted file mode 100644
index 15d6f46dcb5..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCleanup.h
+++ /dev/null
@@ -1,650 +0,0 @@
-//===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes support the generation of LLVM IR for cleanups.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
-#define LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
-
-#include "EHScopeStack.h"
-
-#include "Address.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
-
-namespace llvm {
-class BasicBlock;
-class Value;
-class ConstantInt;
-class AllocaInst;
-}
-
-namespace clang {
-class FunctionDecl;
-namespace CodeGen {
-class CodeGenModule;
-class CodeGenFunction;
-
-/// The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the
-/// type of a catch handler, so we use this wrapper.
-struct CatchTypeInfo {
- llvm::Constant *RTTI;
- unsigned Flags;
-};
-
-/// A protected scope for zero-cost EH handling.
-class EHScope {
- llvm::BasicBlock *CachedLandingPad;
- llvm::BasicBlock *CachedEHDispatchBlock;
-
- EHScopeStack::stable_iterator EnclosingEHScope;
-
- class CommonBitFields {
- friend class EHScope;
- unsigned Kind : 3;
- };
- enum { NumCommonBits = 3 };
-
-protected:
- class CatchBitFields {
- friend class EHCatchScope;
- unsigned : NumCommonBits;
-
- unsigned NumHandlers : 32 - NumCommonBits;
- };
-
- class CleanupBitFields {
- friend class EHCleanupScope;
- unsigned : NumCommonBits;
-
- /// Whether this cleanup needs to be run along normal edges.
- unsigned IsNormalCleanup : 1;
-
- /// Whether this cleanup needs to be run along exception edges.
- unsigned IsEHCleanup : 1;
-
- /// Whether this cleanup is currently active.
- unsigned IsActive : 1;
-
- /// Whether this cleanup is a lifetime marker
- unsigned IsLifetimeMarker : 1;
-
- /// Whether the normal cleanup should test the activation flag.
- unsigned TestFlagInNormalCleanup : 1;
-
- /// Whether the EH cleanup should test the activation flag.
- unsigned TestFlagInEHCleanup : 1;
-
- /// The amount of extra storage needed by the Cleanup.
- /// Always a multiple of the scope-stack alignment.
- unsigned CleanupSize : 12;
- };
-
- class FilterBitFields {
- friend class EHFilterScope;
- unsigned : NumCommonBits;
-
- unsigned NumFilters : 32 - NumCommonBits;
- };
-
- union {
- CommonBitFields CommonBits;
- CatchBitFields CatchBits;
- CleanupBitFields CleanupBits;
- FilterBitFields FilterBits;
- };
-
-public:
- enum Kind { Cleanup, Catch, Terminate, Filter, PadEnd };
-
- EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
- : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr),
- EnclosingEHScope(enclosingEHScope) {
- CommonBits.Kind = kind;
- }
-
- Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); }
-
- llvm::BasicBlock *getCachedLandingPad() const {
- return CachedLandingPad;
- }
-
- void setCachedLandingPad(llvm::BasicBlock *block) {
- CachedLandingPad = block;
- }
-
- llvm::BasicBlock *getCachedEHDispatchBlock() const {
- return CachedEHDispatchBlock;
- }
-
- void setCachedEHDispatchBlock(llvm::BasicBlock *block) {
- CachedEHDispatchBlock = block;
- }
-
- bool hasEHBranches() const {
- if (llvm::BasicBlock *block = getCachedEHDispatchBlock())
- return !block->use_empty();
- return false;
- }
-
- EHScopeStack::stable_iterator getEnclosingEHScope() const {
- return EnclosingEHScope;
- }
-};
-
-/// A scope which attempts to handle some, possibly all, types of
-/// exceptions.
-///
-/// Objective C \@finally blocks are represented using a cleanup scope
-/// after the catch scope.
-class EHCatchScope : public EHScope {
- // In effect, we have a flexible array member
- // Handler Handlers[0];
- // But that's only standard in C99, not C++, so we have to do
- // annoying pointer arithmetic instead.
-
-public:
- struct Handler {
- /// A type info value, or null (C++ null, not an LLVM null pointer)
- /// for a catch-all.
- CatchTypeInfo Type;
-
- /// The catch handler for this type.
- llvm::BasicBlock *Block;
-
- bool isCatchAll() const { return Type.RTTI == nullptr; }
- };
-
-private:
- friend class EHScopeStack;
-
- Handler *getHandlers() {
- return reinterpret_cast<Handler*>(this+1);
- }
-
- const Handler *getHandlers() const {
- return reinterpret_cast<const Handler*>(this+1);
- }
-
-public:
- static size_t getSizeForNumHandlers(unsigned N) {
- return sizeof(EHCatchScope) + N * sizeof(Handler);
- }
-
- EHCatchScope(unsigned numHandlers,
- EHScopeStack::stable_iterator enclosingEHScope)
- : EHScope(Catch, enclosingEHScope) {
- CatchBits.NumHandlers = numHandlers;
- assert(CatchBits.NumHandlers == numHandlers && "NumHandlers overflow?");
- }
-
- unsigned getNumHandlers() const {
- return CatchBits.NumHandlers;
- }
-
- void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
- setHandler(I, CatchTypeInfo{nullptr, 0}, Block);
- }
-
- void setHandler(unsigned I, llvm::Constant *Type, llvm::BasicBlock *Block) {
- assert(I < getNumHandlers());
- getHandlers()[I].Type = CatchTypeInfo{Type, 0};
- getHandlers()[I].Block = Block;
- }
-
- void setHandler(unsigned I, CatchTypeInfo Type, llvm::BasicBlock *Block) {
- assert(I < getNumHandlers());
- getHandlers()[I].Type = Type;
- getHandlers()[I].Block = Block;
- }
-
- const Handler &getHandler(unsigned I) const {
- assert(I < getNumHandlers());
- return getHandlers()[I];
- }
-
- // Clear all handler blocks.
- // FIXME: it's better to always call clearHandlerBlocks in DTOR and have a
- // 'takeHandler' or some such function which removes ownership from the
- // EHCatchScope object if the handlers should live longer than EHCatchScope.
- void clearHandlerBlocks() {
- for (unsigned I = 0, N = getNumHandlers(); I != N; ++I)
- delete getHandler(I).Block;
- }
-
- typedef const Handler *iterator;
- iterator begin() const { return getHandlers(); }
- iterator end() const { return getHandlers() + getNumHandlers(); }
-
- static bool classof(const EHScope *Scope) {
- return Scope->getKind() == Catch;
- }
-};
-
-/// A cleanup scope which generates the cleanup blocks lazily.
-class alignas(8) EHCleanupScope : public EHScope {
- /// The nearest normal cleanup scope enclosing this one.
- EHScopeStack::stable_iterator EnclosingNormal;
-
- /// The nearest EH scope enclosing this one.
- EHScopeStack::stable_iterator EnclosingEH;
-
- /// The dual entry/exit block along the normal edge. This is lazily
- /// created if needed before the cleanup is popped.
- llvm::BasicBlock *NormalBlock;
-
- /// An optional i1 variable indicating whether this cleanup has been
- /// activated yet.
- llvm::AllocaInst *ActiveFlag;
-
- /// Extra information required for cleanups that have resolved
- /// branches through them. This has to be allocated on the side
- /// because everything on the cleanup stack has be trivially
- /// movable.
- struct ExtInfo {
- /// The destinations of normal branch-afters and branch-throughs.
- llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
-
- /// Normal branch-afters.
- SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
- BranchAfters;
- };
- mutable struct ExtInfo *ExtInfo;
-
- /// The number of fixups required by enclosing scopes (not including
- /// this one). If this is the top cleanup scope, all the fixups
- /// from this index onwards belong to this scope.
- unsigned FixupDepth;
-
- struct ExtInfo &getExtInfo() {
- if (!ExtInfo) ExtInfo = new struct ExtInfo();
- return *ExtInfo;
- }
-
- const struct ExtInfo &getExtInfo() const {
- if (!ExtInfo) ExtInfo = new struct ExtInfo();
- return *ExtInfo;
- }
-
-public:
- /// Gets the size required for a lazy cleanup scope with the given
- /// cleanup-data requirements.
- static size_t getSizeForCleanupSize(size_t Size) {
- return sizeof(EHCleanupScope) + Size;
- }
-
- size_t getAllocatedSize() const {
- return sizeof(EHCleanupScope) + CleanupBits.CleanupSize;
- }
-
- EHCleanupScope(bool isNormal, bool isEH, bool isActive,
- unsigned cleanupSize, unsigned fixupDepth,
- EHScopeStack::stable_iterator enclosingNormal,
- EHScopeStack::stable_iterator enclosingEH)
- : EHScope(EHScope::Cleanup, enclosingEH),
- EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
- ActiveFlag(nullptr), ExtInfo(nullptr), FixupDepth(fixupDepth) {
- CleanupBits.IsNormalCleanup = isNormal;
- CleanupBits.IsEHCleanup = isEH;
- CleanupBits.IsActive = isActive;
- CleanupBits.IsLifetimeMarker = false;
- CleanupBits.TestFlagInNormalCleanup = false;
- CleanupBits.TestFlagInEHCleanup = false;
- CleanupBits.CleanupSize = cleanupSize;
-
- assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
- }
-
- void Destroy() {
- delete ExtInfo;
- }
- // Objects of EHCleanupScope are not destructed. Use Destroy().
- ~EHCleanupScope() = delete;
-
- bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
- llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
- void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
-
- bool isEHCleanup() const { return CleanupBits.IsEHCleanup; }
-
- bool isActive() const { return CleanupBits.IsActive; }
- void setActive(bool A) { CleanupBits.IsActive = A; }
-
- bool isLifetimeMarker() const { return CleanupBits.IsLifetimeMarker; }
- void setLifetimeMarker() { CleanupBits.IsLifetimeMarker = true; }
-
- bool hasActiveFlag() const { return ActiveFlag != nullptr; }
- Address getActiveFlag() const {
- return Address(ActiveFlag, CharUnits::One());
- }
- void setActiveFlag(Address Var) {
- assert(Var.getAlignment().isOne());
- ActiveFlag = cast<llvm::AllocaInst>(Var.getPointer());
- }
-
- void setTestFlagInNormalCleanup() {
- CleanupBits.TestFlagInNormalCleanup = true;
- }
- bool shouldTestFlagInNormalCleanup() const {
- return CleanupBits.TestFlagInNormalCleanup;
- }
-
- void setTestFlagInEHCleanup() {
- CleanupBits.TestFlagInEHCleanup = true;
- }
- bool shouldTestFlagInEHCleanup() const {
- return CleanupBits.TestFlagInEHCleanup;
- }
-
- unsigned getFixupDepth() const { return FixupDepth; }
- EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
- return EnclosingNormal;
- }
-
- size_t getCleanupSize() const { return CleanupBits.CleanupSize; }
- void *getCleanupBuffer() { return this + 1; }
-
- EHScopeStack::Cleanup *getCleanup() {
- return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
- }
-
- /// True if this cleanup scope has any branch-afters or branch-throughs.
- bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
-
- /// Add a branch-after to this cleanup scope. A branch-after is a
- /// branch from a point protected by this (normal) cleanup to a
- /// point in the normal cleanup scope immediately containing it.
- /// For example,
- /// for (;;) { A a; break; }
- /// contains a branch-after.
- ///
- /// Branch-afters each have their own destination out of the
- /// cleanup, guaranteed distinct from anything else threaded through
- /// it. Therefore branch-afters usually force a switch after the
- /// cleanup.
- void addBranchAfter(llvm::ConstantInt *Index,
- llvm::BasicBlock *Block) {
- struct ExtInfo &ExtInfo = getExtInfo();
- if (ExtInfo.Branches.insert(Block).second)
- ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
- }
-
- /// Return the number of unique branch-afters on this scope.
- unsigned getNumBranchAfters() const {
- return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
- }
-
- llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
- assert(I < getNumBranchAfters());
- return ExtInfo->BranchAfters[I].first;
- }
-
- llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
- assert(I < getNumBranchAfters());
- return ExtInfo->BranchAfters[I].second;
- }
-
- /// Add a branch-through to this cleanup scope. A branch-through is
- /// a branch from a scope protected by this (normal) cleanup to an
- /// enclosing scope other than the immediately-enclosing normal
- /// cleanup scope.
- ///
- /// In the following example, the branch through B's scope is a
- /// branch-through, while the branch through A's scope is a
- /// branch-after:
- /// for (;;) { A a; B b; break; }
- ///
- /// All branch-throughs have a common destination out of the
- /// cleanup, one possibly shared with the fall-through. Therefore
- /// branch-throughs usually don't force a switch after the cleanup.
- ///
- /// \return true if the branch-through was new to this scope
- bool addBranchThrough(llvm::BasicBlock *Block) {
- return getExtInfo().Branches.insert(Block).second;
- }
-
- /// Determines if this cleanup scope has any branch throughs.
- bool hasBranchThroughs() const {
- if (!ExtInfo) return false;
- return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
- }
-
- static bool classof(const EHScope *Scope) {
- return (Scope->getKind() == Cleanup);
- }
-};
-// NOTE: there's a bunch of different data classes tacked on after an
-// EHCleanupScope. It is asserted (in EHScopeStack::pushCleanup*) that
-// they don't require greater alignment than ScopeStackAlignment. So,
-// EHCleanupScope ought to have alignment equal to that -- not more
-// (would be misaligned by the stack allocator), and not less (would
-// break the appended classes).
-static_assert(alignof(EHCleanupScope) == EHScopeStack::ScopeStackAlignment,
- "EHCleanupScope expected alignment");
-
-/// An exceptions scope which filters exceptions thrown through it.
-/// Only exceptions matching the filter types will be permitted to be
-/// thrown.
-///
-/// This is used to implement C++ exception specifications.
-class EHFilterScope : public EHScope {
- // Essentially ends in a flexible array member:
- // llvm::Value *FilterTypes[0];
-
- llvm::Value **getFilters() {
- return reinterpret_cast<llvm::Value**>(this+1);
- }
-
- llvm::Value * const *getFilters() const {
- return reinterpret_cast<llvm::Value* const *>(this+1);
- }
-
-public:
- EHFilterScope(unsigned numFilters)
- : EHScope(Filter, EHScopeStack::stable_end()) {
- FilterBits.NumFilters = numFilters;
- assert(FilterBits.NumFilters == numFilters && "NumFilters overflow");
- }
-
- static size_t getSizeForNumFilters(unsigned numFilters) {
- return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*);
- }
-
- unsigned getNumFilters() const { return FilterBits.NumFilters; }
-
- void setFilter(unsigned i, llvm::Value *filterValue) {
- assert(i < getNumFilters());
- getFilters()[i] = filterValue;
- }
-
- llvm::Value *getFilter(unsigned i) const {
- assert(i < getNumFilters());
- return getFilters()[i];
- }
-
- static bool classof(const EHScope *scope) {
- return scope->getKind() == Filter;
- }
-};
-
-/// An exceptions scope which calls std::terminate if any exception
-/// reaches it.
-class EHTerminateScope : public EHScope {
-public:
- EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)
- : EHScope(Terminate, enclosingEHScope) {}
- static size_t getSize() { return sizeof(EHTerminateScope); }
-
- static bool classof(const EHScope *scope) {
- return scope->getKind() == Terminate;
- }
-};
-
-class EHPadEndScope : public EHScope {
-public:
- EHPadEndScope(EHScopeStack::stable_iterator enclosingEHScope)
- : EHScope(PadEnd, enclosingEHScope) {}
- static size_t getSize() { return sizeof(EHPadEndScope); }
-
- static bool classof(const EHScope *scope) {
- return scope->getKind() == PadEnd;
- }
-};
-
-/// A non-stable pointer into the scope stack.
-class EHScopeStack::iterator {
- char *Ptr;
-
- friend class EHScopeStack;
- explicit iterator(char *Ptr) : Ptr(Ptr) {}
-
-public:
- iterator() : Ptr(nullptr) {}
-
- EHScope *get() const {
- return reinterpret_cast<EHScope*>(Ptr);
- }
-
- EHScope *operator->() const { return get(); }
- EHScope &operator*() const { return *get(); }
-
- iterator &operator++() {
- size_t Size;
- switch (get()->getKind()) {
- case EHScope::Catch:
- Size = EHCatchScope::getSizeForNumHandlers(
- static_cast<const EHCatchScope *>(get())->getNumHandlers());
- break;
-
- case EHScope::Filter:
- Size = EHFilterScope::getSizeForNumFilters(
- static_cast<const EHFilterScope *>(get())->getNumFilters());
- break;
-
- case EHScope::Cleanup:
- Size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize();
- break;
-
- case EHScope::Terminate:
- Size = EHTerminateScope::getSize();
- break;
-
- case EHScope::PadEnd:
- Size = EHPadEndScope::getSize();
- break;
- }
- Ptr += llvm::alignTo(Size, ScopeStackAlignment);
- return *this;
- }
-
- iterator next() {
- iterator copy = *this;
- ++copy;
- return copy;
- }
-
- iterator operator++(int) {
- iterator copy = *this;
- operator++();
- return copy;
- }
-
- bool encloses(iterator other) const { return Ptr >= other.Ptr; }
- bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
-
- bool operator==(iterator other) const { return Ptr == other.Ptr; }
- bool operator!=(iterator other) const { return Ptr != other.Ptr; }
-};
-
-inline EHScopeStack::iterator EHScopeStack::begin() const {
- return iterator(StartOfData);
-}
-
-inline EHScopeStack::iterator EHScopeStack::end() const {
- return iterator(EndOfBuffer);
-}
-
-inline void EHScopeStack::popCatch() {
- assert(!empty() && "popping exception stack when not empty");
-
- EHCatchScope &scope = cast<EHCatchScope>(*begin());
- InnermostEHScope = scope.getEnclosingEHScope();
- deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
-}
-
-inline void EHScopeStack::popTerminate() {
- assert(!empty() && "popping exception stack when not empty");
-
- EHTerminateScope &scope = cast<EHTerminateScope>(*begin());
- InnermostEHScope = scope.getEnclosingEHScope();
- deallocate(EHTerminateScope::getSize());
-}
-
-inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
- assert(sp.isValid() && "finding invalid savepoint");
- assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
- return iterator(EndOfBuffer - sp.Size);
-}
-
-inline EHScopeStack::stable_iterator
-EHScopeStack::stabilize(iterator ir) const {
- assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
- return stable_iterator(EndOfBuffer - ir.Ptr);
-}
-
-/// The exceptions personality for a function.
-struct EHPersonality {
- const char *PersonalityFn;
-
- // If this is non-null, this personality requires a non-standard
- // function for rethrowing an exception after a catchall cleanup.
- // This function must have prototype void(void*).
- const char *CatchallRethrowFn;
-
- static const EHPersonality &get(CodeGenModule &CGM, const FunctionDecl *FD);
- static const EHPersonality &get(CodeGenFunction &CGF);
-
- static const EHPersonality GNU_C;
- static const EHPersonality GNU_C_SJLJ;
- static const EHPersonality GNU_C_SEH;
- static const EHPersonality GNU_ObjC;
- static const EHPersonality GNU_ObjC_SJLJ;
- static const EHPersonality GNU_ObjC_SEH;
- static const EHPersonality GNUstep_ObjC;
- static const EHPersonality GNU_ObjCXX;
- static const EHPersonality NeXT_ObjC;
- static const EHPersonality GNU_CPlusPlus;
- static const EHPersonality GNU_CPlusPlus_SJLJ;
- static const EHPersonality GNU_CPlusPlus_SEH;
- static const EHPersonality MSVC_except_handler;
- static const EHPersonality MSVC_C_specific_handler;
- static const EHPersonality MSVC_CxxFrameHandler3;
- static const EHPersonality GNU_Wasm_CPlusPlus;
-
- /// Does this personality use landingpads or the family of pad instructions
- /// designed to form funclets?
- bool usesFuncletPads() const {
- return isMSVCPersonality() || isWasmPersonality();
- }
-
- bool isMSVCPersonality() const {
- return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
- this == &MSVC_CxxFrameHandler3;
- }
-
- bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
-
- bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
-};
-}
-}
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp
deleted file mode 100644
index 80fa7c87363..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp
+++ /dev/null
@@ -1,760 +0,0 @@
-//===----- CGCoroutine.cpp - Emit LLVM Code for C++ coroutines ------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of coroutines.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCleanup.h"
-#include "CodeGenFunction.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtVisitor.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-using llvm::Value;
-using llvm::BasicBlock;
-
-namespace {
-enum class AwaitKind { Init, Normal, Yield, Final };
-static constexpr llvm::StringLiteral AwaitKindStr[] = {"init", "await", "yield",
- "final"};
-}
-
-struct clang::CodeGen::CGCoroData {
- // What is the current await expression kind and how many
- // await/yield expressions were encountered so far.
- // These are used to generate pretty labels for await expressions in LLVM IR.
- AwaitKind CurrentAwaitKind = AwaitKind::Init;
- unsigned AwaitNum = 0;
- unsigned YieldNum = 0;
-
- // How many co_return statements are in the coroutine. Used to decide whether
- // we need to add co_return; equivalent at the end of the user authored body.
- unsigned CoreturnCount = 0;
-
- // A branch to this block is emitted when coroutine needs to suspend.
- llvm::BasicBlock *SuspendBB = nullptr;
-
- // The promise type's 'unhandled_exception' handler, if it defines one.
- Stmt *ExceptionHandler = nullptr;
-
- // A temporary i1 alloca that stores whether 'await_resume' threw an
- // exception. If it did, 'true' is stored in this variable, and the coroutine
- // body must be skipped. If the promise type does not define an exception
- // handler, this is null.
- llvm::Value *ResumeEHVar = nullptr;
-
- // Stores the jump destination just before the coroutine memory is freed.
- // This is the destination that every suspend point jumps to for the cleanup
- // branch.
- CodeGenFunction::JumpDest CleanupJD;
-
- // Stores the jump destination just before the final suspend. The co_return
- // statements jumps to this point after calling return_xxx promise member.
- CodeGenFunction::JumpDest FinalJD;
-
- // Stores the llvm.coro.id emitted in the function so that we can supply it
- // as the first argument to coro.begin, coro.alloc and coro.free intrinsics.
- // Note: llvm.coro.id returns a token that cannot be directly expressed in a
- // builtin.
- llvm::CallInst *CoroId = nullptr;
-
- // Stores the llvm.coro.begin emitted in the function so that we can replace
- // all coro.frame intrinsics with direct SSA value of coro.begin that returns
- // the address of the coroutine frame of the current coroutine.
- llvm::CallInst *CoroBegin = nullptr;
-
- // Stores the last emitted coro.free for the deallocate expressions, we use it
- // to wrap dealloc code with if(auto mem = coro.free) dealloc(mem).
- llvm::CallInst *LastCoroFree = nullptr;
-
- // If coro.id came from the builtin, remember the expression to give better
- // diagnostic. If CoroIdExpr is nullptr, the coro.id was created by
- // EmitCoroutineBody.
- CallExpr const *CoroIdExpr = nullptr;
-};
-
-// Defining these here allows to keep CGCoroData private to this file.
-clang::CodeGen::CodeGenFunction::CGCoroInfo::CGCoroInfo() {}
-CodeGenFunction::CGCoroInfo::~CGCoroInfo() {}
-
-static void createCoroData(CodeGenFunction &CGF,
- CodeGenFunction::CGCoroInfo &CurCoro,
- llvm::CallInst *CoroId,
- CallExpr const *CoroIdExpr = nullptr) {
- if (CurCoro.Data) {
- if (CurCoro.Data->CoroIdExpr)
- CGF.CGM.Error(CoroIdExpr->getBeginLoc(),
- "only one __builtin_coro_id can be used in a function");
- else if (CoroIdExpr)
- CGF.CGM.Error(CoroIdExpr->getBeginLoc(),
- "__builtin_coro_id shall not be used in a C++ coroutine");
- else
- llvm_unreachable("EmitCoroutineBodyStatement called twice?");
-
- return;
- }
-
- CurCoro.Data = std::unique_ptr<CGCoroData>(new CGCoroData);
- CurCoro.Data->CoroId = CoroId;
- CurCoro.Data->CoroIdExpr = CoroIdExpr;
-}
-
-// Synthesize a pretty name for a suspend point.
-static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) {
- unsigned No = 0;
- switch (Kind) {
- case AwaitKind::Init:
- case AwaitKind::Final:
- break;
- case AwaitKind::Normal:
- No = ++Coro.AwaitNum;
- break;
- case AwaitKind::Yield:
- No = ++Coro.YieldNum;
- break;
- }
- SmallString<32> Prefix(AwaitKindStr[static_cast<unsigned>(Kind)]);
- if (No > 1) {
- Twine(No).toVector(Prefix);
- }
- return Prefix;
-}
-
-static bool memberCallExpressionCanThrow(const Expr *E) {
- if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
- if (const auto *Proto =
- CE->getMethodDecl()->getType()->getAs<FunctionProtoType>())
- if (isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
- Proto->canThrow() == CT_Cannot)
- return false;
- return true;
-}
-
-// Emit suspend expression which roughly looks like:
-//
-// auto && x = CommonExpr();
-// if (!x.await_ready()) {
-// llvm_coro_save();
-// x.await_suspend(...); (*)
-// llvm_coro_suspend(); (**)
-// }
-// x.await_resume();
-//
-// where the result of the entire expression is the result of x.await_resume()
-//
-// (*) If x.await_suspend return type is bool, it allows to veto a suspend:
-// if (x.await_suspend(...))
-// llvm_coro_suspend();
-//
-// (**) llvm_coro_suspend() encodes three possible continuations as
-// a switch instruction:
-//
-// %where-to = call i8 @llvm.coro.suspend(...)
-// switch i8 %where-to, label %coro.ret [ ; jump to epilogue to suspend
-// i8 0, label %yield.ready ; go here when resumed
-// i8 1, label %yield.cleanup ; go here when destroyed
-// ]
-//
-// See llvm's docs/Coroutines.rst for more details.
-//
-namespace {
- struct LValueOrRValue {
- LValue LV;
- RValue RV;
- };
-}
-static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
- CoroutineSuspendExpr const &S,
- AwaitKind Kind, AggValueSlot aggSlot,
- bool ignoreResult, bool forLValue) {
- auto *E = S.getCommonExpr();
-
- auto Binder =
- CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E);
- auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); });
-
- auto Prefix = buildSuspendPrefixStr(Coro, Kind);
- BasicBlock *ReadyBlock = CGF.createBasicBlock(Prefix + Twine(".ready"));
- BasicBlock *SuspendBlock = CGF.createBasicBlock(Prefix + Twine(".suspend"));
- BasicBlock *CleanupBlock = CGF.createBasicBlock(Prefix + Twine(".cleanup"));
-
- // If expression is ready, no need to suspend.
- CGF.EmitBranchOnBoolExpr(S.getReadyExpr(), ReadyBlock, SuspendBlock, 0);
-
- // Otherwise, emit suspend logic.
- CGF.EmitBlock(SuspendBlock);
-
- auto &Builder = CGF.Builder;
- llvm::Function *CoroSave = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_save);
- auto *NullPtr = llvm::ConstantPointerNull::get(CGF.CGM.Int8PtrTy);
- auto *SaveCall = Builder.CreateCall(CoroSave, {NullPtr});
-
- auto *SuspendRet = CGF.EmitScalarExpr(S.getSuspendExpr());
- if (SuspendRet != nullptr && SuspendRet->getType()->isIntegerTy(1)) {
- // Veto suspension if requested by bool returning await_suspend.
- BasicBlock *RealSuspendBlock =
- CGF.createBasicBlock(Prefix + Twine(".suspend.bool"));
- CGF.Builder.CreateCondBr(SuspendRet, RealSuspendBlock, ReadyBlock);
- SuspendBlock = RealSuspendBlock;
- CGF.EmitBlock(RealSuspendBlock);
- }
-
- // Emit the suspend point.
- const bool IsFinalSuspend = (Kind == AwaitKind::Final);
- llvm::Function *CoroSuspend =
- CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_suspend);
- auto *SuspendResult = Builder.CreateCall(
- CoroSuspend, {SaveCall, Builder.getInt1(IsFinalSuspend)});
-
- // Create a switch capturing three possible continuations.
- auto *Switch = Builder.CreateSwitch(SuspendResult, Coro.SuspendBB, 2);
- Switch->addCase(Builder.getInt8(0), ReadyBlock);
- Switch->addCase(Builder.getInt8(1), CleanupBlock);
-
- // Emit cleanup for this suspend point.
- CGF.EmitBlock(CleanupBlock);
- CGF.EmitBranchThroughCleanup(Coro.CleanupJD);
-
- // Emit await_resume expression.
- CGF.EmitBlock(ReadyBlock);
-
- // Exception handling requires additional IR. If the 'await_resume' function
- // is marked as 'noexcept', we avoid generating this additional IR.
- CXXTryStmt *TryStmt = nullptr;
- if (Coro.ExceptionHandler && Kind == AwaitKind::Init &&
- memberCallExpressionCanThrow(S.getResumeExpr())) {
- Coro.ResumeEHVar =
- CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh"));
- Builder.CreateFlagStore(true, Coro.ResumeEHVar);
-
- auto Loc = S.getResumeExpr()->getExprLoc();
- auto *Catch = new (CGF.getContext())
- CXXCatchStmt(Loc, /*exDecl=*/nullptr, Coro.ExceptionHandler);
- auto *TryBody =
- CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(), Loc, Loc);
- TryStmt = CXXTryStmt::Create(CGF.getContext(), Loc, TryBody, Catch);
- CGF.EnterCXXTryStmt(*TryStmt);
- }
-
- LValueOrRValue Res;
- if (forLValue)
- Res.LV = CGF.EmitLValue(S.getResumeExpr());
- else
- Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
-
- if (TryStmt) {
- Builder.CreateFlagStore(false, Coro.ResumeEHVar);
- CGF.ExitCXXTryStmt(*TryStmt);
- }
-
- return Res;
-}
-
-RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E,
- AggValueSlot aggSlot,
- bool ignoreResult) {
- return emitSuspendExpression(*this, *CurCoro.Data, E,
- CurCoro.Data->CurrentAwaitKind, aggSlot,
- ignoreResult, /*forLValue*/false).RV;
-}
-RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E,
- AggValueSlot aggSlot,
- bool ignoreResult) {
- return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield,
- aggSlot, ignoreResult, /*forLValue*/false).RV;
-}
-
-void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
- ++CurCoro.Data->CoreturnCount;
- const Expr *RV = S.getOperand();
- if (RV && RV->getType()->isVoidType()) {
- // Make sure to evaluate the expression of a co_return with a void
- // expression for side effects.
- RunCleanupsScope cleanupScope(*this);
- EmitIgnoredExpr(RV);
- }
- EmitStmt(S.getPromiseCall());
- EmitBranchThroughCleanup(CurCoro.Data->FinalJD);
-}
-
-
-#ifndef NDEBUG
-static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx,
- const CoroutineSuspendExpr *E) {
- const auto *RE = E->getResumeExpr();
- // Is it possible for RE to be a CXXBindTemporaryExpr wrapping
- // a MemberCallExpr?
- assert(isa<CallExpr>(RE) && "unexpected suspend expression type");
- return cast<CallExpr>(RE)->getCallReturnType(Ctx);
-}
-#endif
-
-LValue
-CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) {
- assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
- "Can't have a scalar return unless the return type is a "
- "reference type!");
- return emitSuspendExpression(*this, *CurCoro.Data, *E,
- CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(),
- /*ignoreResult*/false, /*forLValue*/true).LV;
-}
-
-LValue
-CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) {
- assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
- "Can't have a scalar return unless the return type is a "
- "reference type!");
- return emitSuspendExpression(*this, *CurCoro.Data, *E,
- AwaitKind::Yield, AggValueSlot::ignored(),
- /*ignoreResult*/false, /*forLValue*/true).LV;
-}
-
-// Hunts for the parameter reference in the parameter copy/move declaration.
-namespace {
-struct GetParamRef : public StmtVisitor<GetParamRef> {
-public:
- DeclRefExpr *Expr = nullptr;
- GetParamRef() {}
- void VisitDeclRefExpr(DeclRefExpr *E) {
- assert(Expr == nullptr && "multilple declref in param move");
- Expr = E;
- }
- void VisitStmt(Stmt *S) {
- for (auto *C : S->children()) {
- if (C)
- Visit(C);
- }
- }
-};
-}
-
-// This class replaces references to parameters to their copies by changing
-// the addresses in CGF.LocalDeclMap and restoring back the original values in
-// its destructor.
-
-namespace {
- struct ParamReferenceReplacerRAII {
- CodeGenFunction::DeclMapTy SavedLocals;
- CodeGenFunction::DeclMapTy& LocalDeclMap;
-
- ParamReferenceReplacerRAII(CodeGenFunction::DeclMapTy &LocalDeclMap)
- : LocalDeclMap(LocalDeclMap) {}
-
- void addCopy(DeclStmt const *PM) {
- // Figure out what param it refers to.
-
- assert(PM->isSingleDecl());
- VarDecl const*VD = static_cast<VarDecl const*>(PM->getSingleDecl());
- Expr const *InitExpr = VD->getInit();
- GetParamRef Visitor;
- Visitor.Visit(const_cast<Expr*>(InitExpr));
- assert(Visitor.Expr);
- DeclRefExpr *DREOrig = Visitor.Expr;
- auto *PD = DREOrig->getDecl();
-
- auto it = LocalDeclMap.find(PD);
- assert(it != LocalDeclMap.end() && "parameter is not found");
- SavedLocals.insert({ PD, it->second });
-
- auto copyIt = LocalDeclMap.find(VD);
- assert(copyIt != LocalDeclMap.end() && "parameter copy is not found");
- it->second = copyIt->getSecond();
- }
-
- ~ParamReferenceReplacerRAII() {
- for (auto&& SavedLocal : SavedLocals) {
- LocalDeclMap.insert({SavedLocal.first, SavedLocal.second});
- }
- }
- };
-}
-
-// For WinEH exception representation backend needs to know what funclet coro.end
-// belongs to. That information is passed in a funclet bundle.
-static SmallVector<llvm::OperandBundleDef, 1>
-getBundlesForCoroEnd(CodeGenFunction &CGF) {
- SmallVector<llvm::OperandBundleDef, 1> BundleList;
-
- if (llvm::Instruction *EHPad = CGF.CurrentFuncletPad)
- BundleList.emplace_back("funclet", EHPad);
-
- return BundleList;
-}
-
-namespace {
-// We will insert coro.end to cut any of the destructors for objects that
-// do not need to be destroyed once the coroutine is resumed.
-// See llvm/docs/Coroutines.rst for more details about coro.end.
-struct CallCoroEnd final : public EHScopeStack::Cleanup {
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- auto &CGM = CGF.CGM;
- auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
- llvm::Function *CoroEndFn = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
- // See if we have a funclet bundle to associate coro.end with. (WinEH)
- auto Bundles = getBundlesForCoroEnd(CGF);
- auto *CoroEnd = CGF.Builder.CreateCall(
- CoroEndFn, {NullPtr, CGF.Builder.getTrue()}, Bundles);
- if (Bundles.empty()) {
- // Otherwise, (landingpad model), create a conditional branch that leads
- // either to a cleanup block or a block with EH resume instruction.
- auto *ResumeBB = CGF.getEHResumeBlock(/*cleanup=*/true);
- auto *CleanupContBB = CGF.createBasicBlock("cleanup.cont");
- CGF.Builder.CreateCondBr(CoroEnd, ResumeBB, CleanupContBB);
- CGF.EmitBlock(CleanupContBB);
- }
- }
-};
-}
-
-namespace {
-// Make sure to call coro.delete on scope exit.
-struct CallCoroDelete final : public EHScopeStack::Cleanup {
- Stmt *Deallocate;
-
- // Emit "if (coro.free(CoroId, CoroBegin)) Deallocate;"
-
- // Note: That deallocation will be emitted twice: once for a normal exit and
- // once for exceptional exit. This usage is safe because Deallocate does not
- // contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr()
- // builds a single call to a deallocation function which is safe to emit
- // multiple times.
- void Emit(CodeGenFunction &CGF, Flags) override {
- // Remember the current point, as we are going to emit deallocation code
- // first to get to coro.free instruction that is an argument to a delete
- // call.
- BasicBlock *SaveInsertBlock = CGF.Builder.GetInsertBlock();
-
- auto *FreeBB = CGF.createBasicBlock("coro.free");
- CGF.EmitBlock(FreeBB);
- CGF.EmitStmt(Deallocate);
-
- auto *AfterFreeBB = CGF.createBasicBlock("after.coro.free");
- CGF.EmitBlock(AfterFreeBB);
-
- // We should have captured coro.free from the emission of deallocate.
- auto *CoroFree = CGF.CurCoro.Data->LastCoroFree;
- if (!CoroFree) {
- CGF.CGM.Error(Deallocate->getBeginLoc(),
- "Deallocation expressoin does not refer to coro.free");
- return;
- }
-
- // Get back to the block we were originally and move coro.free there.
- auto *InsertPt = SaveInsertBlock->getTerminator();
- CoroFree->moveBefore(InsertPt);
- CGF.Builder.SetInsertPoint(InsertPt);
-
- // Add if (auto *mem = coro.free) Deallocate;
- auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
- auto *Cond = CGF.Builder.CreateICmpNE(CoroFree, NullPtr);
- CGF.Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB);
-
- // No longer need old terminator.
- InsertPt->eraseFromParent();
- CGF.Builder.SetInsertPoint(AfterFreeBB);
- }
- explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
-};
-}
-
-namespace {
-struct GetReturnObjectManager {
- CodeGenFunction &CGF;
- CGBuilderTy &Builder;
- const CoroutineBodyStmt &S;
-
- Address GroActiveFlag;
- CodeGenFunction::AutoVarEmission GroEmission;
-
- GetReturnObjectManager(CodeGenFunction &CGF, const CoroutineBodyStmt &S)
- : CGF(CGF), Builder(CGF.Builder), S(S), GroActiveFlag(Address::invalid()),
- GroEmission(CodeGenFunction::AutoVarEmission::invalid()) {}
-
- // The gro variable has to outlive coroutine frame and coroutine promise, but,
- // it can only be initialized after coroutine promise was created, thus, we
- // split its emission in two parts. EmitGroAlloca emits an alloca and sets up
- // cleanups. Later when coroutine promise is available we initialize the gro
- // and sets the flag that the cleanup is now active.
-
- void EmitGroAlloca() {
- auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl());
- if (!GroDeclStmt) {
- // If get_return_object returns void, no need to do an alloca.
- return;
- }
-
- auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl());
-
- // Set GRO flag that it is not initialized yet
- GroActiveFlag =
- CGF.CreateTempAlloca(Builder.getInt1Ty(), CharUnits::One(), "gro.active");
- Builder.CreateStore(Builder.getFalse(), GroActiveFlag);
-
- GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl);
-
- // Remember the top of EHStack before emitting the cleanup.
- auto old_top = CGF.EHStack.stable_begin();
- CGF.EmitAutoVarCleanups(GroEmission);
- auto top = CGF.EHStack.stable_begin();
-
- // Make the cleanup conditional on gro.active
- for (auto b = CGF.EHStack.find(top), e = CGF.EHStack.find(old_top);
- b != e; b++) {
- if (auto *Cleanup = dyn_cast<EHCleanupScope>(&*b)) {
- assert(!Cleanup->hasActiveFlag() && "cleanup already has active flag?");
- Cleanup->setActiveFlag(GroActiveFlag);
- Cleanup->setTestFlagInEHCleanup();
- Cleanup->setTestFlagInNormalCleanup();
- }
- }
- }
-
- void EmitGroInit() {
- if (!GroActiveFlag.isValid()) {
- // No Gro variable was allocated. Simply emit the call to
- // get_return_object.
- CGF.EmitStmt(S.getResultDecl());
- return;
- }
-
- CGF.EmitAutoVarInit(GroEmission);
- Builder.CreateStore(Builder.getTrue(), GroActiveFlag);
- }
-};
-}
-
-static void emitBodyAndFallthrough(CodeGenFunction &CGF,
- const CoroutineBodyStmt &S, Stmt *Body) {
- CGF.EmitStmt(Body);
- const bool CanFallthrough = CGF.Builder.GetInsertBlock();
- if (CanFallthrough)
- if (Stmt *OnFallthrough = S.getFallthroughHandler())
- CGF.EmitStmt(OnFallthrough);
-}
-
-void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
- auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
- auto &TI = CGM.getContext().getTargetInfo();
- unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth();
-
- auto *EntryBB = Builder.GetInsertBlock();
- auto *AllocBB = createBasicBlock("coro.alloc");
- auto *InitBB = createBasicBlock("coro.init");
- auto *FinalBB = createBasicBlock("coro.final");
- auto *RetBB = createBasicBlock("coro.ret");
-
- auto *CoroId = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::coro_id),
- {Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr});
- createCoroData(*this, CurCoro, CoroId);
- CurCoro.Data->SuspendBB = RetBB;
-
- // Backend is allowed to elide memory allocations, to help it, emit
- // auto mem = coro.alloc() ? 0 : ... allocation code ...;
- auto *CoroAlloc = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId});
-
- Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
-
- EmitBlock(AllocBB);
- auto *AllocateCall = EmitScalarExpr(S.getAllocate());
- auto *AllocOrInvokeContBB = Builder.GetInsertBlock();
-
- // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
- if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
- auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure");
-
- // See if allocation was successful.
- auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy);
- auto *Cond = Builder.CreateICmpNE(AllocateCall, NullPtr);
- Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB);
-
- // If not, return OnAllocFailure object.
- EmitBlock(RetOnFailureBB);
- EmitStmt(RetOnAllocFailure);
- }
- else {
- Builder.CreateBr(InitBB);
- }
-
- EmitBlock(InitBB);
-
- // Pass the result of the allocation to coro.begin.
- auto *Phi = Builder.CreatePHI(VoidPtrTy, 2);
- Phi->addIncoming(NullPtr, EntryBB);
- Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
- auto *CoroBegin = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi});
- CurCoro.Data->CoroBegin = CoroBegin;
-
- GetReturnObjectManager GroManager(*this, S);
- GroManager.EmitGroAlloca();
-
- CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB);
- {
- ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap);
- CodeGenFunction::RunCleanupsScope ResumeScope(*this);
- EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate());
-
- // Create parameter copies. We do it before creating a promise, since an
- // evolution of coroutine TS may allow promise constructor to observe
- // parameter copies.
- for (auto *PM : S.getParamMoves()) {
- EmitStmt(PM);
- ParamReplacer.addCopy(cast<DeclStmt>(PM));
- // TODO: if(CoroParam(...)) need to surround ctor and dtor
- // for the copy, so that llvm can elide it if the copy is
- // not needed.
- }
-
- EmitStmt(S.getPromiseDeclStmt());
-
- Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl());
- auto *PromiseAddrVoidPtr =
- new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId);
- // Update CoroId to refer to the promise. We could not do it earlier because
- // promise local variable was not emitted yet.
- CoroId->setArgOperand(1, PromiseAddrVoidPtr);
-
- // Now we have the promise, initialize the GRO
- GroManager.EmitGroInit();
-
- EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
-
- CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
- CurCoro.Data->ExceptionHandler = S.getExceptionHandler();
- EmitStmt(S.getInitSuspendStmt());
- CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
-
- CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
-
- if (CurCoro.Data->ExceptionHandler) {
- // If we generated IR to record whether an exception was thrown from
- // 'await_resume', then use that IR to determine whether the coroutine
- // body should be skipped.
- // If we didn't generate the IR (perhaps because 'await_resume' was marked
- // as 'noexcept'), then we skip this check.
- BasicBlock *ContBB = nullptr;
- if (CurCoro.Data->ResumeEHVar) {
- BasicBlock *BodyBB = createBasicBlock("coro.resumed.body");
- ContBB = createBasicBlock("coro.resumed.cont");
- Value *SkipBody = Builder.CreateFlagLoad(CurCoro.Data->ResumeEHVar,
- "coro.resumed.eh");
- Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
- EmitBlock(BodyBB);
- }
-
- auto Loc = S.getBeginLoc();
- CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr,
- CurCoro.Data->ExceptionHandler);
- auto *TryStmt =
- CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch);
-
- EnterCXXTryStmt(*TryStmt);
- emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
- ExitCXXTryStmt(*TryStmt);
-
- if (ContBB)
- EmitBlock(ContBB);
- }
- else {
- emitBodyAndFallthrough(*this, S, S.getBody());
- }
-
- // See if we need to generate final suspend.
- const bool CanFallthrough = Builder.GetInsertBlock();
- const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
- if (CanFallthrough || HasCoreturns) {
- EmitBlock(FinalBB);
- CurCoro.Data->CurrentAwaitKind = AwaitKind::Final;
- EmitStmt(S.getFinalSuspendStmt());
- } else {
- // We don't need FinalBB. Emit it to make sure the block is deleted.
- EmitBlock(FinalBB, /*IsFinished=*/true);
- }
- }
-
- EmitBlock(RetBB);
- // Emit coro.end before getReturnStmt (and parameter destructors), since
- // resume and destroy parts of the coroutine should not include them.
- llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
- Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()});
-
- if (Stmt *Ret = S.getReturnStmt())
- EmitStmt(Ret);
-}
-
-// Emit coroutine intrinsic and patch up arguments of the token type.
-RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
- unsigned int IID) {
- SmallVector<llvm::Value *, 8> Args;
- switch (IID) {
- default:
- break;
- // The coro.frame builtin is replaced with an SSA value of the coro.begin
- // intrinsic.
- case llvm::Intrinsic::coro_frame: {
- if (CurCoro.Data && CurCoro.Data->CoroBegin) {
- return RValue::get(CurCoro.Data->CoroBegin);
- }
- CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_begin "
- "has been used earlier in this function");
- auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
- return RValue::get(NullPtr);
- }
- // The following three intrinsics take a token parameter referring to a token
- // returned by earlier call to @llvm.coro.id. Since we cannot represent it in
- // builtins, we patch it up here.
- case llvm::Intrinsic::coro_alloc:
- case llvm::Intrinsic::coro_begin:
- case llvm::Intrinsic::coro_free: {
- if (CurCoro.Data && CurCoro.Data->CoroId) {
- Args.push_back(CurCoro.Data->CoroId);
- break;
- }
- CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_id has"
- " been used earlier in this function");
- // Fallthrough to the next case to add TokenNone as the first argument.
- LLVM_FALLTHROUGH;
- }
- // @llvm.coro.suspend takes a token parameter. Add token 'none' as the first
- // argument.
- case llvm::Intrinsic::coro_suspend:
- Args.push_back(llvm::ConstantTokenNone::get(getLLVMContext()));
- break;
- }
- for (auto &Arg : E->arguments())
- Args.push_back(EmitScalarExpr(Arg));
-
- llvm::Value *F = CGM.getIntrinsic(IID);
- llvm::CallInst *Call = Builder.CreateCall(F, Args);
-
- // Note: The following code is to enable to emit coro.id and coro.begin by
- // hand to experiment with coroutines in C.
- // If we see @llvm.coro.id remember it in the CoroData. We will update
- // coro.alloc, coro.begin and coro.free intrinsics to refer to it.
- if (IID == llvm::Intrinsic::coro_id) {
- createCoroData(*this, CurCoro, Call, E);
- }
- else if (IID == llvm::Intrinsic::coro_begin) {
- if (CurCoro.Data)
- CurCoro.Data->CoroBegin = Call;
- }
- else if (IID == llvm::Intrinsic::coro_free) {
- // Remember the last coro_free as we need it to build the conditional
- // deletion of the coroutine frame.
- if (CurCoro.Data)
- CurCoro.Data->LastCoroFree = Call;
- }
- return RValue::get(Call);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
deleted file mode 100644
index ad1a9157a12..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
+++ /dev/null
@@ -1,4497 +0,0 @@
-//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This coordinates the debug information generation while generating code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGDebugInfo.h"
-#include "CGBlocks.h"
-#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "ConstantEmitter.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclFriend.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/Version.h"
-#include "clang/Frontend/FrontendOptions.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/ModuleMap.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Metadata.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MD5.h"
-#include "llvm/Support/Path.h"
-using namespace clang;
-using namespace clang::CodeGen;
-
-static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) {
- auto TI = Ctx.getTypeInfo(Ty);
- return TI.AlignIsRequired ? TI.Align : 0;
-}
-
-static uint32_t getTypeAlignIfRequired(QualType Ty, const ASTContext &Ctx) {
- return getTypeAlignIfRequired(Ty.getTypePtr(), Ctx);
-}
-
-static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
- return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
-}
-
-CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
- : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
- DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
- DBuilder(CGM.getModule()) {
- for (const auto &KV : CGM.getCodeGenOpts().DebugPrefixMap)
- DebugPrefixMap[KV.first] = KV.second;
- CreateCompileUnit();
-}
-
-CGDebugInfo::~CGDebugInfo() {
- assert(LexicalBlockStack.empty() &&
- "Region stack mismatch, stack not empty!");
-}
-
-ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
- SourceLocation TemporaryLocation)
- : CGF(&CGF) {
- init(TemporaryLocation);
-}
-
-ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
- bool DefaultToEmpty,
- SourceLocation TemporaryLocation)
- : CGF(&CGF) {
- init(TemporaryLocation, DefaultToEmpty);
-}
-
-void ApplyDebugLocation::init(SourceLocation TemporaryLocation,
- bool DefaultToEmpty) {
- auto *DI = CGF->getDebugInfo();
- if (!DI) {
- CGF = nullptr;
- return;
- }
-
- OriginalLocation = CGF->Builder.getCurrentDebugLocation();
-
- if (OriginalLocation && !DI->CGM.getExpressionLocationsEnabled())
- return;
-
- if (TemporaryLocation.isValid()) {
- DI->EmitLocation(CGF->Builder, TemporaryLocation);
- return;
- }
-
- if (DefaultToEmpty) {
- CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc());
- return;
- }
-
- // Construct a location that has a valid scope, but no line info.
- assert(!DI->LexicalBlockStack.empty());
- CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
- 0, 0, DI->LexicalBlockStack.back(), DI->getInlinedAt()));
-}
-
-ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E)
- : CGF(&CGF) {
- init(E->getExprLoc());
-}
-
-ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc)
- : CGF(&CGF) {
- if (!CGF.getDebugInfo()) {
- this->CGF = nullptr;
- return;
- }
- OriginalLocation = CGF.Builder.getCurrentDebugLocation();
- if (Loc)
- CGF.Builder.SetCurrentDebugLocation(std::move(Loc));
-}
-
-ApplyDebugLocation::~ApplyDebugLocation() {
- // Query CGF so the location isn't overwritten when location updates are
- // temporarily disabled (for C++ default function arguments)
- if (CGF)
- CGF->Builder.SetCurrentDebugLocation(std::move(OriginalLocation));
-}
-
-ApplyInlineDebugLocation::ApplyInlineDebugLocation(CodeGenFunction &CGF,
- GlobalDecl InlinedFn)
- : CGF(&CGF) {
- if (!CGF.getDebugInfo()) {
- this->CGF = nullptr;
- return;
- }
- auto &DI = *CGF.getDebugInfo();
- SavedLocation = DI.getLocation();
- assert((DI.getInlinedAt() ==
- CGF.Builder.getCurrentDebugLocation()->getInlinedAt()) &&
- "CGDebugInfo and IRBuilder are out of sync");
-
- DI.EmitInlineFunctionStart(CGF.Builder, InlinedFn);
-}
-
-ApplyInlineDebugLocation::~ApplyInlineDebugLocation() {
- if (!CGF)
- return;
- auto &DI = *CGF->getDebugInfo();
- DI.EmitInlineFunctionEnd(CGF->Builder);
- DI.EmitLocation(CGF->Builder, SavedLocation);
-}
-
-void CGDebugInfo::setLocation(SourceLocation Loc) {
- // If the new location isn't valid return.
- if (Loc.isInvalid())
- return;
-
- CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc);
-
- // If we've changed files in the middle of a lexical scope go ahead
- // and create a new lexical scope with file node if it's different
- // from the one in the scope.
- if (LexicalBlockStack.empty())
- return;
-
- SourceManager &SM = CGM.getContext().getSourceManager();
- auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
- PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
- if (PCLoc.isInvalid() || Scope->getFile() == getOrCreateFile(CurLoc))
- return;
-
- if (auto *LBF = dyn_cast<llvm::DILexicalBlockFile>(Scope)) {
- LexicalBlockStack.pop_back();
- LexicalBlockStack.emplace_back(DBuilder.createLexicalBlockFile(
- LBF->getScope(), getOrCreateFile(CurLoc)));
- } else if (isa<llvm::DILexicalBlock>(Scope) ||
- isa<llvm::DISubprogram>(Scope)) {
- LexicalBlockStack.pop_back();
- LexicalBlockStack.emplace_back(
- DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc)));
- }
-}
-
-llvm::DIScope *CGDebugInfo::getDeclContextDescriptor(const Decl *D) {
- llvm::DIScope *Mod = getParentModuleOrNull(D);
- return getContextDescriptor(cast<Decl>(D->getDeclContext()),
- Mod ? Mod : TheCU);
-}
-
-llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context,
- llvm::DIScope *Default) {
- if (!Context)
- return Default;
-
- auto I = RegionMap.find(Context);
- if (I != RegionMap.end()) {
- llvm::Metadata *V = I->second;
- return dyn_cast_or_null<llvm::DIScope>(V);
- }
-
- // Check namespace.
- if (const auto *NSDecl = dyn_cast<NamespaceDecl>(Context))
- return getOrCreateNamespace(NSDecl);
-
- if (const auto *RDecl = dyn_cast<RecordDecl>(Context))
- if (!RDecl->isDependentType())
- return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl),
- TheCU->getFile());
- return Default;
-}
-
-PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
- PrintingPolicy PP = CGM.getContext().getPrintingPolicy();
-
- // If we're emitting codeview, it's important to try to match MSVC's naming so
- // that visualizers written for MSVC will trigger for our class names. In
- // particular, we can't have spaces between arguments of standard templates
- // like basic_string and vector.
- if (CGM.getCodeGenOpts().EmitCodeView)
- PP.MSVCFormatting = true;
-
- // Apply -fdebug-prefix-map.
- PP.RemapFilePaths = true;
- PP.remapPath = [this](StringRef Path) { return remapDIPath(Path); };
- return PP;
-}
-
-StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
- assert(FD && "Invalid FunctionDecl!");
- IdentifierInfo *FII = FD->getIdentifier();
- FunctionTemplateSpecializationInfo *Info =
- FD->getTemplateSpecializationInfo();
-
- // Emit the unqualified name in normal operation. LLVM and the debugger can
- // compute the fully qualified name from the scope chain. If we're only
- // emitting line table info, there won't be any scope chains, so emit the
- // fully qualified name here so that stack traces are more accurate.
- // FIXME: Do this when emitting DWARF as well as when emitting CodeView after
- // evaluating the size impact.
- bool UseQualifiedName = DebugKind == codegenoptions::DebugLineTablesOnly &&
- CGM.getCodeGenOpts().EmitCodeView;
-
- if (!Info && FII && !UseQualifiedName)
- return FII->getName();
-
- SmallString<128> NS;
- llvm::raw_svector_ostream OS(NS);
- if (!UseQualifiedName)
- FD->printName(OS);
- else
- FD->printQualifiedName(OS, getPrintingPolicy());
-
- // Add any template specialization args.
- if (Info) {
- const TemplateArgumentList *TArgs = Info->TemplateArguments;
- printTemplateArgumentList(OS, TArgs->asArray(), getPrintingPolicy());
- }
-
- // Copy this name on the side and use its reference.
- return internString(OS.str());
-}
-
-StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
- SmallString<256> MethodName;
- llvm::raw_svector_ostream OS(MethodName);
- OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
- const DeclContext *DC = OMD->getDeclContext();
- if (const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) {
- OS << OID->getName();
- } else if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) {
- OS << OID->getName();
- } else if (const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) {
- if (OC->IsClassExtension()) {
- OS << OC->getClassInterface()->getName();
- } else {
- OS << OC->getIdentifier()->getNameStart() << '('
- << OC->getIdentifier()->getNameStart() << ')';
- }
- } else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
- OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')';
- } else if (isa<ObjCProtocolDecl>(DC)) {
- // We can extract the type of the class from the self pointer.
- if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
- QualType ClassTy =
- cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
- ClassTy.print(OS, PrintingPolicy(LangOptions()));
- }
- }
- OS << ' ' << OMD->getSelector().getAsString() << ']';
-
- return internString(OS.str());
-}
-
-StringRef CGDebugInfo::getSelectorName(Selector S) {
- return internString(S.getAsString());
-}
-
-StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
- if (isa<ClassTemplateSpecializationDecl>(RD)) {
- SmallString<128> Name;
- llvm::raw_svector_ostream OS(Name);
- RD->getNameForDiagnostic(OS, getPrintingPolicy(),
- /*Qualified*/ false);
-
- // Copy this name on the side and use its reference.
- return internString(Name);
- }
-
- // quick optimization to avoid having to intern strings that are already
- // stored reliably elsewhere
- if (const IdentifierInfo *II = RD->getIdentifier())
- return II->getName();
-
- // The CodeView printer in LLVM wants to see the names of unnamed types: it is
- // used to reconstruct the fully qualified type names.
- if (CGM.getCodeGenOpts().EmitCodeView) {
- if (const TypedefNameDecl *D = RD->getTypedefNameForAnonDecl()) {
- assert(RD->getDeclContext() == D->getDeclContext() &&
- "Typedef should not be in another decl context!");
- assert(D->getDeclName().getAsIdentifierInfo() &&
- "Typedef was not named!");
- return D->getDeclName().getAsIdentifierInfo()->getName();
- }
-
- if (CGM.getLangOpts().CPlusPlus) {
- StringRef Name;
-
- ASTContext &Context = CGM.getContext();
- if (const DeclaratorDecl *DD = Context.getDeclaratorForUnnamedTagDecl(RD))
- // Anonymous types without a name for linkage purposes have their
- // declarator mangled in if they have one.
- Name = DD->getName();
- else if (const TypedefNameDecl *TND =
- Context.getTypedefNameForUnnamedTagDecl(RD))
- // Anonymous types without a name for linkage purposes have their
- // associate typedef mangled in if they have one.
- Name = TND->getName();
-
- if (!Name.empty()) {
- SmallString<256> UnnamedType("<unnamed-type-");
- UnnamedType += Name;
- UnnamedType += '>';
- return internString(UnnamedType);
- }
- }
- }
-
- return StringRef();
-}
-
-Optional<llvm::DIFile::ChecksumKind>
-CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const {
- Checksum.clear();
-
- if (!CGM.getCodeGenOpts().EmitCodeView &&
- CGM.getCodeGenOpts().DwarfVersion < 5)
- return None;
-
- SourceManager &SM = CGM.getContext().getSourceManager();
- bool Invalid;
- llvm::MemoryBuffer *MemBuffer = SM.getBuffer(FID, &Invalid);
- if (Invalid)
- return None;
-
- llvm::MD5 Hash;
- llvm::MD5::MD5Result Result;
-
- Hash.update(MemBuffer->getBuffer());
- Hash.final(Result);
-
- Hash.stringifyResult(Result, Checksum);
- return llvm::DIFile::CSK_MD5;
-}
-
-Optional<StringRef> CGDebugInfo::getSource(const SourceManager &SM,
- FileID FID) {
- if (!CGM.getCodeGenOpts().EmbedSource)
- return None;
-
- bool SourceInvalid = false;
- StringRef Source = SM.getBufferData(FID, &SourceInvalid);
-
- if (SourceInvalid)
- return None;
-
- return Source;
-}
-
-llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
- if (!Loc.isValid())
- // If Location is not valid then use main input file.
- return TheCU->getFile();
-
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
-
- StringRef FileName = PLoc.getFilename();
- if (PLoc.isInvalid() || FileName.empty())
- // If the location is not valid then use main input file.
- return TheCU->getFile();
-
- // Cache the results.
- auto It = DIFileCache.find(FileName.data());
- if (It != DIFileCache.end()) {
- // Verify that the information still exists.
- if (llvm::Metadata *V = It->second)
- return cast<llvm::DIFile>(V);
- }
-
- SmallString<32> Checksum;
- Optional<llvm::DIFile::ChecksumKind> CSKind =
- computeChecksum(SM.getFileID(Loc), Checksum);
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
- if (CSKind)
- CSInfo.emplace(*CSKind, Checksum);
- return createFile(FileName, CSInfo, getSource(SM, SM.getFileID(Loc)));
-}
-
-llvm::DIFile *
-CGDebugInfo::createFile(StringRef FileName,
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo,
- Optional<StringRef> Source) {
- StringRef Dir;
- StringRef File;
- std::string RemappedFile = remapDIPath(FileName);
- std::string CurDir = remapDIPath(getCurrentDirname());
- SmallString<128> DirBuf;
- SmallString<128> FileBuf;
- if (llvm::sys::path::is_absolute(RemappedFile)) {
- // Strip the common prefix (if it is more than just "/") from current
- // directory and FileName for a more space-efficient encoding.
- auto FileIt = llvm::sys::path::begin(RemappedFile);
- auto FileE = llvm::sys::path::end(RemappedFile);
- auto CurDirIt = llvm::sys::path::begin(CurDir);
- auto CurDirE = llvm::sys::path::end(CurDir);
- for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt)
- llvm::sys::path::append(DirBuf, *CurDirIt);
- if (std::distance(llvm::sys::path::begin(CurDir), CurDirIt) == 1) {
- // The common prefix only the root; stripping it would cause
- // LLVM diagnostic locations to be more confusing.
- Dir = {};
- File = RemappedFile;
- } else {
- for (; FileIt != FileE; ++FileIt)
- llvm::sys::path::append(FileBuf, *FileIt);
- Dir = DirBuf;
- File = FileBuf;
- }
- } else {
- Dir = CurDir;
- File = RemappedFile;
- }
- llvm::DIFile *F = DBuilder.createFile(File, Dir, CSInfo, Source);
- DIFileCache[FileName.data()].reset(F);
- return F;
-}
-
-std::string CGDebugInfo::remapDIPath(StringRef Path) const {
- for (const auto &Entry : DebugPrefixMap)
- if (Path.startswith(Entry.first))
- return (Twine(Entry.second) + Path.substr(Entry.first.size())).str();
- return Path.str();
-}
-
-unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
- if (Loc.isInvalid() && CurLoc.isInvalid())
- return 0;
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
- return PLoc.isValid() ? PLoc.getLine() : 0;
-}
-
-unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) {
- // We may not want column information at all.
- if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo)
- return 0;
-
- // If the location is invalid then use the current column.
- if (Loc.isInvalid() && CurLoc.isInvalid())
- return 0;
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
- return PLoc.isValid() ? PLoc.getColumn() : 0;
-}
-
-StringRef CGDebugInfo::getCurrentDirname() {
- if (!CGM.getCodeGenOpts().DebugCompilationDir.empty())
- return CGM.getCodeGenOpts().DebugCompilationDir;
-
- if (!CWDName.empty())
- return CWDName;
- SmallString<256> CWD;
- llvm::sys::fs::current_path(CWD);
- return CWDName = internString(CWD);
-}
-
-void CGDebugInfo::CreateCompileUnit() {
- SmallString<32> Checksum;
- Optional<llvm::DIFile::ChecksumKind> CSKind;
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
-
- // Should we be asking the SourceManager for the main file name, instead of
- // accepting it as an argument? This just causes the main file name to
- // mismatch with source locations and create extra lexical scopes or
- // mismatched debug info (a CU with a DW_AT_file of "-", because that's what
- // the driver passed, but functions/other things have DW_AT_file of "<stdin>"
- // because that's what the SourceManager says)
-
- // Get absolute path name.
- SourceManager &SM = CGM.getContext().getSourceManager();
- std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
- if (MainFileName.empty())
- MainFileName = "<stdin>";
-
- // The main file name provided via the "-main-file-name" option contains just
- // the file name itself with no path information. This file name may have had
- // a relative path, so we look into the actual file entry for the main
- // file to determine the real absolute path for the file.
- std::string MainFileDir;
- if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- MainFileDir = remapDIPath(MainFile->getDir()->getName());
- if (MainFileDir != ".") {
- llvm::SmallString<1024> MainFileDirSS(MainFileDir);
- llvm::sys::path::append(MainFileDirSS, MainFileName);
- MainFileName = MainFileDirSS.str();
- }
- // If the main file name provided is identical to the input file name, and
- // if the input file is a preprocessed source, use the module name for
- // debug info. The module name comes from the name specified in the first
- // linemarker if the input is a preprocessed source.
- if (MainFile->getName() == MainFileName &&
- FrontendOptions::getInputKindForExtension(
- MainFile->getName().rsplit('.').second)
- .isPreprocessed())
- MainFileName = CGM.getModule().getName().str();
-
- CSKind = computeChecksum(SM.getMainFileID(), Checksum);
- }
-
- llvm::dwarf::SourceLanguage LangTag;
- const LangOptions &LO = CGM.getLangOpts();
- if (LO.CPlusPlus) {
- if (LO.ObjC)
- LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
- else
- LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
- } else if (LO.ObjC) {
- LangTag = llvm::dwarf::DW_LANG_ObjC;
- } else if (LO.RenderScript) {
- LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript;
- } else if (LO.C99) {
- LangTag = llvm::dwarf::DW_LANG_C99;
- } else {
- LangTag = llvm::dwarf::DW_LANG_C89;
- }
-
- std::string Producer = getClangFullVersion();
-
- // Figure out which version of the ObjC runtime we have.
- unsigned RuntimeVers = 0;
- if (LO.ObjC)
- RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1;
-
- llvm::DICompileUnit::DebugEmissionKind EmissionKind;
- switch (DebugKind) {
- case codegenoptions::NoDebugInfo:
- case codegenoptions::LocTrackingOnly:
- EmissionKind = llvm::DICompileUnit::NoDebug;
- break;
- case codegenoptions::DebugLineTablesOnly:
- EmissionKind = llvm::DICompileUnit::LineTablesOnly;
- break;
- case codegenoptions::DebugDirectivesOnly:
- EmissionKind = llvm::DICompileUnit::DebugDirectivesOnly;
- break;
- case codegenoptions::LimitedDebugInfo:
- case codegenoptions::FullDebugInfo:
- EmissionKind = llvm::DICompileUnit::FullDebug;
- break;
- }
-
- uint64_t DwoId = 0;
- auto &CGOpts = CGM.getCodeGenOpts();
- // The DIFile used by the CU is distinct from the main source
- // file. Its directory part specifies what becomes the
- // DW_AT_comp_dir (the compilation directory), even if the source
- // file was specified with an absolute path.
- if (CSKind)
- CSInfo.emplace(*CSKind, Checksum);
- llvm::DIFile *CUFile = DBuilder.createFile(
- remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSInfo,
- getSource(SM, SM.getMainFileID()));
-
- // Create new compile unit.
- TheCU = DBuilder.createCompileUnit(
- LangTag, CUFile, CGOpts.EmitVersionIdentMetadata ? Producer : "",
- LO.Optimize || CGOpts.PrepareForLTO || CGOpts.PrepareForThinLTO,
- CGOpts.DwarfDebugFlags, RuntimeVers,
- (CGOpts.getSplitDwarfMode() != CodeGenOptions::NoFission)
- ? ""
- : CGOpts.SplitDwarfFile,
- EmissionKind, DwoId, CGOpts.SplitDwarfInlining,
- CGOpts.DebugInfoForProfiling,
- CGM.getTarget().getTriple().isNVPTX()
- ? llvm::DICompileUnit::DebugNameTableKind::None
- : static_cast<llvm::DICompileUnit::DebugNameTableKind>(
- CGOpts.DebugNameTable),
- CGOpts.DebugRangesBaseAddress);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
- llvm::dwarf::TypeKind Encoding;
- StringRef BTName;
- switch (BT->getKind()) {
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- case BuiltinType::Dependent:
- llvm_unreachable("Unexpected builtin type");
- case BuiltinType::NullPtr:
- return DBuilder.createNullPtrType();
- case BuiltinType::Void:
- return nullptr;
- case BuiltinType::ObjCClass:
- if (!ClassTy)
- ClassTy =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU, TheCU->getFile(), 0);
- return ClassTy;
- case BuiltinType::ObjCId: {
- // typedef struct objc_class *Class;
- // typedef struct objc_object {
- // Class isa;
- // } *id;
-
- if (ObjTy)
- return ObjTy;
-
- if (!ClassTy)
- ClassTy =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU, TheCU->getFile(), 0);
-
- unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
-
- auto *ISATy = DBuilder.createPointerType(ClassTy, Size);
-
- ObjTy = DBuilder.createStructType(TheCU, "objc_object", TheCU->getFile(), 0,
- 0, 0, llvm::DINode::FlagZero, nullptr,
- llvm::DINodeArray());
-
- DBuilder.replaceArrays(
- ObjTy, DBuilder.getOrCreateArray(&*DBuilder.createMemberType(
- ObjTy, "isa", TheCU->getFile(), 0, Size, 0, 0,
- llvm::DINode::FlagZero, ISATy)));
- return ObjTy;
- }
- case BuiltinType::ObjCSel: {
- if (!SelTy)
- SelTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_selector", TheCU,
- TheCU->getFile(), 0);
- return SelTy;
- }
-
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id: \
- return getOrCreateStructPtrType("opencl_" #ImgType "_" #Suffix "_t", \
- SingletonId);
-#include "clang/Basic/OpenCLImageTypes.def"
- case BuiltinType::OCLSampler:
- return getOrCreateStructPtrType("opencl_sampler_t", OCLSamplerDITy);
- case BuiltinType::OCLEvent:
- return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy);
- case BuiltinType::OCLClkEvent:
- return getOrCreateStructPtrType("opencl_clk_event_t", OCLClkEventDITy);
- case BuiltinType::OCLQueue:
- return getOrCreateStructPtrType("opencl_queue_t", OCLQueueDITy);
- case BuiltinType::OCLReserveID:
- return getOrCreateStructPtrType("opencl_reserve_id_t", OCLReserveIDDITy);
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- case BuiltinType::Id: \
- return getOrCreateStructPtrType("opencl_" #ExtType, Id##Ty);
-#include "clang/Basic/OpenCLExtensionTypes.def"
-
- case BuiltinType::UChar:
- case BuiltinType::Char_U:
- Encoding = llvm::dwarf::DW_ATE_unsigned_char;
- break;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- Encoding = llvm::dwarf::DW_ATE_signed_char;
- break;
- case BuiltinType::Char8:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- Encoding = llvm::dwarf::DW_ATE_UTF;
- break;
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::UInt128:
- case BuiltinType::ULong:
- case BuiltinType::WChar_U:
- case BuiltinType::ULongLong:
- Encoding = llvm::dwarf::DW_ATE_unsigned;
- break;
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Int128:
- case BuiltinType::Long:
- case BuiltinType::WChar_S:
- case BuiltinType::LongLong:
- Encoding = llvm::dwarf::DW_ATE_signed;
- break;
- case BuiltinType::Bool:
- Encoding = llvm::dwarf::DW_ATE_boolean;
- break;
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::LongDouble:
- case BuiltinType::Float16:
- case BuiltinType::Float128:
- case BuiltinType::Double:
- // FIXME: For targets where long double and __float128 have the same size,
- // they are currently indistinguishable in the debugger without some
- // special treatment. However, there is currently no consensus on encoding
- // and this should be updated once a DWARF encoding exists for distinct
- // floating point types of the same size.
- Encoding = llvm::dwarf::DW_ATE_float;
- break;
- case BuiltinType::ShortAccum:
- case BuiltinType::Accum:
- case BuiltinType::LongAccum:
- case BuiltinType::ShortFract:
- case BuiltinType::Fract:
- case BuiltinType::LongFract:
- case BuiltinType::SatShortFract:
- case BuiltinType::SatFract:
- case BuiltinType::SatLongFract:
- case BuiltinType::SatShortAccum:
- case BuiltinType::SatAccum:
- case BuiltinType::SatLongAccum:
- Encoding = llvm::dwarf::DW_ATE_signed_fixed;
- break;
- case BuiltinType::UShortAccum:
- case BuiltinType::UAccum:
- case BuiltinType::ULongAccum:
- case BuiltinType::UShortFract:
- case BuiltinType::UFract:
- case BuiltinType::ULongFract:
- case BuiltinType::SatUShortAccum:
- case BuiltinType::SatUAccum:
- case BuiltinType::SatULongAccum:
- case BuiltinType::SatUShortFract:
- case BuiltinType::SatUFract:
- case BuiltinType::SatULongFract:
- Encoding = llvm::dwarf::DW_ATE_unsigned_fixed;
- break;
- }
-
- switch (BT->getKind()) {
- case BuiltinType::Long:
- BTName = "long int";
- break;
- case BuiltinType::LongLong:
- BTName = "long long int";
- break;
- case BuiltinType::ULong:
- BTName = "long unsigned int";
- break;
- case BuiltinType::ULongLong:
- BTName = "long long unsigned int";
- break;
- default:
- BTName = BT->getName(CGM.getLangOpts());
- break;
- }
- // Bit size and offset of the type.
- uint64_t Size = CGM.getContext().getTypeSize(BT);
- return DBuilder.createBasicType(BTName, Size, Encoding);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) {
- // Bit size and offset of the type.
- llvm::dwarf::TypeKind Encoding = llvm::dwarf::DW_ATE_complex_float;
- if (Ty->isComplexIntegerType())
- Encoding = llvm::dwarf::DW_ATE_lo_user;
-
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- return DBuilder.createBasicType("complex", Size, Encoding);
-}
-
-llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty,
- llvm::DIFile *Unit) {
- QualifierCollector Qc;
- const Type *T = Qc.strip(Ty);
-
- // Ignore these qualifiers for now.
- Qc.removeObjCGCAttr();
- Qc.removeAddressSpace();
- Qc.removeObjCLifetime();
-
- // We will create one Derived type for one qualifier and recurse to handle any
- // additional ones.
- llvm::dwarf::Tag Tag;
- if (Qc.hasConst()) {
- Tag = llvm::dwarf::DW_TAG_const_type;
- Qc.removeConst();
- } else if (Qc.hasVolatile()) {
- Tag = llvm::dwarf::DW_TAG_volatile_type;
- Qc.removeVolatile();
- } else if (Qc.hasRestrict()) {
- Tag = llvm::dwarf::DW_TAG_restrict_type;
- Qc.removeRestrict();
- } else {
- assert(Qc.empty() && "Unknown type qualifier for debug info");
- return getOrCreateType(QualType(T, 0), Unit);
- }
-
- auto *FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit);
-
- // No need to fill in the Name, Line, Size, Alignment, Offset in case of
- // CVR derived types.
- return DBuilder.createQualifiedType(Tag, FromTy);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
- llvm::DIFile *Unit) {
-
- // The frontend treats 'id' as a typedef to an ObjCObjectType,
- // whereas 'id<protocol>' is treated as an ObjCPointerType. For the
- // debug info, we want to emit 'id' in both cases.
- if (Ty->isObjCQualifiedIdType())
- return getOrCreateType(CGM.getContext().getObjCIdType(), Unit);
-
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
- Ty->getPointeeType(), Unit);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty,
- llvm::DIFile *Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
- Ty->getPointeeType(), Unit);
-}
-
-/// \return whether a C++ mangling exists for the type defined by TD.
-static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) {
- switch (TheCU->getSourceLanguage()) {
- case llvm::dwarf::DW_LANG_C_plus_plus:
- return true;
- case llvm::dwarf::DW_LANG_ObjC_plus_plus:
- return isa<CXXRecordDecl>(TD) || isa<EnumDecl>(TD);
- default:
- return false;
- }
-}
-
-// Determines if the debug info for this tag declaration needs a type
-// identifier. The purpose of the unique identifier is to deduplicate type
-// information for identical types across TUs. Because of the C++ one definition
-// rule (ODR), it is valid to assume that the type is defined the same way in
-// every TU and its debug info is equivalent.
-//
-// C does not have the ODR, and it is common for codebases to contain multiple
-// different definitions of a struct with the same name in different TUs.
-// Therefore, if the type doesn't have a C++ mangling, don't give it an
-// identifer. Type information in C is smaller and simpler than C++ type
-// information, so the increase in debug info size is negligible.
-//
-// If the type is not externally visible, it should be unique to the current TU,
-// and should not need an identifier to participate in type deduplication.
-// However, when emitting CodeView, the format internally uses these
-// unique type name identifers for references between debug info. For example,
-// the method of a class in an anonymous namespace uses the identifer to refer
-// to its parent class. The Microsoft C++ ABI attempts to provide unique names
-// for such types, so when emitting CodeView, always use identifiers for C++
-// types. This may create problems when attempting to emit CodeView when the MS
-// C++ ABI is not in use.
-static bool needsTypeIdentifier(const TagDecl *TD, CodeGenModule &CGM,
- llvm::DICompileUnit *TheCU) {
- // We only add a type identifier for types with C++ name mangling.
- if (!hasCXXMangling(TD, TheCU))
- return false;
-
- // Externally visible types with C++ mangling need a type identifier.
- if (TD->isExternallyVisible())
- return true;
-
- // CodeView types with C++ mangling need a type identifier.
- if (CGM.getCodeGenOpts().EmitCodeView)
- return true;
-
- return false;
-}
-
-// Returns a unique type identifier string if one exists, or an empty string.
-static SmallString<256> getTypeIdentifier(const TagType *Ty, CodeGenModule &CGM,
- llvm::DICompileUnit *TheCU) {
- SmallString<256> Identifier;
- const TagDecl *TD = Ty->getDecl();
-
- if (!needsTypeIdentifier(TD, CGM, TheCU))
- return Identifier;
-
- // TODO: This is using the RTTI name. Is there a better way to get
- // a unique string for a type?
- llvm::raw_svector_ostream Out(Identifier);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(QualType(Ty, 0), Out);
- return Identifier;
-}
-
-/// \return the appropriate DWARF tag for a composite type.
-static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) {
- llvm::dwarf::Tag Tag;
- if (RD->isStruct() || RD->isInterface())
- Tag = llvm::dwarf::DW_TAG_structure_type;
- else if (RD->isUnion())
- Tag = llvm::dwarf::DW_TAG_union_type;
- else {
- // FIXME: This could be a struct type giving a default visibility different
- // than C++ class type, but needs llvm metadata changes first.
- assert(RD->isClass());
- Tag = llvm::dwarf::DW_TAG_class_type;
- }
- return Tag;
-}
-
-llvm::DICompositeType *
-CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
- llvm::DIScope *Ctx) {
- const RecordDecl *RD = Ty->getDecl();
- if (llvm::DIType *T = getTypeOrNull(CGM.getContext().getRecordType(RD)))
- return cast<llvm::DICompositeType>(T);
- llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation());
- unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = getClassName(RD);
-
- uint64_t Size = 0;
- uint32_t Align = 0;
-
- // Create the type.
- SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
- llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType(
- getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align,
- llvm::DINode::FlagFwdDecl, Identifier);
- if (CGM.getCodeGenOpts().DebugFwdTemplateParams)
- if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- DBuilder.replaceArrays(RetTy, llvm::DINodeArray(),
- CollectCXXTemplateParams(TSpecial, DefUnit));
- ReplaceMap.emplace_back(
- std::piecewise_construct, std::make_tuple(Ty),
- std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
- return RetTy;
-}
-
-llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
- const Type *Ty,
- QualType PointeeTy,
- llvm::DIFile *Unit) {
- // Bit size, align and offset of the type.
- // Size is always the size of a pointer. We can't use getTypeSize here
- // because that does not return the correct value for references.
- unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace);
- auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
- Optional<unsigned> DWARFAddressSpace =
- CGM.getTarget().getDWARFAddressSpace(AddressSpace);
-
- if (Tag == llvm::dwarf::DW_TAG_reference_type ||
- Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
- return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit),
- Size, Align, DWARFAddressSpace);
- else
- return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
- Align, DWARFAddressSpace);
-}
-
-llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
- llvm::DIType *&Cache) {
- if (Cache)
- return Cache;
- Cache = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, Name,
- TheCU, TheCU->getFile(), 0);
- unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- Cache = DBuilder.createPointerType(Cache, Size);
- return Cache;
-}
-
-uint64_t CGDebugInfo::collectDefaultElementTypesForBlockPointer(
- const BlockPointerType *Ty, llvm::DIFile *Unit, llvm::DIDerivedType *DescTy,
- unsigned LineNo, SmallVectorImpl<llvm::Metadata *> &EltTys) {
- QualType FType;
-
- // Advanced by calls to CreateMemberType in increments of FType, then
- // returned as the overall size of the default elements.
- uint64_t FieldOffset = 0;
-
- // Blocks in OpenCL have unique constraints which make the standard fields
- // redundant while requiring size and align fields for enqueue_kernel. See
- // initializeForBlockHeader in CGBlocks.cpp
- if (CGM.getLangOpts().OpenCL) {
- FType = CGM.getContext().IntTy;
- EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__align", &FieldOffset));
- } else {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
- FType = CGM.getContext().IntTy;
- EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset));
- FType = CGM.getContext().getPointerType(Ty->getPointeeType());
- EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset));
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- uint64_t FieldSize = CGM.getContext().getTypeSize(Ty);
- uint32_t FieldAlign = CGM.getContext().getTypeAlign(Ty);
- EltTys.push_back(DBuilder.createMemberType(
- Unit, "__descriptor", nullptr, LineNo, FieldSize, FieldAlign,
- FieldOffset, llvm::DINode::FlagZero, DescTy));
- FieldOffset += FieldSize;
- }
-
- return FieldOffset;
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty,
- llvm::DIFile *Unit) {
- SmallVector<llvm::Metadata *, 8> EltTys;
- QualType FType;
- uint64_t FieldOffset;
- llvm::DINodeArray Elements;
-
- FieldOffset = 0;
- FType = CGM.getContext().UnsignedLongTy;
- EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
-
- Elements = DBuilder.getOrCreateArray(EltTys);
- EltTys.clear();
-
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagAppleBlock;
-
- auto *EltTy =
- DBuilder.createStructType(Unit, "__block_descriptor", nullptr, 0,
- FieldOffset, 0, Flags, nullptr, Elements);
-
- // Bit size, align and offset of the type.
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
-
- auto *DescTy = DBuilder.createPointerType(EltTy, Size);
-
- FieldOffset = collectDefaultElementTypesForBlockPointer(Ty, Unit, DescTy,
- 0, EltTys);
-
- Elements = DBuilder.getOrCreateArray(EltTys);
-
- // The __block_literal_generic structs are marked with a special
- // DW_AT_APPLE_BLOCK attribute and are an implementation detail only
- // the debugger needs to know about. To allow type uniquing, emit
- // them without a name or a location.
- EltTy = DBuilder.createStructType(Unit, "", nullptr, 0, FieldOffset, 0,
- Flags, nullptr, Elements);
-
- return DBuilder.createPointerType(EltTy, Size);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
- llvm::DIFile *Unit) {
- assert(Ty->isTypeAlias());
- llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit);
-
- SmallString<128> NS;
- llvm::raw_svector_ostream OS(NS);
- Ty->getTemplateName().print(OS, getPrintingPolicy(), /*qualified*/ false);
- printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy());
-
- auto *AliasDecl =
- cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
- ->getTemplatedDecl();
-
- SourceLocation Loc = AliasDecl->getLocation();
- return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc),
- getLineNumber(Loc),
- getDeclContextDescriptor(AliasDecl));
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty,
- llvm::DIFile *Unit) {
- // We don't set size information, but do specify where the typedef was
- // declared.
- SourceLocation Loc = Ty->getDecl()->getLocation();
-
- // Typedefs are derived from some other type.
- return DBuilder.createTypedef(
- getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit),
- Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc),
- getDeclContextDescriptor(Ty->getDecl()));
-}
-
-static unsigned getDwarfCC(CallingConv CC) {
- switch (CC) {
- case CC_C:
- // Avoid emitting DW_AT_calling_convention if the C convention was used.
- return 0;
-
- case CC_X86StdCall:
- return llvm::dwarf::DW_CC_BORLAND_stdcall;
- case CC_X86FastCall:
- return llvm::dwarf::DW_CC_BORLAND_msfastcall;
- case CC_X86ThisCall:
- return llvm::dwarf::DW_CC_BORLAND_thiscall;
- case CC_X86VectorCall:
- return llvm::dwarf::DW_CC_LLVM_vectorcall;
- case CC_X86Pascal:
- return llvm::dwarf::DW_CC_BORLAND_pascal;
- case CC_Win64:
- return llvm::dwarf::DW_CC_LLVM_Win64;
- case CC_X86_64SysV:
- return llvm::dwarf::DW_CC_LLVM_X86_64SysV;
- case CC_AAPCS:
- case CC_AArch64VectorCall:
- return llvm::dwarf::DW_CC_LLVM_AAPCS;
- case CC_AAPCS_VFP:
- return llvm::dwarf::DW_CC_LLVM_AAPCS_VFP;
- case CC_IntelOclBicc:
- return llvm::dwarf::DW_CC_LLVM_IntelOclBicc;
- case CC_SpirFunction:
- return llvm::dwarf::DW_CC_LLVM_SpirFunction;
- case CC_OpenCLKernel:
- return llvm::dwarf::DW_CC_LLVM_OpenCLKernel;
- case CC_Swift:
- return llvm::dwarf::DW_CC_LLVM_Swift;
- case CC_PreserveMost:
- return llvm::dwarf::DW_CC_LLVM_PreserveMost;
- case CC_PreserveAll:
- return llvm::dwarf::DW_CC_LLVM_PreserveAll;
- case CC_X86RegCall:
- return llvm::dwarf::DW_CC_LLVM_X86RegCall;
- }
- return 0;
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty,
- llvm::DIFile *Unit) {
- SmallVector<llvm::Metadata *, 16> EltTys;
-
- // Add the result type at least.
- EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit));
-
- // Set up remainder of arguments if there is a prototype.
- // otherwise emit it as a variadic function.
- if (isa<FunctionNoProtoType>(Ty))
- EltTys.push_back(DBuilder.createUnspecifiedParameter());
- else if (const auto *FPT = dyn_cast<FunctionProtoType>(Ty)) {
- for (const QualType &ParamType : FPT->param_types())
- EltTys.push_back(getOrCreateType(ParamType, Unit));
- if (FPT->isVariadic())
- EltTys.push_back(DBuilder.createUnspecifiedParameter());
- }
-
- llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
- return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
- getDwarfCC(Ty->getCallConv()));
-}
-
-/// Convert an AccessSpecifier into the corresponding DINode flag.
-/// As an optimization, return 0 if the access specifier equals the
-/// default for the containing type.
-static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access,
- const RecordDecl *RD) {
- AccessSpecifier Default = clang::AS_none;
- if (RD && RD->isClass())
- Default = clang::AS_private;
- else if (RD && (RD->isStruct() || RD->isUnion()))
- Default = clang::AS_public;
-
- if (Access == Default)
- return llvm::DINode::FlagZero;
-
- switch (Access) {
- case clang::AS_private:
- return llvm::DINode::FlagPrivate;
- case clang::AS_protected:
- return llvm::DINode::FlagProtected;
- case clang::AS_public:
- return llvm::DINode::FlagPublic;
- case clang::AS_none:
- return llvm::DINode::FlagZero;
- }
- llvm_unreachable("unexpected access enumerator");
-}
-
-llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
- llvm::DIScope *RecordTy,
- const RecordDecl *RD) {
- StringRef Name = BitFieldDecl->getName();
- QualType Ty = BitFieldDecl->getType();
- SourceLocation Loc = BitFieldDecl->getLocation();
- llvm::DIFile *VUnit = getOrCreateFile(Loc);
- llvm::DIType *DebugType = getOrCreateType(Ty, VUnit);
-
- // Get the location for the field.
- llvm::DIFile *File = getOrCreateFile(Loc);
- unsigned Line = getLineNumber(Loc);
-
- const CGBitFieldInfo &BitFieldInfo =
- CGM.getTypes().getCGRecordLayout(RD).getBitFieldInfo(BitFieldDecl);
- uint64_t SizeInBits = BitFieldInfo.Size;
- assert(SizeInBits > 0 && "found named 0-width bitfield");
- uint64_t StorageOffsetInBits =
- CGM.getContext().toBits(BitFieldInfo.StorageOffset);
- uint64_t Offset = BitFieldInfo.Offset;
- // The bit offsets for big endian machines are reversed for big
- // endian target, compensate for that as the DIDerivedType requires
- // un-reversed offsets.
- if (CGM.getDataLayout().isBigEndian())
- Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset;
- uint64_t OffsetInBits = StorageOffsetInBits + Offset;
- llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD);
- return DBuilder.createBitFieldMemberType(
- RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits,
- Flags, DebugType);
-}
-
-llvm::DIType *
-CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc,
- AccessSpecifier AS, uint64_t offsetInBits,
- uint32_t AlignInBits, llvm::DIFile *tunit,
- llvm::DIScope *scope, const RecordDecl *RD) {
- llvm::DIType *debugType = getOrCreateType(type, tunit);
-
- // Get the location for the field.
- llvm::DIFile *file = getOrCreateFile(loc);
- unsigned line = getLineNumber(loc);
-
- uint64_t SizeInBits = 0;
- auto Align = AlignInBits;
- if (!type->isIncompleteArrayType()) {
- TypeInfo TI = CGM.getContext().getTypeInfo(type);
- SizeInBits = TI.Width;
- if (!Align)
- Align = getTypeAlignIfRequired(type, CGM.getContext());
- }
-
- llvm::DINode::DIFlags flags = getAccessFlag(AS, RD);
- return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align,
- offsetInBits, flags, debugType);
-}
-
-void CGDebugInfo::CollectRecordLambdaFields(
- const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements,
- llvm::DIType *RecordTy) {
- // For C++11 Lambdas a Field will be the same as a Capture, but the Capture
- // has the name and the location of the variable so we should iterate over
- // both concurrently.
- const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl);
- RecordDecl::field_iterator Field = CXXDecl->field_begin();
- unsigned fieldno = 0;
- for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
- E = CXXDecl->captures_end();
- I != E; ++I, ++Field, ++fieldno) {
- const LambdaCapture &C = *I;
- if (C.capturesVariable()) {
- SourceLocation Loc = C.getLocation();
- assert(!Field->isBitField() && "lambdas don't have bitfield members!");
- VarDecl *V = C.getCapturedVar();
- StringRef VName = V->getName();
- llvm::DIFile *VUnit = getOrCreateFile(Loc);
- auto Align = getDeclAlignIfRequired(V, CGM.getContext());
- llvm::DIType *FieldType = createFieldType(
- VName, Field->getType(), Loc, Field->getAccess(),
- layout.getFieldOffset(fieldno), Align, VUnit, RecordTy, CXXDecl);
- elements.push_back(FieldType);
- } else if (C.capturesThis()) {
- // TODO: Need to handle 'this' in some way by probably renaming the
- // this of the lambda class and having a field member of 'this' or
- // by using AT_object_pointer for the function and having that be
- // used as 'this' for semantic references.
- FieldDecl *f = *Field;
- llvm::DIFile *VUnit = getOrCreateFile(f->getLocation());
- QualType type = f->getType();
- llvm::DIType *fieldType = createFieldType(
- "this", type, f->getLocation(), f->getAccess(),
- layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl);
-
- elements.push_back(fieldType);
- }
- }
-}
-
-llvm::DIDerivedType *
-CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy,
- const RecordDecl *RD) {
- // Create the descriptor for the static variable, with or without
- // constant initializers.
- Var = Var->getCanonicalDecl();
- llvm::DIFile *VUnit = getOrCreateFile(Var->getLocation());
- llvm::DIType *VTy = getOrCreateType(Var->getType(), VUnit);
-
- unsigned LineNumber = getLineNumber(Var->getLocation());
- StringRef VName = Var->getName();
- llvm::Constant *C = nullptr;
- if (Var->getInit()) {
- const APValue *Value = Var->evaluateValue();
- if (Value) {
- if (Value->isInt())
- C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
- if (Value->isFloat())
- C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat());
- }
- }
-
- llvm::DINode::DIFlags Flags = getAccessFlag(Var->getAccess(), RD);
- auto Align = getDeclAlignIfRequired(Var, CGM.getContext());
- llvm::DIDerivedType *GV = DBuilder.createStaticMemberType(
- RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Align);
- StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV);
- return GV;
-}
-
-void CGDebugInfo::CollectRecordNormalField(
- const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit,
- SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy,
- const RecordDecl *RD) {
- StringRef name = field->getName();
- QualType type = field->getType();
-
- // Ignore unnamed fields unless they're anonymous structs/unions.
- if (name.empty() && !type->isRecordType())
- return;
-
- llvm::DIType *FieldType;
- if (field->isBitField()) {
- FieldType = createBitFieldType(field, RecordTy, RD);
- } else {
- auto Align = getDeclAlignIfRequired(field, CGM.getContext());
- FieldType =
- createFieldType(name, type, field->getLocation(), field->getAccess(),
- OffsetInBits, Align, tunit, RecordTy, RD);
- }
-
- elements.push_back(FieldType);
-}
-
-void CGDebugInfo::CollectRecordNestedType(
- const TypeDecl *TD, SmallVectorImpl<llvm::Metadata *> &elements) {
- QualType Ty = CGM.getContext().getTypeDeclType(TD);
- // Injected class names are not considered nested records.
- if (isa<InjectedClassNameType>(Ty))
- return;
- SourceLocation Loc = TD->getLocation();
- llvm::DIType *nestedType = getOrCreateType(Ty, getOrCreateFile(Loc));
- elements.push_back(nestedType);
-}
-
-void CGDebugInfo::CollectRecordFields(
- const RecordDecl *record, llvm::DIFile *tunit,
- SmallVectorImpl<llvm::Metadata *> &elements,
- llvm::DICompositeType *RecordTy) {
- const auto *CXXDecl = dyn_cast<CXXRecordDecl>(record);
-
- if (CXXDecl && CXXDecl->isLambda())
- CollectRecordLambdaFields(CXXDecl, elements, RecordTy);
- else {
- const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
-
- // Field number for non-static fields.
- unsigned fieldNo = 0;
-
- // Static and non-static members should appear in the same order as
- // the corresponding declarations in the source program.
- for (const auto *I : record->decls())
- if (const auto *V = dyn_cast<VarDecl>(I)) {
- if (V->hasAttr<NoDebugAttr>())
- continue;
-
- // Skip variable template specializations when emitting CodeView. MSVC
- // doesn't emit them.
- if (CGM.getCodeGenOpts().EmitCodeView &&
- isa<VarTemplateSpecializationDecl>(V))
- continue;
-
- // Reuse the existing static member declaration if one exists
- auto MI = StaticDataMemberCache.find(V->getCanonicalDecl());
- if (MI != StaticDataMemberCache.end()) {
- assert(MI->second &&
- "Static data member declaration should still exist");
- elements.push_back(MI->second);
- } else {
- auto Field = CreateRecordStaticField(V, RecordTy, record);
- elements.push_back(Field);
- }
- } else if (const auto *field = dyn_cast<FieldDecl>(I)) {
- CollectRecordNormalField(field, layout.getFieldOffset(fieldNo), tunit,
- elements, RecordTy, record);
-
- // Bump field number for next field.
- ++fieldNo;
- } else if (CGM.getCodeGenOpts().EmitCodeView) {
- // Debug info for nested types is included in the member list only for
- // CodeView.
- if (const auto *nestedType = dyn_cast<TypeDecl>(I))
- if (!nestedType->isImplicit() &&
- nestedType->getDeclContext() == record)
- CollectRecordNestedType(nestedType, elements);
- }
- }
-}
-
-llvm::DISubroutineType *
-CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile *Unit) {
- const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
- if (Method->isStatic())
- return cast_or_null<llvm::DISubroutineType>(
- getOrCreateType(QualType(Func, 0), Unit));
- return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit);
-}
-
-llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType(
- QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile *Unit) {
- // Add "this" pointer.
- llvm::DITypeRefArray Args(
- cast<llvm::DISubroutineType>(getOrCreateType(QualType(Func, 0), Unit))
- ->getTypeArray());
- assert(Args.size() && "Invalid number of arguments!");
-
- SmallVector<llvm::Metadata *, 16> Elts;
-
- // First element is always return type. For 'void' functions it is NULL.
- Elts.push_back(Args[0]);
-
- // "this" pointer is always first argument.
- const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl();
- if (isa<ClassTemplateSpecializationDecl>(RD)) {
- // Create pointer type directly in this case.
- const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
- QualType PointeeTy = ThisPtrTy->getPointeeType();
- unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getTarget().getPointerWidth(AS);
- auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext());
- llvm::DIType *PointeeType = getOrCreateType(PointeeTy, Unit);
- llvm::DIType *ThisPtrType =
- DBuilder.createPointerType(PointeeType, Size, Align);
- TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType);
- // TODO: This and the artificial type below are misleading, the
- // types aren't artificial the argument is, but the current
- // metadata doesn't represent that.
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- } else {
- llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit);
- TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType);
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- }
-
- // Copy rest of the arguments.
- for (unsigned i = 1, e = Args.size(); i != e; ++i)
- Elts.push_back(Args[i]);
-
- llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
-
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- if (Func->getExtProtoInfo().RefQualifier == RQ_LValue)
- Flags |= llvm::DINode::FlagLValueReference;
- if (Func->getExtProtoInfo().RefQualifier == RQ_RValue)
- Flags |= llvm::DINode::FlagRValueReference;
-
- return DBuilder.createSubroutineType(EltTypeArray, Flags,
- getDwarfCC(Func->getCallConv()));
-}
-
-/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
-/// inside a function.
-static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
- if (const auto *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext()))
- return isFunctionLocalClass(NRD);
- if (isa<FunctionDecl>(RD->getDeclContext()))
- return true;
- return false;
-}
-
-llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
- const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
- bool IsCtorOrDtor =
- isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
-
- StringRef MethodName = getFunctionName(Method);
- llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
-
- // Since a single ctor/dtor corresponds to multiple functions, it doesn't
- // make sense to give a single ctor/dtor a linkage name.
- StringRef MethodLinkageName;
- // FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional
- // property to use here. It may've been intended to model "is non-external
- // type" but misses cases of non-function-local but non-external classes such
- // as those in anonymous namespaces as well as the reverse - external types
- // that are function local, such as those in (non-local) inline functions.
- if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
- MethodLinkageName = CGM.getMangledName(Method);
-
- // Get the location for the method.
- llvm::DIFile *MethodDefUnit = nullptr;
- unsigned MethodLine = 0;
- if (!Method->isImplicit()) {
- MethodDefUnit = getOrCreateFile(Method->getLocation());
- MethodLine = getLineNumber(Method->getLocation());
- }
-
- // Collect virtual method info.
- llvm::DIType *ContainingType = nullptr;
- unsigned VIndex = 0;
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
- int ThisAdjustment = 0;
-
- if (Method->isVirtual()) {
- if (Method->isPure())
- SPFlags |= llvm::DISubprogram::SPFlagPureVirtual;
- else
- SPFlags |= llvm::DISubprogram::SPFlagVirtual;
-
- if (CGM.getTarget().getCXXABI().isItaniumFamily()) {
- // It doesn't make sense to give a virtual destructor a vtable index,
- // since a single destructor has two entries in the vtable.
- if (!isa<CXXDestructorDecl>(Method))
- VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method);
- } else {
- // Emit MS ABI vftable information. There is only one entry for the
- // deleting dtor.
- const auto *DD = dyn_cast<CXXDestructorDecl>(Method);
- GlobalDecl GD = DD ? GlobalDecl(DD, Dtor_Deleting) : GlobalDecl(Method);
- MethodVFTableLocation ML =
- CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
- VIndex = ML.Index;
-
- // CodeView only records the vftable offset in the class that introduces
- // the virtual method. This is possible because, unlike Itanium, the MS
- // C++ ABI does not include all virtual methods from non-primary bases in
- // the vtable for the most derived class. For example, if C inherits from
- // A and B, C's primary vftable will not include B's virtual methods.
- if (Method->size_overridden_methods() == 0)
- Flags |= llvm::DINode::FlagIntroducedVirtual;
-
- // The 'this' adjustment accounts for both the virtual and non-virtual
- // portions of the adjustment. Presumably the debugger only uses it when
- // it knows the dynamic type of an object.
- ThisAdjustment = CGM.getCXXABI()
- .getVirtualFunctionPrologueThisAdjustment(GD)
- .getQuantity();
- }
- ContainingType = RecordTy;
- }
-
- if (Method->isStatic())
- Flags |= llvm::DINode::FlagStaticMember;
- if (Method->isImplicit())
- Flags |= llvm::DINode::FlagArtificial;
- Flags |= getAccessFlag(Method->getAccess(), Method->getParent());
- if (const auto *CXXC = dyn_cast<CXXConstructorDecl>(Method)) {
- if (CXXC->isExplicit())
- Flags |= llvm::DINode::FlagExplicit;
- } else if (const auto *CXXC = dyn_cast<CXXConversionDecl>(Method)) {
- if (CXXC->isExplicit())
- Flags |= llvm::DINode::FlagExplicit;
- }
- if (Method->hasPrototype())
- Flags |= llvm::DINode::FlagPrototyped;
- if (Method->getRefQualifier() == RQ_LValue)
- Flags |= llvm::DINode::FlagLValueReference;
- if (Method->getRefQualifier() == RQ_RValue)
- Flags |= llvm::DINode::FlagRValueReference;
- if (CGM.getLangOpts().Optimize)
- SPFlags |= llvm::DISubprogram::SPFlagOptimized;
-
- llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
- llvm::DISubprogram *SP = DBuilder.createMethod(
- RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine,
- MethodTy, VIndex, ThisAdjustment, ContainingType, Flags, SPFlags,
- TParamsArray.get());
-
- SPCache[Method->getCanonicalDecl()].reset(SP);
-
- return SP;
-}
-
-void CGDebugInfo::CollectCXXMemberFunctions(
- const CXXRecordDecl *RD, llvm::DIFile *Unit,
- SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) {
-
- // Since we want more than just the individual member decls if we
- // have templated functions iterate over every declaration to gather
- // the functions.
- for (const auto *I : RD->decls()) {
- const auto *Method = dyn_cast<CXXMethodDecl>(I);
- // If the member is implicit, don't add it to the member list. This avoids
- // the member being added to type units by LLVM, while still allowing it
- // to be emitted into the type declaration/reference inside the compile
- // unit.
- // Ditto 'nodebug' methods, for consistency with CodeGenFunction.cpp.
- // FIXME: Handle Using(Shadow?)Decls here to create
- // DW_TAG_imported_declarations inside the class for base decls brought into
- // derived classes. GDB doesn't seem to notice/leverage these when I tried
- // it, so I'm not rushing to fix this. (GCC seems to produce them, if
- // referenced)
- if (!Method || Method->isImplicit() || Method->hasAttr<NoDebugAttr>())
- continue;
-
- if (Method->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
- continue;
-
- // Reuse the existing member function declaration if it exists.
- // It may be associated with the declaration of the type & should be
- // reused as we're building the definition.
- //
- // This situation can arise in the vtable-based debug info reduction where
- // implicit members are emitted in a non-vtable TU.
- auto MI = SPCache.find(Method->getCanonicalDecl());
- EltTys.push_back(MI == SPCache.end()
- ? CreateCXXMemberFunction(Method, Unit, RecordTy)
- : static_cast<llvm::Metadata *>(MI->second));
- }
-}
-
-void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit,
- SmallVectorImpl<llvm::Metadata *> &EltTys,
- llvm::DIType *RecordTy) {
- llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> SeenTypes;
- CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->bases(), SeenTypes,
- llvm::DINode::FlagZero);
-
- // If we are generating CodeView debug info, we also need to emit records for
- // indirect virtual base classes.
- if (CGM.getCodeGenOpts().EmitCodeView) {
- CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->vbases(), SeenTypes,
- llvm::DINode::FlagIndirectVirtualBase);
- }
-}
-
-void CGDebugInfo::CollectCXXBasesAux(
- const CXXRecordDecl *RD, llvm::DIFile *Unit,
- SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy,
- const CXXRecordDecl::base_class_const_range &Bases,
- llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> &SeenTypes,
- llvm::DINode::DIFlags StartingFlags) {
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- for (const auto &BI : Bases) {
- const auto *Base =
- cast<CXXRecordDecl>(BI.getType()->getAs<RecordType>()->getDecl());
- if (!SeenTypes.insert(Base).second)
- continue;
- auto *BaseTy = getOrCreateType(BI.getType(), Unit);
- llvm::DINode::DIFlags BFlags = StartingFlags;
- uint64_t BaseOffset;
- uint32_t VBPtrOffset = 0;
-
- if (BI.isVirtual()) {
- if (CGM.getTarget().getCXXABI().isItaniumFamily()) {
- // virtual base offset offset is -ve. The code generator emits dwarf
- // expression where it expects +ve number.
- BaseOffset = 0 - CGM.getItaniumVTableContext()
- .getVirtualBaseOffsetOffset(RD, Base)
- .getQuantity();
- } else {
- // In the MS ABI, store the vbtable offset, which is analogous to the
- // vbase offset offset in Itanium.
- BaseOffset =
- 4 * CGM.getMicrosoftVTableContext().getVBTableIndex(RD, Base);
- VBPtrOffset = CGM.getContext()
- .getASTRecordLayout(RD)
- .getVBPtrOffset()
- .getQuantity();
- }
- BFlags |= llvm::DINode::FlagVirtual;
- } else
- BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base));
- // FIXME: Inconsistent units for BaseOffset. It is in bytes when
- // BI->isVirtual() and bits when not.
-
- BFlags |= getAccessFlag(BI.getAccessSpecifier(), RD);
- llvm::DIType *DTy = DBuilder.createInheritance(RecordTy, BaseTy, BaseOffset,
- VBPtrOffset, BFlags);
- EltTys.push_back(DTy);
- }
-}
-
-llvm::DINodeArray
-CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
- ArrayRef<TemplateArgument> TAList,
- llvm::DIFile *Unit) {
- SmallVector<llvm::Metadata *, 16> TemplateParams;
- for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
- const TemplateArgument &TA = TAList[i];
- StringRef Name;
- if (TPList)
- Name = TPList->getParam(i)->getName();
- switch (TA.getKind()) {
- case TemplateArgument::Type: {
- llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit);
- TemplateParams.push_back(
- DBuilder.createTemplateTypeParameter(TheCU, Name, TTy));
- } break;
- case TemplateArgument::Integral: {
- llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit);
- TemplateParams.push_back(DBuilder.createTemplateValueParameter(
- TheCU, Name, TTy,
- llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral())));
- } break;
- case TemplateArgument::Declaration: {
- const ValueDecl *D = TA.getAsDecl();
- QualType T = TA.getParamTypeForDecl().getDesugaredType(CGM.getContext());
- llvm::DIType *TTy = getOrCreateType(T, Unit);
- llvm::Constant *V = nullptr;
- const CXXMethodDecl *MD;
- // Variable pointer template parameters have a value that is the address
- // of the variable.
- if (const auto *VD = dyn_cast<VarDecl>(D))
- V = CGM.GetAddrOfGlobalVar(VD);
- // Member function pointers have special support for building them, though
- // this is currently unsupported in LLVM CodeGen.
- else if ((MD = dyn_cast<CXXMethodDecl>(D)) && MD->isInstance())
- V = CGM.getCXXABI().EmitMemberFunctionPointer(MD);
- else if (const auto *FD = dyn_cast<FunctionDecl>(D))
- V = CGM.GetAddrOfFunction(FD);
- // Member data pointers have special handling too to compute the fixed
- // offset within the object.
- else if (const auto *MPT = dyn_cast<MemberPointerType>(T.getTypePtr())) {
- // These five lines (& possibly the above member function pointer
- // handling) might be able to be refactored to use similar code in
- // CodeGenModule::getMemberPointerConstant
- uint64_t fieldOffset = CGM.getContext().getFieldOffset(D);
- CharUnits chars =
- CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset);
- V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars);
- }
- TemplateParams.push_back(DBuilder.createTemplateValueParameter(
- TheCU, Name, TTy,
- cast_or_null<llvm::Constant>(V->stripPointerCasts())));
- } break;
- case TemplateArgument::NullPtr: {
- QualType T = TA.getNullPtrType();
- llvm::DIType *TTy = getOrCreateType(T, Unit);
- llvm::Constant *V = nullptr;
- // Special case member data pointer null values since they're actually -1
- // instead of zero.
- if (const auto *MPT = dyn_cast<MemberPointerType>(T.getTypePtr()))
- // But treat member function pointers as simple zero integers because
- // it's easier than having a special case in LLVM's CodeGen. If LLVM
- // CodeGen grows handling for values of non-null member function
- // pointers then perhaps we could remove this special case and rely on
- // EmitNullMemberPointer for member function pointers.
- if (MPT->isMemberDataPointer())
- V = CGM.getCXXABI().EmitNullMemberPointer(MPT);
- if (!V)
- V = llvm::ConstantInt::get(CGM.Int8Ty, 0);
- TemplateParams.push_back(
- DBuilder.createTemplateValueParameter(TheCU, Name, TTy, V));
- } break;
- case TemplateArgument::Template:
- TemplateParams.push_back(DBuilder.createTemplateTemplateParameter(
- TheCU, Name, nullptr,
- TA.getAsTemplate().getAsTemplateDecl()->getQualifiedNameAsString()));
- break;
- case TemplateArgument::Pack:
- TemplateParams.push_back(DBuilder.createTemplateParameterPack(
- TheCU, Name, nullptr,
- CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit)));
- break;
- case TemplateArgument::Expression: {
- const Expr *E = TA.getAsExpr();
- QualType T = E->getType();
- if (E->isGLValue())
- T = CGM.getContext().getLValueReferenceType(T);
- llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(E, T);
- assert(V && "Expression in template argument isn't constant");
- llvm::DIType *TTy = getOrCreateType(T, Unit);
- TemplateParams.push_back(DBuilder.createTemplateValueParameter(
- TheCU, Name, TTy, V->stripPointerCasts()));
- } break;
- // And the following should never occur:
- case TemplateArgument::TemplateExpansion:
- case TemplateArgument::Null:
- llvm_unreachable(
- "These argument types shouldn't exist in concrete types");
- }
- }
- return DBuilder.getOrCreateArray(TemplateParams);
-}
-
-llvm::DINodeArray
-CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD,
- llvm::DIFile *Unit) {
- if (FD->getTemplatedKind() ==
- FunctionDecl::TK_FunctionTemplateSpecialization) {
- const TemplateParameterList *TList = FD->getTemplateSpecializationInfo()
- ->getTemplate()
- ->getTemplateParameters();
- return CollectTemplateParams(
- TList, FD->getTemplateSpecializationArgs()->asArray(), Unit);
- }
- return llvm::DINodeArray();
-}
-
-llvm::DINodeArray CGDebugInfo::CollectVarTemplateParams(const VarDecl *VL,
- llvm::DIFile *Unit) {
- // Always get the full list of parameters, not just the ones from the
- // specialization. A partial specialization may have fewer parameters than
- // there are arguments.
- auto *TS = dyn_cast<VarTemplateSpecializationDecl>(VL);
- if (!TS)
- return llvm::DINodeArray();
- VarTemplateDecl *T = TS->getSpecializedTemplate();
- const TemplateParameterList *TList = T->getTemplateParameters();
- auto TA = TS->getTemplateArgs().asArray();
- return CollectTemplateParams(TList, TA, Unit);
-}
-
-llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams(
- const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) {
- // Always get the full list of parameters, not just the ones from the
- // specialization. A partial specialization may have fewer parameters than
- // there are arguments.
- TemplateParameterList *TPList =
- TSpecial->getSpecializedTemplate()->getTemplateParameters();
- const TemplateArgumentList &TAList = TSpecial->getTemplateArgs();
- return CollectTemplateParams(TPList, TAList.asArray(), Unit);
-}
-
-llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) {
- if (VTablePtrType)
- return VTablePtrType;
-
- ASTContext &Context = CGM.getContext();
-
- /* Function type */
- llvm::Metadata *STy = getOrCreateType(Context.IntTy, Unit);
- llvm::DITypeRefArray SElements = DBuilder.getOrCreateTypeArray(STy);
- llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements);
- unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
- unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
- Optional<unsigned> DWARFAddressSpace =
- CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
-
- llvm::DIType *vtbl_ptr_type = DBuilder.createPointerType(
- SubTy, Size, 0, DWARFAddressSpace, "__vtbl_ptr_type");
- VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size);
- return VTablePtrType;
-}
-
-StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
- // Copy the gdb compatible name on the side and use its reference.
- return internString("_vptr$", RD->getNameAsString());
-}
-
-void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
- SmallVectorImpl<llvm::Metadata *> &EltTys,
- llvm::DICompositeType *RecordTy) {
- // If this class is not dynamic then there is not any vtable info to collect.
- if (!RD->isDynamicClass())
- return;
-
- // Don't emit any vtable shape or vptr info if this class doesn't have an
- // extendable vfptr. This can happen if the class doesn't have virtual
- // methods, or in the MS ABI if those virtual methods only come from virtually
- // inherited bases.
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- if (!RL.hasExtendableVFPtr())
- return;
-
- // CodeView needs to know how large the vtable of every dynamic class is, so
- // emit a special named pointer type into the element list. The vptr type
- // points to this type as well.
- llvm::DIType *VPtrTy = nullptr;
- bool NeedVTableShape = CGM.getCodeGenOpts().EmitCodeView &&
- CGM.getTarget().getCXXABI().isMicrosoft();
- if (NeedVTableShape) {
- uint64_t PtrWidth =
- CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- const VTableLayout &VFTLayout =
- CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero());
- unsigned VSlotCount =
- VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData;
- unsigned VTableWidth = PtrWidth * VSlotCount;
- unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
- Optional<unsigned> DWARFAddressSpace =
- CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
-
- // Create a very wide void* type and insert it directly in the element list.
- llvm::DIType *VTableType = DBuilder.createPointerType(
- nullptr, VTableWidth, 0, DWARFAddressSpace, "__vtbl_ptr_type");
- EltTys.push_back(VTableType);
-
- // The vptr is a pointer to this special vtable type.
- VPtrTy = DBuilder.createPointerType(VTableType, PtrWidth);
- }
-
- // If there is a primary base then the artificial vptr member lives there.
- if (RL.getPrimaryBase())
- return;
-
- if (!VPtrTy)
- VPtrTy = getOrCreateVTablePtrType(Unit);
-
- unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- llvm::DIType *VPtrMember =
- DBuilder.createMemberType(Unit, getVTableName(RD), Unit, 0, Size, 0, 0,
- llvm::DINode::FlagArtificial, VPtrTy);
- EltTys.push_back(VPtrMember);
-}
-
-llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy,
- SourceLocation Loc) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc));
- return T;
-}
-
-llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D,
- SourceLocation Loc) {
- return getOrCreateStandaloneType(D, Loc);
-}
-
-llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D,
- SourceLocation Loc) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- assert(!D.isNull() && "null type");
- llvm::DIType *T = getOrCreateType(D, getOrCreateFile(Loc));
- assert(T && "could not create debug info for type");
-
- RetainedTypes.push_back(D.getAsOpaquePtr());
- return T;
-}
-
-void CGDebugInfo::completeType(const EnumDecl *ED) {
- if (DebugKind <= codegenoptions::DebugLineTablesOnly)
- return;
- QualType Ty = CGM.getContext().getEnumType(ED);
- void *TyPtr = Ty.getAsOpaquePtr();
- auto I = TypeCache.find(TyPtr);
- if (I == TypeCache.end() || !cast<llvm::DIType>(I->second)->isForwardDecl())
- return;
- llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<EnumType>());
- assert(!Res->isForwardDecl());
- TypeCache[TyPtr].reset(Res);
-}
-
-void CGDebugInfo::completeType(const RecordDecl *RD) {
- if (DebugKind > codegenoptions::LimitedDebugInfo ||
- !CGM.getLangOpts().CPlusPlus)
- completeRequiredType(RD);
-}
-
-/// Return true if the class or any of its methods are marked dllimport.
-static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) {
- if (RD->hasAttr<DLLImportAttr>())
- return true;
- for (const CXXMethodDecl *MD : RD->methods())
- if (MD->hasAttr<DLLImportAttr>())
- return true;
- return false;
-}
-
-/// Does a type definition exist in an imported clang module?
-static bool isDefinedInClangModule(const RecordDecl *RD) {
- // Only definitions that where imported from an AST file come from a module.
- if (!RD || !RD->isFromASTFile())
- return false;
- // Anonymous entities cannot be addressed. Treat them as not from module.
- if (!RD->isExternallyVisible() && RD->getName().empty())
- return false;
- if (auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) {
- if (!CXXDecl->isCompleteDefinition())
- return false;
- // Check wether RD is a template.
- auto TemplateKind = CXXDecl->getTemplateSpecializationKind();
- if (TemplateKind != TSK_Undeclared) {
- // Unfortunately getOwningModule() isn't accurate enough to find the
- // owning module of a ClassTemplateSpecializationDecl that is inside a
- // namespace spanning multiple modules.
- bool Explicit = false;
- if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(CXXDecl))
- Explicit = TD->isExplicitInstantiationOrSpecialization();
- if (!Explicit && CXXDecl->getEnclosingNamespaceContext())
- return false;
- // This is a template, check the origin of the first member.
- if (CXXDecl->field_begin() == CXXDecl->field_end())
- return TemplateKind == TSK_ExplicitInstantiationDeclaration;
- if (!CXXDecl->field_begin()->isFromASTFile())
- return false;
- }
- }
- return true;
-}
-
-void CGDebugInfo::completeClassData(const RecordDecl *RD) {
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- if (CXXRD->isDynamicClass() &&
- CGM.getVTableLinkage(CXXRD) ==
- llvm::GlobalValue::AvailableExternallyLinkage &&
- !isClassOrMethodDLLImport(CXXRD))
- return;
-
- if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
- return;
-
- completeClass(RD);
-}
-
-void CGDebugInfo::completeClass(const RecordDecl *RD) {
- if (DebugKind <= codegenoptions::DebugLineTablesOnly)
- return;
- QualType Ty = CGM.getContext().getRecordType(RD);
- void *TyPtr = Ty.getAsOpaquePtr();
- auto I = TypeCache.find(TyPtr);
- if (I != TypeCache.end() && !cast<llvm::DIType>(I->second)->isForwardDecl())
- return;
- llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<RecordType>());
- assert(!Res->isForwardDecl());
- TypeCache[TyPtr].reset(Res);
-}
-
-static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I,
- CXXRecordDecl::method_iterator End) {
- for (CXXMethodDecl *MD : llvm::make_range(I, End))
- if (FunctionDecl *Tmpl = MD->getInstantiatedFromMemberFunction())
- if (!Tmpl->isImplicit() && Tmpl->isThisDeclarationADefinition() &&
- !MD->getMemberSpecializationInfo()->isExplicitSpecialization())
- return true;
- return false;
-}
-
-static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
- bool DebugTypeExtRefs, const RecordDecl *RD,
- const LangOptions &LangOpts) {
- if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
- return true;
-
- if (auto *ES = RD->getASTContext().getExternalSource())
- if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always)
- return true;
-
- if (DebugKind > codegenoptions::LimitedDebugInfo)
- return false;
-
- if (!LangOpts.CPlusPlus)
- return false;
-
- if (!RD->isCompleteDefinitionRequired())
- return true;
-
- const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
-
- if (!CXXDecl)
- return false;
-
- // Only emit complete debug info for a dynamic class when its vtable is
- // emitted. However, Microsoft debuggers don't resolve type information
- // across DLL boundaries, so skip this optimization if the class or any of its
- // methods are marked dllimport. This isn't a complete solution, since objects
- // without any dllimport methods can be used in one DLL and constructed in
- // another, but it is the current behavior of LimitedDebugInfo.
- if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass() &&
- !isClassOrMethodDLLImport(CXXDecl))
- return true;
-
- TemplateSpecializationKind Spec = TSK_Undeclared;
- if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- Spec = SD->getSpecializationKind();
-
- if (Spec == TSK_ExplicitInstantiationDeclaration &&
- hasExplicitMemberDefinition(CXXDecl->method_begin(),
- CXXDecl->method_end()))
- return true;
-
- return false;
-}
-
-void CGDebugInfo::completeRequiredType(const RecordDecl *RD) {
- if (shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD, CGM.getLangOpts()))
- return;
-
- QualType Ty = CGM.getContext().getRecordType(RD);
- llvm::DIType *T = getTypeOrNull(Ty);
- if (T && T->isForwardDecl())
- completeClassData(RD);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) {
- RecordDecl *RD = Ty->getDecl();
- llvm::DIType *T = cast_or_null<llvm::DIType>(getTypeOrNull(QualType(Ty, 0)));
- if (T || shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD,
- CGM.getLangOpts())) {
- if (!T)
- T = getOrCreateRecordFwdDecl(Ty, getDeclContextDescriptor(RD));
- return T;
- }
-
- return CreateTypeDefinition(Ty);
-}
-
-llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
- RecordDecl *RD = Ty->getDecl();
-
- // Get overall information about the record type for the debug info.
- llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation());
-
- // Records and classes and unions can all be recursive. To handle them, we
- // first generate a debug descriptor for the struct as a forward declaration.
- // Then (if it is a definition) we go through and get debug info for all of
- // its members. Finally, we create a descriptor for the complete type (which
- // may refer to the forward decl if the struct is recursive) and replace all
- // uses of the forward declaration with the final definition.
- llvm::DICompositeType *FwdDecl = getOrCreateLimitedType(Ty, DefUnit);
-
- const RecordDecl *D = RD->getDefinition();
- if (!D || !D->isCompleteDefinition())
- return FwdDecl;
-
- if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD))
- CollectContainingType(CXXDecl, FwdDecl);
-
- // Push the struct on region stack.
- LexicalBlockStack.emplace_back(&*FwdDecl);
- RegionMap[Ty->getDecl()].reset(FwdDecl);
-
- // Convert all the elements.
- SmallVector<llvm::Metadata *, 16> EltTys;
- // what about nested types?
-
- // Note: The split of CXXDecl information here is intentional, the
- // gdb tests will depend on a certain ordering at printout. The debug
- // information offsets are still correct if we merge them all together
- // though.
- const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
- if (CXXDecl) {
- CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl);
- CollectVTableInfo(CXXDecl, DefUnit, EltTys, FwdDecl);
- }
-
- // Collect data fields (including static variables and any initializers).
- CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
- if (CXXDecl)
- CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl);
-
- LexicalBlockStack.pop_back();
- RegionMap.erase(Ty->getDecl());
-
- llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
- DBuilder.replaceArrays(FwdDecl, Elements);
-
- if (FwdDecl->isTemporary())
- FwdDecl =
- llvm::MDNode::replaceWithPermanent(llvm::TempDICompositeType(FwdDecl));
-
- RegionMap[Ty->getDecl()].reset(FwdDecl);
- return FwdDecl;
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty,
- llvm::DIFile *Unit) {
- // Ignore protocols.
- return getOrCreateType(Ty->getBaseType(), Unit);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const ObjCTypeParamType *Ty,
- llvm::DIFile *Unit) {
- // Ignore protocols.
- SourceLocation Loc = Ty->getDecl()->getLocation();
-
- // Use Typedefs to represent ObjCTypeParamType.
- return DBuilder.createTypedef(
- getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit),
- Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc),
- getDeclContextDescriptor(Ty->getDecl()));
-}
-
-/// \return true if Getter has the default name for the property PD.
-static bool hasDefaultGetterName(const ObjCPropertyDecl *PD,
- const ObjCMethodDecl *Getter) {
- assert(PD);
- if (!Getter)
- return true;
-
- assert(Getter->getDeclName().isObjCZeroArgSelector());
- return PD->getName() ==
- Getter->getDeclName().getObjCSelector().getNameForSlot(0);
-}
-
-/// \return true if Setter has the default name for the property PD.
-static bool hasDefaultSetterName(const ObjCPropertyDecl *PD,
- const ObjCMethodDecl *Setter) {
- assert(PD);
- if (!Setter)
- return true;
-
- assert(Setter->getDeclName().isObjCOneArgSelector());
- return SelectorTable::constructSetterName(PD->getName()) ==
- Setter->getDeclName().getObjCSelector().getNameForSlot(0);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
- llvm::DIFile *Unit) {
- ObjCInterfaceDecl *ID = Ty->getDecl();
- if (!ID)
- return nullptr;
-
- // Return a forward declaration if this type was imported from a clang module,
- // and this is not the compile unit with the implementation of the type (which
- // may contain hidden ivars).
- if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() &&
- !ID->getImplementation())
- return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- ID->getName(),
- getDeclContextDescriptor(ID), Unit, 0);
-
- // Get overall information about the record type for the debug info.
- llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation());
- unsigned Line = getLineNumber(ID->getLocation());
- auto RuntimeLang =
- static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
-
- // If this is just a forward declaration return a special forward-declaration
- // debug type since we won't be able to lay out the entire type.
- ObjCInterfaceDecl *Def = ID->getDefinition();
- if (!Def || !Def->getImplementation()) {
- llvm::DIScope *Mod = getParentModuleOrNull(ID);
- llvm::DIType *FwdDecl = DBuilder.createReplaceableCompositeType(
- llvm::dwarf::DW_TAG_structure_type, ID->getName(), Mod ? Mod : TheCU,
- DefUnit, Line, RuntimeLang);
- ObjCInterfaceCache.push_back(ObjCInterfaceCacheEntry(Ty, FwdDecl, Unit));
- return FwdDecl;
- }
-
- return CreateTypeDefinition(Ty, Unit);
-}
-
-llvm::DIModule *
-CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod,
- bool CreateSkeletonCU) {
- // Use the Module pointer as the key into the cache. This is a
- // nullptr if the "Module" is a PCH, which is safe because we don't
- // support chained PCH debug info, so there can only be a single PCH.
- const Module *M = Mod.getModuleOrNull();
- auto ModRef = ModuleCache.find(M);
- if (ModRef != ModuleCache.end())
- return cast<llvm::DIModule>(ModRef->second);
-
- // Macro definitions that were defined with "-D" on the command line.
- SmallString<128> ConfigMacros;
- {
- llvm::raw_svector_ostream OS(ConfigMacros);
- const auto &PPOpts = CGM.getPreprocessorOpts();
- unsigned I = 0;
- // Translate the macro definitions back into a command line.
- for (auto &M : PPOpts.Macros) {
- if (++I > 1)
- OS << " ";
- const std::string &Macro = M.first;
- bool Undef = M.second;
- OS << "\"-" << (Undef ? 'U' : 'D');
- for (char c : Macro)
- switch (c) {
- case '\\':
- OS << "\\\\";
- break;
- case '"':
- OS << "\\\"";
- break;
- default:
- OS << c;
- }
- OS << '\"';
- }
- }
-
- bool IsRootModule = M ? !M->Parent : true;
- if (CreateSkeletonCU && IsRootModule) {
- // PCH files don't have a signature field in the control block,
- // but LLVM detects skeleton CUs by looking for a non-zero DWO id.
- // We use the lower 64 bits for debug info.
- uint64_t Signature =
- Mod.getSignature()
- ? (uint64_t)Mod.getSignature()[1] << 32 | Mod.getSignature()[0]
- : ~1ULL;
- llvm::DIBuilder DIB(CGM.getModule());
- DIB.createCompileUnit(TheCU->getSourceLanguage(),
- // TODO: Support "Source" from external AST providers?
- DIB.createFile(Mod.getModuleName(), Mod.getPath()),
- TheCU->getProducer(), true, StringRef(), 0,
- Mod.getASTFile(), llvm::DICompileUnit::FullDebug,
- Signature);
- DIB.finalize();
- }
- llvm::DIModule *Parent =
- IsRootModule ? nullptr
- : getOrCreateModuleRef(
- ExternalASTSource::ASTSourceDescriptor(*M->Parent),
- CreateSkeletonCU);
- llvm::DIModule *DIMod =
- DBuilder.createModule(Parent, Mod.getModuleName(), ConfigMacros,
- Mod.getPath(), CGM.getHeaderSearchOpts().Sysroot);
- ModuleCache[M].reset(DIMod);
- return DIMod;
-}
-
-llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
- llvm::DIFile *Unit) {
- ObjCInterfaceDecl *ID = Ty->getDecl();
- llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation());
- unsigned Line = getLineNumber(ID->getLocation());
- unsigned RuntimeLang = TheCU->getSourceLanguage();
-
- // Bit size, align and offset of the type.
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
-
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- if (ID->getImplementation())
- Flags |= llvm::DINode::FlagObjcClassComplete;
-
- llvm::DIScope *Mod = getParentModuleOrNull(ID);
- llvm::DICompositeType *RealDecl = DBuilder.createStructType(
- Mod ? Mod : Unit, ID->getName(), DefUnit, Line, Size, Align, Flags,
- nullptr, llvm::DINodeArray(), RuntimeLang);
-
- QualType QTy(Ty, 0);
- TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl);
-
- // Push the struct on region stack.
- LexicalBlockStack.emplace_back(RealDecl);
- RegionMap[Ty->getDecl()].reset(RealDecl);
-
- // Convert all the elements.
- SmallVector<llvm::Metadata *, 16> EltTys;
-
- ObjCInterfaceDecl *SClass = ID->getSuperClass();
- if (SClass) {
- llvm::DIType *SClassTy =
- getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
- if (!SClassTy)
- return nullptr;
-
- llvm::DIType *InhTag = DBuilder.createInheritance(RealDecl, SClassTy, 0, 0,
- llvm::DINode::FlagZero);
- EltTys.push_back(InhTag);
- }
-
- // Create entries for all of the properties.
- auto AddProperty = [&](const ObjCPropertyDecl *PD) {
- SourceLocation Loc = PD->getLocation();
- llvm::DIFile *PUnit = getOrCreateFile(Loc);
- unsigned PLine = getLineNumber(Loc);
- ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
- ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
- llvm::MDNode *PropertyNode = DBuilder.createObjCProperty(
- PD->getName(), PUnit, PLine,
- hasDefaultGetterName(PD, Getter) ? ""
- : getSelectorName(PD->getGetterName()),
- hasDefaultSetterName(PD, Setter) ? ""
- : getSelectorName(PD->getSetterName()),
- PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit));
- EltTys.push_back(PropertyNode);
- };
- {
- llvm::SmallPtrSet<const IdentifierInfo *, 16> PropertySet;
- for (const ObjCCategoryDecl *ClassExt : ID->known_extensions())
- for (auto *PD : ClassExt->properties()) {
- PropertySet.insert(PD->getIdentifier());
- AddProperty(PD);
- }
- for (const auto *PD : ID->properties()) {
- // Don't emit duplicate metadata for properties that were already in a
- // class extension.
- if (!PropertySet.insert(PD->getIdentifier()).second)
- continue;
- AddProperty(PD);
- }
- }
-
- const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
- unsigned FieldNo = 0;
- for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field;
- Field = Field->getNextIvar(), ++FieldNo) {
- llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit);
- if (!FieldTy)
- return nullptr;
-
- StringRef FieldName = Field->getName();
-
- // Ignore unnamed fields.
- if (FieldName.empty())
- continue;
-
- // Get the location for the field.
- llvm::DIFile *FieldDefUnit = getOrCreateFile(Field->getLocation());
- unsigned FieldLine = getLineNumber(Field->getLocation());
- QualType FType = Field->getType();
- uint64_t FieldSize = 0;
- uint32_t FieldAlign = 0;
-
- if (!FType->isIncompleteArrayType()) {
-
- // Bit size, align and offset of the type.
- FieldSize = Field->isBitField()
- ? Field->getBitWidthValue(CGM.getContext())
- : CGM.getContext().getTypeSize(FType);
- FieldAlign = getTypeAlignIfRequired(FType, CGM.getContext());
- }
-
- uint64_t FieldOffset;
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- // We don't know the runtime offset of an ivar if we're using the
- // non-fragile ABI. For bitfields, use the bit offset into the first
- // byte of storage of the bitfield. For other fields, use zero.
- if (Field->isBitField()) {
- FieldOffset =
- CGM.getObjCRuntime().ComputeBitfieldBitOffset(CGM, ID, Field);
- FieldOffset %= CGM.getContext().getCharWidth();
- } else {
- FieldOffset = 0;
- }
- } else {
- FieldOffset = RL.getFieldOffset(FieldNo);
- }
-
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- if (Field->getAccessControl() == ObjCIvarDecl::Protected)
- Flags = llvm::DINode::FlagProtected;
- else if (Field->getAccessControl() == ObjCIvarDecl::Private)
- Flags = llvm::DINode::FlagPrivate;
- else if (Field->getAccessControl() == ObjCIvarDecl::Public)
- Flags = llvm::DINode::FlagPublic;
-
- llvm::MDNode *PropertyNode = nullptr;
- if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
- if (ObjCPropertyImplDecl *PImpD =
- ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
- if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
- SourceLocation Loc = PD->getLocation();
- llvm::DIFile *PUnit = getOrCreateFile(Loc);
- unsigned PLine = getLineNumber(Loc);
- ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
- ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
- PropertyNode = DBuilder.createObjCProperty(
- PD->getName(), PUnit, PLine,
- hasDefaultGetterName(PD, Getter)
- ? ""
- : getSelectorName(PD->getGetterName()),
- hasDefaultSetterName(PD, Setter)
- ? ""
- : getSelectorName(PD->getSetterName()),
- PD->getPropertyAttributes(),
- getOrCreateType(PD->getType(), PUnit));
- }
- }
- }
- FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, FieldLine,
- FieldSize, FieldAlign, FieldOffset, Flags,
- FieldTy, PropertyNode);
- EltTys.push_back(FieldTy);
- }
-
- llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
- DBuilder.replaceArrays(RealDecl, Elements);
-
- LexicalBlockStack.pop_back();
- return RealDecl;
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty,
- llvm::DIFile *Unit) {
- llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit);
- int64_t Count = Ty->getNumElements();
-
- llvm::Metadata *Subscript;
- QualType QTy(Ty, 0);
- auto SizeExpr = SizeExprCache.find(QTy);
- if (SizeExpr != SizeExprCache.end())
- Subscript = DBuilder.getOrCreateSubrange(0, SizeExpr->getSecond());
- else
- Subscript = DBuilder.getOrCreateSubrange(0, Count ? Count : -1);
- llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
-
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
-
- return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIFile *Unit) {
- uint64_t Size;
- uint32_t Align;
-
- // FIXME: make getTypeAlign() aware of VLAs and incomplete array types
- if (const auto *VAT = dyn_cast<VariableArrayType>(Ty)) {
- Size = 0;
- Align = getTypeAlignIfRequired(CGM.getContext().getBaseElementType(VAT),
- CGM.getContext());
- } else if (Ty->isIncompleteArrayType()) {
- Size = 0;
- if (Ty->getElementType()->isIncompleteType())
- Align = 0;
- else
- Align = getTypeAlignIfRequired(Ty->getElementType(), CGM.getContext());
- } else if (Ty->isIncompleteType()) {
- Size = 0;
- Align = 0;
- } else {
- // Size and align of the whole array, not the element type.
- Size = CGM.getContext().getTypeSize(Ty);
- Align = getTypeAlignIfRequired(Ty, CGM.getContext());
- }
-
- // Add the dimensions of the array. FIXME: This loses CV qualifiers from
- // interior arrays, do we care? Why aren't nested arrays represented the
- // obvious/recursive way?
- SmallVector<llvm::Metadata *, 8> Subscripts;
- QualType EltTy(Ty, 0);
- while ((Ty = dyn_cast<ArrayType>(EltTy))) {
- // If the number of elements is known, then count is that number. Otherwise,
- // it's -1. This allows us to represent a subrange with an array of 0
- // elements, like this:
- //
- // struct foo {
- // int x[0];
- // };
- int64_t Count = -1; // Count == -1 is an unbounded array.
- if (const auto *CAT = dyn_cast<ConstantArrayType>(Ty))
- Count = CAT->getSize().getZExtValue();
- else if (const auto *VAT = dyn_cast<VariableArrayType>(Ty)) {
- if (Expr *Size = VAT->getSizeExpr()) {
- Expr::EvalResult Result;
- if (Size->EvaluateAsInt(Result, CGM.getContext()))
- Count = Result.Val.getInt().getExtValue();
- }
- }
-
- auto SizeNode = SizeExprCache.find(EltTy);
- if (SizeNode != SizeExprCache.end())
- Subscripts.push_back(
- DBuilder.getOrCreateSubrange(0, SizeNode->getSecond()));
- else
- Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
- EltTy = Ty->getElementType();
- }
-
- llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts);
-
- return DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
- SubscriptArray);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const LValueReferenceType *Ty,
- llvm::DIFile *Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type, Ty,
- Ty->getPointeeType(), Unit);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const RValueReferenceType *Ty,
- llvm::DIFile *Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type, Ty,
- Ty->getPointeeType(), Unit);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty,
- llvm::DIFile *U) {
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- uint64_t Size = 0;
-
- if (!Ty->isIncompleteType()) {
- Size = CGM.getContext().getTypeSize(Ty);
-
- // Set the MS inheritance model. There is no flag for the unspecified model.
- if (CGM.getTarget().getCXXABI().isMicrosoft()) {
- switch (Ty->getMostRecentCXXRecordDecl()->getMSInheritanceModel()) {
- case MSInheritanceAttr::Keyword_single_inheritance:
- Flags |= llvm::DINode::FlagSingleInheritance;
- break;
- case MSInheritanceAttr::Keyword_multiple_inheritance:
- Flags |= llvm::DINode::FlagMultipleInheritance;
- break;
- case MSInheritanceAttr::Keyword_virtual_inheritance:
- Flags |= llvm::DINode::FlagVirtualInheritance;
- break;
- case MSInheritanceAttr::Keyword_unspecified_inheritance:
- break;
- }
- }
- }
-
- llvm::DIType *ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U);
- if (Ty->isMemberDataPointerType())
- return DBuilder.createMemberPointerType(
- getOrCreateType(Ty->getPointeeType(), U), ClassType, Size, /*Align=*/0,
- Flags);
-
- const FunctionProtoType *FPT =
- Ty->getPointeeType()->getAs<FunctionProtoType>();
- return DBuilder.createMemberPointerType(
- getOrCreateInstanceMethodType(
- CXXMethodDecl::getThisType(FPT, Ty->getMostRecentCXXRecordDecl()),
- FPT, U),
- ClassType, Size, /*Align=*/0, Flags);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) {
- auto *FromTy = getOrCreateType(Ty->getValueType(), U);
- return DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_atomic_type, FromTy);
-}
-
-llvm::DIType *CGDebugInfo::CreateType(const PipeType *Ty, llvm::DIFile *U) {
- return getOrCreateType(Ty->getElementType(), U);
-}
-
-llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) {
- const EnumDecl *ED = Ty->getDecl();
-
- uint64_t Size = 0;
- uint32_t Align = 0;
- if (!ED->getTypeForDecl()->isIncompleteType()) {
- Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
- Align = getDeclAlignIfRequired(ED, CGM.getContext());
- }
-
- SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
-
- bool isImportedFromModule =
- DebugTypeExtRefs && ED->isFromASTFile() && ED->getDefinition();
-
- // If this is just a forward declaration, construct an appropriately
- // marked node and just return it.
- if (isImportedFromModule || !ED->getDefinition()) {
- // Note that it is possible for enums to be created as part of
- // their own declcontext. In this case a FwdDecl will be created
- // twice. This doesn't cause a problem because both FwdDecls are
- // entered into the ReplaceMap: finalize() will replace the first
- // FwdDecl with the second and then replace the second with
- // complete type.
- llvm::DIScope *EDContext = getDeclContextDescriptor(ED);
- llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation());
- llvm::TempDIScope TmpContext(DBuilder.createReplaceableCompositeType(
- llvm::dwarf::DW_TAG_enumeration_type, "", TheCU, DefUnit, 0));
-
- unsigned Line = getLineNumber(ED->getLocation());
- StringRef EDName = ED->getName();
- llvm::DIType *RetTy = DBuilder.createReplaceableCompositeType(
- llvm::dwarf::DW_TAG_enumeration_type, EDName, EDContext, DefUnit, Line,
- 0, Size, Align, llvm::DINode::FlagFwdDecl, Identifier);
-
- ReplaceMap.emplace_back(
- std::piecewise_construct, std::make_tuple(Ty),
- std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
- return RetTy;
- }
-
- return CreateTypeDefinition(Ty);
-}
-
-llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) {
- const EnumDecl *ED = Ty->getDecl();
- uint64_t Size = 0;
- uint32_t Align = 0;
- if (!ED->getTypeForDecl()->isIncompleteType()) {
- Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
- Align = getDeclAlignIfRequired(ED, CGM.getContext());
- }
-
- SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
-
- // Create elements for each enumerator.
- SmallVector<llvm::Metadata *, 16> Enumerators;
- ED = ED->getDefinition();
- bool IsSigned = ED->getIntegerType()->isSignedIntegerType();
- for (const auto *Enum : ED->enumerators()) {
- const auto &InitVal = Enum->getInitVal();
- auto Value = IsSigned ? InitVal.getSExtValue() : InitVal.getZExtValue();
- Enumerators.push_back(
- DBuilder.createEnumerator(Enum->getName(), Value, !IsSigned));
- }
-
- // Return a CompositeType for the enum itself.
- llvm::DINodeArray EltArray = DBuilder.getOrCreateArray(Enumerators);
-
- llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation());
- unsigned Line = getLineNumber(ED->getLocation());
- llvm::DIScope *EnumContext = getDeclContextDescriptor(ED);
- llvm::DIType *ClassTy = getOrCreateType(ED->getIntegerType(), DefUnit);
- return DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit,
- Line, Size, Align, EltArray, ClassTy,
- Identifier, ED->isScoped());
-}
-
-llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent,
- unsigned MType, SourceLocation LineLoc,
- StringRef Name, StringRef Value) {
- unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
- return DBuilder.createMacro(Parent, Line, MType, Name, Value);
-}
-
-llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent,
- SourceLocation LineLoc,
- SourceLocation FileLoc) {
- llvm::DIFile *FName = getOrCreateFile(FileLoc);
- unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
- return DBuilder.createTempMacroFile(Parent, Line, FName);
-}
-
-static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
- Qualifiers Quals;
- do {
- Qualifiers InnerQuals = T.getLocalQualifiers();
- // Qualifiers::operator+() doesn't like it if you add a Qualifier
- // that is already there.
- Quals += Qualifiers::removeCommonQualifiers(Quals, InnerQuals);
- Quals += InnerQuals;
- QualType LastT = T;
- switch (T->getTypeClass()) {
- default:
- return C.getQualifiedType(T.getTypePtr(), Quals);
- case Type::TemplateSpecialization: {
- const auto *Spec = cast<TemplateSpecializationType>(T);
- if (Spec->isTypeAlias())
- return C.getQualifiedType(T.getTypePtr(), Quals);
- T = Spec->desugar();
- break;
- }
- case Type::TypeOfExpr:
- T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
- break;
- case Type::TypeOf:
- T = cast<TypeOfType>(T)->getUnderlyingType();
- break;
- case Type::Decltype:
- T = cast<DecltypeType>(T)->getUnderlyingType();
- break;
- case Type::UnaryTransform:
- T = cast<UnaryTransformType>(T)->getUnderlyingType();
- break;
- case Type::Attributed:
- T = cast<AttributedType>(T)->getEquivalentType();
- break;
- case Type::Elaborated:
- T = cast<ElaboratedType>(T)->getNamedType();
- break;
- case Type::Paren:
- T = cast<ParenType>(T)->getInnerType();
- break;
- case Type::SubstTemplateTypeParm:
- T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
- break;
- case Type::Auto:
- case Type::DeducedTemplateSpecialization: {
- QualType DT = cast<DeducedType>(T)->getDeducedType();
- assert(!DT.isNull() && "Undeduced types shouldn't reach here.");
- T = DT;
- break;
- }
- case Type::Adjusted:
- case Type::Decayed:
- // Decayed and adjusted types use the adjusted type in LLVM and DWARF.
- T = cast<AdjustedType>(T)->getAdjustedType();
- break;
- }
-
- assert(T != LastT && "Type unwrapping failed to unwrap!");
- (void)LastT;
- } while (true);
-}
-
-llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) {
-
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
-
- auto It = TypeCache.find(Ty.getAsOpaquePtr());
- if (It != TypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Metadata *V = It->second)
- return cast<llvm::DIType>(V);
- }
-
- return nullptr;
-}
-
-void CGDebugInfo::completeTemplateDefinition(
- const ClassTemplateSpecializationDecl &SD) {
- if (DebugKind <= codegenoptions::DebugLineTablesOnly)
- return;
- completeUnusedClass(SD);
-}
-
-void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
- if (DebugKind <= codegenoptions::DebugLineTablesOnly)
- return;
-
- completeClassData(&D);
- // In case this type has no member function definitions being emitted, ensure
- // it is retained
- RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr());
-}
-
-llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
- if (Ty.isNull())
- return nullptr;
-
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
-
- if (auto *T = getTypeOrNull(Ty))
- return T;
-
- llvm::DIType *Res = CreateTypeNode(Ty, Unit);
- void *TyPtr = Ty.getAsOpaquePtr();
-
- // And update the type cache.
- TypeCache[TyPtr].reset(Res);
-
- return Res;
-}
-
-llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) {
- // A forward declaration inside a module header does not belong to the module.
- if (isa<RecordDecl>(D) && !cast<RecordDecl>(D)->getDefinition())
- return nullptr;
- if (DebugTypeExtRefs && D->isFromASTFile()) {
- // Record a reference to an imported clang module or precompiled header.
- auto *Reader = CGM.getContext().getExternalSource();
- auto Idx = D->getOwningModuleID();
- auto Info = Reader->getSourceDescriptor(Idx);
- if (Info)
- return getOrCreateModuleRef(*Info, /*SkeletonCU=*/true);
- } else if (ClangModuleMap) {
- // We are building a clang module or a precompiled header.
- //
- // TODO: When D is a CXXRecordDecl or a C++ Enum, the ODR applies
- // and it wouldn't be necessary to specify the parent scope
- // because the type is already unique by definition (it would look
- // like the output of -fno-standalone-debug). On the other hand,
- // the parent scope helps a consumer to quickly locate the object
- // file where the type's definition is located, so it might be
- // best to make this behavior a command line or debugger tuning
- // option.
- if (Module *M = D->getOwningModule()) {
- // This is a (sub-)module.
- auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
- return getOrCreateModuleRef(Info, /*SkeletonCU=*/false);
- } else {
- // This the precompiled header being built.
- return getOrCreateModuleRef(PCHDescriptor, /*SkeletonCU=*/false);
- }
- }
-
- return nullptr;
-}
-
-llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
- // Handle qualifiers, which recursively handles what they refer to.
- if (Ty.hasLocalQualifiers())
- return CreateQualifiedType(Ty, Unit);
-
- // Work out details of type.
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base)
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Dependent types cannot show up in debug information");
-
- case Type::ExtVector:
- case Type::Vector:
- return CreateType(cast<VectorType>(Ty), Unit);
- case Type::ObjCObjectPointer:
- return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
- case Type::ObjCObject:
- return CreateType(cast<ObjCObjectType>(Ty), Unit);
- case Type::ObjCTypeParam:
- return CreateType(cast<ObjCTypeParamType>(Ty), Unit);
- case Type::ObjCInterface:
- return CreateType(cast<ObjCInterfaceType>(Ty), Unit);
- case Type::Builtin:
- return CreateType(cast<BuiltinType>(Ty));
- case Type::Complex:
- return CreateType(cast<ComplexType>(Ty));
- case Type::Pointer:
- return CreateType(cast<PointerType>(Ty), Unit);
- case Type::BlockPointer:
- return CreateType(cast<BlockPointerType>(Ty), Unit);
- case Type::Typedef:
- return CreateType(cast<TypedefType>(Ty), Unit);
- case Type::Record:
- return CreateType(cast<RecordType>(Ty));
- case Type::Enum:
- return CreateEnumType(cast<EnumType>(Ty));
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- return CreateType(cast<FunctionType>(Ty), Unit);
- case Type::ConstantArray:
- case Type::VariableArray:
- case Type::IncompleteArray:
- return CreateType(cast<ArrayType>(Ty), Unit);
-
- case Type::LValueReference:
- return CreateType(cast<LValueReferenceType>(Ty), Unit);
- case Type::RValueReference:
- return CreateType(cast<RValueReferenceType>(Ty), Unit);
-
- case Type::MemberPointer:
- return CreateType(cast<MemberPointerType>(Ty), Unit);
-
- case Type::Atomic:
- return CreateType(cast<AtomicType>(Ty), Unit);
-
- case Type::Pipe:
- return CreateType(cast<PipeType>(Ty), Unit);
-
- case Type::TemplateSpecialization:
- return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
-
- case Type::Auto:
- case Type::Attributed:
- case Type::Adjusted:
- case Type::Decayed:
- case Type::DeducedTemplateSpecialization:
- case Type::Elaborated:
- case Type::Paren:
- case Type::SubstTemplateTypeParm:
- case Type::TypeOfExpr:
- case Type::TypeOf:
- case Type::Decltype:
- case Type::UnaryTransform:
- case Type::PackExpansion:
- break;
- }
-
- llvm_unreachable("type should have been unwrapped!");
-}
-
-llvm::DICompositeType *CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty,
- llvm::DIFile *Unit) {
- QualType QTy(Ty, 0);
-
- auto *T = cast_or_null<llvm::DICompositeType>(getTypeOrNull(QTy));
-
- // We may have cached a forward decl when we could have created
- // a non-forward decl. Go ahead and create a non-forward decl
- // now.
- if (T && !T->isForwardDecl())
- return T;
-
- // Otherwise create the type.
- llvm::DICompositeType *Res = CreateLimitedType(Ty);
-
- // Propagate members from the declaration to the definition
- // CreateType(const RecordType*) will overwrite this with the members in the
- // correct order if the full type is needed.
- DBuilder.replaceArrays(Res, T ? T->getElements() : llvm::DINodeArray());
-
- // And update the type cache.
- TypeCache[QTy.getAsOpaquePtr()].reset(Res);
- return Res;
-}
-
-// TODO: Currently used for context chains when limiting debug info.
-llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
- RecordDecl *RD = Ty->getDecl();
-
- // Get overall information about the record type for the debug info.
- llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation());
- unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = getClassName(RD);
-
- llvm::DIScope *RDContext = getDeclContextDescriptor(RD);
-
- // If we ended up creating the type during the context chain construction,
- // just return that.
- auto *T = cast_or_null<llvm::DICompositeType>(
- getTypeOrNull(CGM.getContext().getRecordType(RD)));
- if (T && (!T->isForwardDecl() || !RD->getDefinition()))
- return T;
-
- // If this is just a forward or incomplete declaration, construct an
- // appropriately marked node and just return it.
- const RecordDecl *D = RD->getDefinition();
- if (!D || !D->isCompleteDefinition())
- return getOrCreateRecordFwdDecl(Ty, RDContext);
-
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- auto Align = getDeclAlignIfRequired(D, CGM.getContext());
-
- SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
-
- // Explicitly record the calling convention for C++ records.
- auto Flags = llvm::DINode::FlagZero;
- if (auto CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- if (CGM.getCXXABI().getRecordArgABI(CXXRD) == CGCXXABI::RAA_Indirect)
- Flags |= llvm::DINode::FlagTypePassByReference;
- else
- Flags |= llvm::DINode::FlagTypePassByValue;
-
- // Record if a C++ record is trivial type.
- if (CXXRD->isTrivial())
- Flags |= llvm::DINode::FlagTrivial;
- }
-
- llvm::DICompositeType *RealDecl = DBuilder.createReplaceableCompositeType(
- getTagForRecord(RD), RDName, RDContext, DefUnit, Line, 0, Size, Align,
- Flags, Identifier);
-
- // Elements of composite types usually have back to the type, creating
- // uniquing cycles. Distinct nodes are more efficient.
- switch (RealDecl->getTag()) {
- default:
- llvm_unreachable("invalid composite type tag");
-
- case llvm::dwarf::DW_TAG_array_type:
- case llvm::dwarf::DW_TAG_enumeration_type:
- // Array elements and most enumeration elements don't have back references,
- // so they don't tend to be involved in uniquing cycles and there is some
- // chance of merging them when linking together two modules. Only make
- // them distinct if they are ODR-uniqued.
- if (Identifier.empty())
- break;
- LLVM_FALLTHROUGH;
-
- case llvm::dwarf::DW_TAG_structure_type:
- case llvm::dwarf::DW_TAG_union_type:
- case llvm::dwarf::DW_TAG_class_type:
- // Immediately resolve to a distinct node.
- RealDecl =
- llvm::MDNode::replaceWithDistinct(llvm::TempDICompositeType(RealDecl));
- break;
- }
-
- RegionMap[Ty->getDecl()].reset(RealDecl);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
-
- if (const auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- DBuilder.replaceArrays(RealDecl, llvm::DINodeArray(),
- CollectCXXTemplateParams(TSpecial, DefUnit));
- return RealDecl;
-}
-
-void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
- llvm::DICompositeType *RealDecl) {
- // A class's primary base or the class itself contains the vtable.
- llvm::DICompositeType *ContainingType = nullptr;
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
- // Seek non-virtual primary base root.
- while (1) {
- const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
- const CXXRecordDecl *PBT = BRL.getPrimaryBase();
- if (PBT && !BRL.isPrimaryBaseVirtual())
- PBase = PBT;
- else
- break;
- }
- ContainingType = cast<llvm::DICompositeType>(
- getOrCreateType(QualType(PBase->getTypeForDecl(), 0),
- getOrCreateFile(RD->getLocation())));
- } else if (RD->isDynamicClass())
- ContainingType = RealDecl;
-
- DBuilder.replaceVTableHolder(RealDecl, ContainingType);
-}
-
-llvm::DIType *CGDebugInfo::CreateMemberType(llvm::DIFile *Unit, QualType FType,
- StringRef Name, uint64_t *Offset) {
- llvm::DIType *FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
- auto FieldAlign = getTypeAlignIfRequired(FType, CGM.getContext());
- llvm::DIType *Ty =
- DBuilder.createMemberType(Unit, Name, Unit, 0, FieldSize, FieldAlign,
- *Offset, llvm::DINode::FlagZero, FieldTy);
- *Offset += FieldSize;
- return Ty;
-}
-
-void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
- StringRef &Name,
- StringRef &LinkageName,
- llvm::DIScope *&FDContext,
- llvm::DINodeArray &TParamsArray,
- llvm::DINode::DIFlags &Flags) {
- const auto *FD = cast<FunctionDecl>(GD.getDecl());
- Name = getFunctionName(FD);
- // Use mangled name as linkage name for C/C++ functions.
- if (FD->hasPrototype()) {
- LinkageName = CGM.getMangledName(GD);
- Flags |= llvm::DINode::FlagPrototyped;
- }
- // No need to replicate the linkage name if it isn't different from the
- // subprogram name, no need to have it at all unless coverage is enabled or
- // debug is set to more than just line tables or extra debug info is needed.
- if (LinkageName == Name || (!CGM.getCodeGenOpts().EmitGcovArcs &&
- !CGM.getCodeGenOpts().EmitGcovNotes &&
- !CGM.getCodeGenOpts().DebugInfoForProfiling &&
- DebugKind <= codegenoptions::DebugLineTablesOnly))
- LinkageName = StringRef();
-
- if (DebugKind >= codegenoptions::LimitedDebugInfo) {
- if (const NamespaceDecl *NSDecl =
- dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
- FDContext = getOrCreateNamespace(NSDecl);
- else if (const RecordDecl *RDecl =
- dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) {
- llvm::DIScope *Mod = getParentModuleOrNull(RDecl);
- FDContext = getContextDescriptor(RDecl, Mod ? Mod : TheCU);
- }
- // Check if it is a noreturn-marked function
- if (FD->isNoReturn())
- Flags |= llvm::DINode::FlagNoReturn;
- // Collect template parameters.
- TParamsArray = CollectFunctionTemplateParams(FD, Unit);
- }
-}
-
-void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit,
- unsigned &LineNo, QualType &T,
- StringRef &Name, StringRef &LinkageName,
- llvm::MDTuple *&TemplateParameters,
- llvm::DIScope *&VDContext) {
- Unit = getOrCreateFile(VD->getLocation());
- LineNo = getLineNumber(VD->getLocation());
-
- setLocation(VD->getLocation());
-
- T = VD->getType();
- if (T->isIncompleteArrayType()) {
- // CodeGen turns int[] into int[1] so we'll do the same here.
- llvm::APInt ConstVal(32, 1);
- QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
-
- T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal,
- 0);
- }
-
- Name = VD->getName();
- if (VD->getDeclContext() && !isa<FunctionDecl>(VD->getDeclContext()) &&
- !isa<ObjCMethodDecl>(VD->getDeclContext()))
- LinkageName = CGM.getMangledName(VD);
- if (LinkageName == Name)
- LinkageName = StringRef();
-
- if (isa<VarTemplateSpecializationDecl>(VD)) {
- llvm::DINodeArray parameterNodes = CollectVarTemplateParams(VD, &*Unit);
- TemplateParameters = parameterNodes.get();
- } else {
- TemplateParameters = nullptr;
- }
-
- // Since we emit declarations (DW_AT_members) for static members, place the
- // definition of those static members in the namespace they were declared in
- // in the source code (the lexical decl context).
- // FIXME: Generalize this for even non-member global variables where the
- // declaration and definition may have different lexical decl contexts, once
- // we have support for emitting declarations of (non-member) global variables.
- const DeclContext *DC = VD->isStaticDataMember() ? VD->getLexicalDeclContext()
- : VD->getDeclContext();
- // When a record type contains an in-line initialization of a static data
- // member, and the record type is marked as __declspec(dllexport), an implicit
- // definition of the member will be created in the record context. DWARF
- // doesn't seem to have a nice way to describe this in a form that consumers
- // are likely to understand, so fake the "normal" situation of a definition
- // outside the class by putting it in the global scope.
- if (DC->isRecord())
- DC = CGM.getContext().getTranslationUnitDecl();
-
- llvm::DIScope *Mod = getParentModuleOrNull(VD);
- VDContext = getContextDescriptor(cast<Decl>(DC), Mod ? Mod : TheCU);
-}
-
-llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD,
- bool Stub) {
- llvm::DINodeArray TParamsArray;
- StringRef Name, LinkageName;
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
- SourceLocation Loc = GD.getDecl()->getLocation();
- llvm::DIFile *Unit = getOrCreateFile(Loc);
- llvm::DIScope *DContext = Unit;
- unsigned Line = getLineNumber(Loc);
- collectFunctionDeclProps(GD, Unit, Name, LinkageName, DContext, TParamsArray,
- Flags);
- auto *FD = dyn_cast<FunctionDecl>(GD.getDecl());
-
- // Build function type.
- SmallVector<QualType, 16> ArgTypes;
- if (FD)
- for (const ParmVarDecl *Parm : FD->parameters())
- ArgTypes.push_back(Parm->getType());
- CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
- QualType FnType = CGM.getContext().getFunctionType(
- FD->getReturnType(), ArgTypes, FunctionProtoType::ExtProtoInfo(CC));
- if (!FD->isExternallyVisible())
- SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
- if (CGM.getLangOpts().Optimize)
- SPFlags |= llvm::DISubprogram::SPFlagOptimized;
-
- if (Stub) {
- Flags |= getCallSiteRelatedAttrs();
- SPFlags |= llvm::DISubprogram::SPFlagDefinition;
- return DBuilder.createFunction(
- DContext, Name, LinkageName, Unit, Line,
- getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags,
- TParamsArray.get(), getFunctionDeclaration(FD));
- }
-
- llvm::DISubprogram *SP = DBuilder.createTempFunctionFwdDecl(
- DContext, Name, LinkageName, Unit, Line,
- getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags,
- TParamsArray.get(), getFunctionDeclaration(FD));
- const FunctionDecl *CanonDecl = FD->getCanonicalDecl();
- FwdDeclReplaceMap.emplace_back(std::piecewise_construct,
- std::make_tuple(CanonDecl),
- std::make_tuple(SP));
- return SP;
-}
-
-llvm::DISubprogram *CGDebugInfo::getFunctionForwardDeclaration(GlobalDecl GD) {
- return getFunctionFwdDeclOrStub(GD, /* Stub = */ false);
-}
-
-llvm::DISubprogram *CGDebugInfo::getFunctionStub(GlobalDecl GD) {
- return getFunctionFwdDeclOrStub(GD, /* Stub = */ true);
-}
-
-llvm::DIGlobalVariable *
-CGDebugInfo::getGlobalVariableForwardDeclaration(const VarDecl *VD) {
- QualType T;
- StringRef Name, LinkageName;
- SourceLocation Loc = VD->getLocation();
- llvm::DIFile *Unit = getOrCreateFile(Loc);
- llvm::DIScope *DContext = Unit;
- unsigned Line = getLineNumber(Loc);
- llvm::MDTuple *TemplateParameters = nullptr;
-
- collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, TemplateParameters,
- DContext);
- auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
- auto *GV = DBuilder.createTempGlobalVariableFwdDecl(
- DContext, Name, LinkageName, Unit, Line, getOrCreateType(T, Unit),
- !VD->isExternallyVisible(), nullptr, TemplateParameters, Align);
- FwdDeclReplaceMap.emplace_back(
- std::piecewise_construct,
- std::make_tuple(cast<VarDecl>(VD->getCanonicalDecl())),
- std::make_tuple(static_cast<llvm::Metadata *>(GV)));
- return GV;
-}
-
-llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
- // We only need a declaration (not a definition) of the type - so use whatever
- // we would otherwise do to get a type for a pointee. (forward declarations in
- // limited debug info, full definitions (if the type definition is available)
- // in unlimited debug info)
- if (const auto *TD = dyn_cast<TypeDecl>(D))
- return getOrCreateType(CGM.getContext().getTypeDeclType(TD),
- getOrCreateFile(TD->getLocation()));
- auto I = DeclCache.find(D->getCanonicalDecl());
-
- if (I != DeclCache.end()) {
- auto N = I->second;
- if (auto *GVE = dyn_cast_or_null<llvm::DIGlobalVariableExpression>(N))
- return GVE->getVariable();
- return dyn_cast_or_null<llvm::DINode>(N);
- }
-
- // No definition for now. Emit a forward definition that might be
- // merged with a potential upcoming definition.
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- return getFunctionForwardDeclaration(FD);
- else if (const auto *VD = dyn_cast<VarDecl>(D))
- return getGlobalVariableForwardDeclaration(VD);
-
- return nullptr;
-}
-
-llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
- if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
- return nullptr;
-
- const auto *FD = dyn_cast<FunctionDecl>(D);
- if (!FD)
- return nullptr;
-
- // Setup context.
- auto *S = getDeclContextDescriptor(D);
-
- auto MI = SPCache.find(FD->getCanonicalDecl());
- if (MI == SPCache.end()) {
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD->getCanonicalDecl())) {
- return CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()),
- cast<llvm::DICompositeType>(S));
- }
- }
- if (MI != SPCache.end()) {
- auto *SP = dyn_cast_or_null<llvm::DISubprogram>(MI->second);
- if (SP && !SP->isDefinition())
- return SP;
- }
-
- for (auto NextFD : FD->redecls()) {
- auto MI = SPCache.find(NextFD->getCanonicalDecl());
- if (MI != SPCache.end()) {
- auto *SP = dyn_cast_or_null<llvm::DISubprogram>(MI->second);
- if (SP && !SP->isDefinition())
- return SP;
- }
- }
- return nullptr;
-}
-
-// getOrCreateFunctionType - Construct type. If it is a c++ method, include
-// implicit parameter "this".
-llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
- QualType FnType,
- llvm::DIFile *F) {
- if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
- // Create fake but valid subroutine type. Otherwise -verify would fail, and
- // subprogram DIE will miss DW_AT_decl_file and DW_AT_decl_line fields.
- return DBuilder.createSubroutineType(DBuilder.getOrCreateTypeArray(None));
-
- if (const auto *Method = dyn_cast<CXXMethodDecl>(D))
- return getOrCreateMethodType(Method, F);
-
- const auto *FTy = FnType->getAs<FunctionType>();
- CallingConv CC = FTy ? FTy->getCallConv() : CallingConv::CC_C;
-
- if (const auto *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
- // Add "self" and "_cmd"
- SmallVector<llvm::Metadata *, 16> Elts;
-
- // First element is always return type. For 'void' functions it is NULL.
- QualType ResultTy = OMethod->getReturnType();
-
- // Replace the instancetype keyword with the actual type.
- if (ResultTy == CGM.getContext().getObjCInstanceType())
- ResultTy = CGM.getContext().getPointerType(
- QualType(OMethod->getClassInterface()->getTypeForDecl(), 0));
-
- Elts.push_back(getOrCreateType(ResultTy, F));
- // "self" pointer is always first argument.
- QualType SelfDeclTy;
- if (auto *SelfDecl = OMethod->getSelfDecl())
- SelfDeclTy = SelfDecl->getType();
- else if (auto *FPT = dyn_cast<FunctionProtoType>(FnType))
- if (FPT->getNumParams() > 1)
- SelfDeclTy = FPT->getParamType(0);
- if (!SelfDeclTy.isNull())
- Elts.push_back(
- CreateSelfType(SelfDeclTy, getOrCreateType(SelfDeclTy, F)));
- // "_cmd" pointer is always second argument.
- Elts.push_back(DBuilder.createArtificialType(
- getOrCreateType(CGM.getContext().getObjCSelType(), F)));
- // Get rest of the arguments.
- for (const auto *PI : OMethod->parameters())
- Elts.push_back(getOrCreateType(PI->getType(), F));
- // Variadic methods need a special marker at the end of the type list.
- if (OMethod->isVariadic())
- Elts.push_back(DBuilder.createUnspecifiedParameter());
-
- llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
- return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
- getDwarfCC(CC));
- }
-
- // Handle variadic function types; they need an additional
- // unspecified parameter.
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isVariadic()) {
- SmallVector<llvm::Metadata *, 16> EltTys;
- EltTys.push_back(getOrCreateType(FD->getReturnType(), F));
- if (const auto *FPT = dyn_cast<FunctionProtoType>(FnType))
- for (QualType ParamType : FPT->param_types())
- EltTys.push_back(getOrCreateType(ParamType, F));
- EltTys.push_back(DBuilder.createUnspecifiedParameter());
- llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
- return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
- getDwarfCC(CC));
- }
-
- return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F));
-}
-
-void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
- SourceLocation ScopeLoc, QualType FnType,
- llvm::Function *Fn, bool CurFuncIsThunk,
- CGBuilderTy &Builder) {
-
- StringRef Name;
- StringRef LinkageName;
-
- FnBeginRegionCount.push_back(LexicalBlockStack.size());
-
- const Decl *D = GD.getDecl();
- bool HasDecl = (D != nullptr);
-
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
- llvm::DIFile *Unit = getOrCreateFile(Loc);
- llvm::DIScope *FDContext = Unit;
- llvm::DINodeArray TParamsArray;
- if (!HasDecl) {
- // Use llvm function name.
- LinkageName = Fn->getName();
- } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- // If there is a subprogram for this function available then use it.
- auto FI = SPCache.find(FD->getCanonicalDecl());
- if (FI != SPCache.end()) {
- auto *SP = dyn_cast_or_null<llvm::DISubprogram>(FI->second);
- if (SP && SP->isDefinition()) {
- LexicalBlockStack.emplace_back(SP);
- RegionMap[D].reset(SP);
- return;
- }
- }
- collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext,
- TParamsArray, Flags);
- } else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D)) {
- Name = getObjCMethodName(OMD);
- Flags |= llvm::DINode::FlagPrototyped;
- } else {
- // Use llvm function name.
- Name = Fn->getName();
- Flags |= llvm::DINode::FlagPrototyped;
- }
- if (Name.startswith("\01"))
- Name = Name.substr(1);
-
- if (!HasDecl || D->isImplicit() || D->hasAttr<ArtificialAttr>()) {
- Flags |= llvm::DINode::FlagArtificial;
- // Artificial functions should not silently reuse CurLoc.
- CurLoc = SourceLocation();
- }
-
- if (CurFuncIsThunk)
- Flags |= llvm::DINode::FlagThunk;
-
- if (Fn->hasLocalLinkage())
- SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
- if (CGM.getLangOpts().Optimize)
- SPFlags |= llvm::DISubprogram::SPFlagOptimized;
-
- llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs();
- llvm::DISubprogram::DISPFlags SPFlagsForDef =
- SPFlags | llvm::DISubprogram::SPFlagDefinition;
-
- unsigned LineNo = getLineNumber(Loc);
- unsigned ScopeLine = getLineNumber(ScopeLoc);
-
- // FIXME: The function declaration we're constructing here is mostly reusing
- // declarations from CXXMethodDecl and not constructing new ones for arbitrary
- // FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
- // all subprograms instead of the actual context since subprogram definitions
- // are emitted as CU level entities by the backend.
- llvm::DISubprogram *SP = DBuilder.createFunction(
- FDContext, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef,
- SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D));
- Fn->setSubprogram(SP);
- // We might get here with a VarDecl in the case we're generating
- // code for the initialization of globals. Do not record these decls
- // as they will overwrite the actual VarDecl Decl in the cache.
- if (HasDecl && isa<FunctionDecl>(D))
- DeclCache[D->getCanonicalDecl()].reset(SP);
-
- if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
- // Starting with DWARF V5 method declarations are emitted as children of
- // the interface type.
- if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
- const ObjCInterfaceDecl *ID = OMD->getClassInterface();
- QualType QTy(ID->getTypeForDecl(), 0);
- auto It = TypeCache.find(QTy.getAsOpaquePtr());
- if (It != TypeCache.end()) {
- llvm::DICompositeType *InterfaceDecl =
- cast<llvm::DICompositeType>(It->second);
- llvm::DISubprogram *FD = DBuilder.createFunction(
- InterfaceDecl, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
- TParamsArray.get());
- DBuilder.finalizeSubprogram(FD);
- ObjCMethodCache[ID].push_back(FD);
- }
- }
- }
-
- // Push the function onto the lexical block stack.
- LexicalBlockStack.emplace_back(SP);
-
- if (HasDecl)
- RegionMap[D].reset(SP);
-}
-
-void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
- QualType FnType) {
- StringRef Name;
- StringRef LinkageName;
-
- const Decl *D = GD.getDecl();
- if (!D)
- return;
-
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- llvm::DIFile *Unit = getOrCreateFile(Loc);
- llvm::DIScope *FDContext = getDeclContextDescriptor(D);
- llvm::DINodeArray TParamsArray;
- if (isa<FunctionDecl>(D)) {
- // If there is a DISubprogram for this function available then use it.
- collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext,
- TParamsArray, Flags);
- } else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D)) {
- Name = getObjCMethodName(OMD);
- Flags |= llvm::DINode::FlagPrototyped;
- } else {
- llvm_unreachable("not a function or ObjC method");
- }
- if (!Name.empty() && Name[0] == '\01')
- Name = Name.substr(1);
-
- if (D->isImplicit()) {
- Flags |= llvm::DINode::FlagArtificial;
- // Artificial functions without a location should not silently reuse CurLoc.
- if (Loc.isInvalid())
- CurLoc = SourceLocation();
- }
- unsigned LineNo = getLineNumber(Loc);
- unsigned ScopeLine = 0;
- llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
- if (CGM.getLangOpts().Optimize)
- SPFlags |= llvm::DISubprogram::SPFlagOptimized;
-
- DBuilder.retainType(DBuilder.createFunction(
- FDContext, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
- TParamsArray.get(), getFunctionDeclaration(D)));
-}
-
-void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
- const auto *FD = cast<FunctionDecl>(GD.getDecl());
- // If there is a subprogram for this function available then use it.
- auto FI = SPCache.find(FD->getCanonicalDecl());
- llvm::DISubprogram *SP = nullptr;
- if (FI != SPCache.end())
- SP = dyn_cast_or_null<llvm::DISubprogram>(FI->second);
- if (!SP || !SP->isDefinition())
- SP = getFunctionStub(GD);
- FnBeginRegionCount.push_back(LexicalBlockStack.size());
- LexicalBlockStack.emplace_back(SP);
- setInlinedAt(Builder.getCurrentDebugLocation());
- EmitLocation(Builder, FD->getLocation());
-}
-
-void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy &Builder) {
- assert(CurInlinedAt && "unbalanced inline scope stack");
- EmitFunctionEnd(Builder, nullptr);
- setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt());
-}
-
-void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
- // Update our current location
- setLocation(Loc);
-
- if (CurLoc.isInvalid() || CurLoc.isMacroID() || LexicalBlockStack.empty())
- return;
-
- llvm::MDNode *Scope = LexicalBlockStack.back();
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
- getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope, CurInlinedAt));
-}
-
-void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
- llvm::MDNode *Back = nullptr;
- if (!LexicalBlockStack.empty())
- Back = LexicalBlockStack.back().get();
- LexicalBlockStack.emplace_back(DBuilder.createLexicalBlock(
- cast<llvm::DIScope>(Back), getOrCreateFile(CurLoc), getLineNumber(CurLoc),
- getColumnNumber(CurLoc)));
-}
-
-void CGDebugInfo::AppendAddressSpaceXDeref(
- unsigned AddressSpace, SmallVectorImpl<int64_t> &Expr) const {
- Optional<unsigned> DWARFAddressSpace =
- CGM.getTarget().getDWARFAddressSpace(AddressSpace);
- if (!DWARFAddressSpace)
- return;
-
- Expr.push_back(llvm::dwarf::DW_OP_constu);
- Expr.push_back(DWARFAddressSpace.getValue());
- Expr.push_back(llvm::dwarf::DW_OP_swap);
- Expr.push_back(llvm::dwarf::DW_OP_xderef);
-}
-
-void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder,
- SourceLocation Loc) {
- // Set our current location.
- setLocation(Loc);
-
- // Emit a line table change for the current location inside the new scope.
- Builder.SetCurrentDebugLocation(
- llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc),
- LexicalBlockStack.back(), CurInlinedAt));
-
- if (DebugKind <= codegenoptions::DebugLineTablesOnly)
- return;
-
- // Create a new lexical block and push it on the stack.
- CreateLexicalBlock(Loc);
-}
-
-void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
- SourceLocation Loc) {
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
-
- // Provide an entry in the line table for the end of the block.
- EmitLocation(Builder, Loc);
-
- if (DebugKind <= codegenoptions::DebugLineTablesOnly)
- return;
-
- LexicalBlockStack.pop_back();
-}
-
-void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) {
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
- unsigned RCount = FnBeginRegionCount.back();
- assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
-
- // Pop all regions for this function.
- while (LexicalBlockStack.size() != RCount) {
- // Provide an entry in the line table for the end of the block.
- EmitLocation(Builder, CurLoc);
- LexicalBlockStack.pop_back();
- }
- FnBeginRegionCount.pop_back();
-
- if (Fn && Fn->getSubprogram())
- DBuilder.finalizeSubprogram(Fn->getSubprogram());
-}
-
-CGDebugInfo::BlockByRefType
-CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
- uint64_t *XOffset) {
- SmallVector<llvm::Metadata *, 5> EltTys;
- QualType FType;
- uint64_t FieldSize, FieldOffset;
- uint32_t FieldAlign;
-
- llvm::DIFile *Unit = getOrCreateFile(VD->getLocation());
- QualType Type = VD->getType();
-
- FieldOffset = 0;
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset));
- FType = CGM.getContext().IntTy;
- EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
-
- bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD);
- if (HasCopyAndDispose) {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(
- CreateMemberType(Unit, FType, "__copy_helper", &FieldOffset));
- EltTys.push_back(
- CreateMemberType(Unit, FType, "__destroy_helper", &FieldOffset));
- }
- bool HasByrefExtendedLayout;
- Qualifiers::ObjCLifetime Lifetime;
- if (CGM.getContext().getByrefLifetime(Type, Lifetime,
- HasByrefExtendedLayout) &&
- HasByrefExtendedLayout) {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(
- CreateMemberType(Unit, FType, "__byref_variable_layout", &FieldOffset));
- }
-
- CharUnits Align = CGM.getContext().getDeclAlign(VD);
- if (Align > CGM.getContext().toCharUnitsFromBits(
- CGM.getTarget().getPointerAlign(0))) {
- CharUnits FieldOffsetInBytes =
- CGM.getContext().toCharUnitsFromBits(FieldOffset);
- CharUnits AlignedOffsetInBytes = FieldOffsetInBytes.alignTo(Align);
- CharUnits NumPaddingBytes = AlignedOffsetInBytes - FieldOffsetInBytes;
-
- if (NumPaddingBytes.isPositive()) {
- llvm::APInt pad(32, NumPaddingBytes.getQuantity());
- FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
- pad, ArrayType::Normal, 0);
- EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
- }
- }
-
- FType = Type;
- llvm::DIType *WrappedTy = getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().toBits(Align);
-
- *XOffset = FieldOffset;
- llvm::DIType *FieldTy = DBuilder.createMemberType(
- Unit, VD->getName(), Unit, 0, FieldSize, FieldAlign, FieldOffset,
- llvm::DINode::FlagZero, WrappedTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
- return {DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0,
- llvm::DINode::FlagZero, nullptr, Elements),
- WrappedTy};
-}
-
-llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
- llvm::Value *Storage,
- llvm::Optional<unsigned> ArgNo,
- CGBuilderTy &Builder) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
- if (VD->hasAttr<NoDebugAttr>())
- return nullptr;
-
- bool Unwritten =
- VD->isImplicit() || (isa<Decl>(VD->getDeclContext()) &&
- cast<Decl>(VD->getDeclContext())->isImplicit());
- llvm::DIFile *Unit = nullptr;
- if (!Unwritten)
- Unit = getOrCreateFile(VD->getLocation());
- llvm::DIType *Ty;
- uint64_t XOffset = 0;
- if (VD->hasAttr<BlocksAttr>())
- Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType;
- else
- Ty = getOrCreateType(VD->getType(), Unit);
-
- // If there is no debug info for this type then do not emit debug info
- // for this variable.
- if (!Ty)
- return nullptr;
-
- // Get location information.
- unsigned Line = 0;
- unsigned Column = 0;
- if (!Unwritten) {
- Line = getLineNumber(VD->getLocation());
- Column = getColumnNumber(VD->getLocation());
- }
- SmallVector<int64_t, 13> Expr;
- llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- if (VD->isImplicit())
- Flags |= llvm::DINode::FlagArtificial;
-
- auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
-
- unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType());
- AppendAddressSpaceXDeref(AddressSpace, Expr);
-
- // If this is implicit parameter of CXXThis or ObjCSelf kind, then give it an
- // object pointer flag.
- if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD)) {
- if (IPD->getParameterKind() == ImplicitParamDecl::CXXThis ||
- IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
- Flags |= llvm::DINode::FlagObjectPointer;
- }
-
- // Note: Older versions of clang used to emit byval references with an extra
- // DW_OP_deref, because they referenced the IR arg directly instead of
- // referencing an alloca. Newer versions of LLVM don't treat allocas
- // differently from other function arguments when used in a dbg.declare.
- auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
- StringRef Name = VD->getName();
- if (!Name.empty()) {
- if (VD->hasAttr<BlocksAttr>()) {
- // Here, we need an offset *into* the alloca.
- CharUnits offset = CharUnits::fromQuantity(32);
- Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
- // offset of __forwarding field
- offset = CGM.getContext().toCharUnitsFromBits(
- CGM.getTarget().getPointerWidth(0));
- Expr.push_back(offset.getQuantity());
- Expr.push_back(llvm::dwarf::DW_OP_deref);
- Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
- // offset of x field
- offset = CGM.getContext().toCharUnitsFromBits(XOffset);
- Expr.push_back(offset.getQuantity());
- }
- } else if (const auto *RT = dyn_cast<RecordType>(VD->getType())) {
- // If VD is an anonymous union then Storage represents value for
- // all union fields.
- const RecordDecl *RD = RT->getDecl();
- if (RD->isUnion() && RD->isAnonymousStructOrUnion()) {
- // GDB has trouble finding local variables in anonymous unions, so we emit
- // artificial local variables for each of the members.
- //
- // FIXME: Remove this code as soon as GDB supports this.
- // The debug info verifier in LLVM operates based on the assumption that a
- // variable has the same size as its storage and we had to disable the
- // check for artificial variables.
- for (const auto *Field : RD->fields()) {
- llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit);
- StringRef FieldName = Field->getName();
-
- // Ignore unnamed fields. Do not ignore unnamed records.
- if (FieldName.empty() && !isa<RecordType>(Field->getType()))
- continue;
-
- // Use VarDecl's Tag, Scope and Line number.
- auto FieldAlign = getDeclAlignIfRequired(Field, CGM.getContext());
- auto *D = DBuilder.createAutoVariable(
- Scope, FieldName, Unit, Line, FieldTy, CGM.getLangOpts().Optimize,
- Flags | llvm::DINode::FlagArtificial, FieldAlign);
-
- // Insert an llvm.dbg.declare into the current block.
- DBuilder.insertDeclare(
- Storage, D, DBuilder.createExpression(Expr),
- llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
- Builder.GetInsertBlock());
- }
- }
- }
-
- // Create the descriptor for the variable.
- auto *D = ArgNo ? DBuilder.createParameterVariable(
- Scope, Name, *ArgNo, Unit, Line, Ty,
- CGM.getLangOpts().Optimize, Flags)
- : DBuilder.createAutoVariable(Scope, Name, Unit, Line, Ty,
- CGM.getLangOpts().Optimize,
- Flags, Align);
-
- // Insert an llvm.dbg.declare into the current block.
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
- llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
- Builder.GetInsertBlock());
-
- return D;
-}
-
-llvm::DILocalVariable *
-CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage,
- CGBuilderTy &Builder) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- return EmitDeclare(VD, Storage, llvm::None, Builder);
-}
-
-llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy,
- llvm::DIType *Ty) {
- llvm::DIType *CachedTy = getTypeOrNull(QualTy);
- if (CachedTy)
- Ty = CachedTy;
- return DBuilder.createObjectPointerType(Ty);
-}
-
-void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
- const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
-
- if (Builder.GetInsertBlock() == nullptr)
- return;
- if (VD->hasAttr<NoDebugAttr>())
- return;
-
- bool isByRef = VD->hasAttr<BlocksAttr>();
-
- uint64_t XOffset = 0;
- llvm::DIFile *Unit = getOrCreateFile(VD->getLocation());
- llvm::DIType *Ty;
- if (isByRef)
- Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType;
- else
- Ty = getOrCreateType(VD->getType(), Unit);
-
- // Self is passed along as an implicit non-arg variable in a
- // block. Mark it as the object pointer.
- if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD))
- if (IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
- Ty = CreateSelfType(VD->getType(), Ty);
-
- // Get location information.
- unsigned Line = getLineNumber(VD->getLocation());
- unsigned Column = getColumnNumber(VD->getLocation());
-
- const llvm::DataLayout &target = CGM.getDataLayout();
-
- CharUnits offset = CharUnits::fromQuantity(
- target.getStructLayout(blockInfo.StructureType)
- ->getElementOffset(blockInfo.getCapture(VD).getIndex()));
-
- SmallVector<int64_t, 9> addr;
- addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
- addr.push_back(offset.getQuantity());
- if (isByRef) {
- addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
- // offset of __forwarding field
- offset =
- CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0));
- addr.push_back(offset.getQuantity());
- addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
- // offset of x field
- offset = CGM.getContext().toCharUnitsFromBits(XOffset);
- addr.push_back(offset.getQuantity());
- }
-
- // Create the descriptor for the variable.
- auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
- auto *D = DBuilder.createAutoVariable(
- cast<llvm::DILocalScope>(LexicalBlockStack.back()), VD->getName(), Unit,
- Line, Ty, false, llvm::DINode::FlagZero, Align);
-
- // Insert an llvm.dbg.declare into the current block.
- auto DL =
- llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt);
- auto *Expr = DBuilder.createExpression(addr);
- if (InsertPoint)
- DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint);
- else
- DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock());
-}
-
-void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
- unsigned ArgNo,
- CGBuilderTy &Builder) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- EmitDeclare(VD, AI, ArgNo, Builder);
-}
-
-namespace {
-struct BlockLayoutChunk {
- uint64_t OffsetInBits;
- const BlockDecl::Capture *Capture;
-};
-bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
- return l.OffsetInBits < r.OffsetInBits;
-}
-} // namespace
-
-void CGDebugInfo::collectDefaultFieldsForBlockLiteralDeclare(
- const CGBlockInfo &Block, const ASTContext &Context, SourceLocation Loc,
- const llvm::StructLayout &BlockLayout, llvm::DIFile *Unit,
- SmallVectorImpl<llvm::Metadata *> &Fields) {
- // Blocks in OpenCL have unique constraints which make the standard fields
- // redundant while requiring size and align fields for enqueue_kernel. See
- // initializeForBlockHeader in CGBlocks.cpp
- if (CGM.getLangOpts().OpenCL) {
- Fields.push_back(createFieldType("__size", Context.IntTy, Loc, AS_public,
- BlockLayout.getElementOffsetInBits(0),
- Unit, Unit));
- Fields.push_back(createFieldType("__align", Context.IntTy, Loc, AS_public,
- BlockLayout.getElementOffsetInBits(1),
- Unit, Unit));
- } else {
- Fields.push_back(createFieldType("__isa", Context.VoidPtrTy, Loc, AS_public,
- BlockLayout.getElementOffsetInBits(0),
- Unit, Unit));
- Fields.push_back(createFieldType("__flags", Context.IntTy, Loc, AS_public,
- BlockLayout.getElementOffsetInBits(1),
- Unit, Unit));
- Fields.push_back(
- createFieldType("__reserved", Context.IntTy, Loc, AS_public,
- BlockLayout.getElementOffsetInBits(2), Unit, Unit));
- auto *FnTy = Block.getBlockExpr()->getFunctionType();
- auto FnPtrType = CGM.getContext().getPointerType(FnTy->desugar());
- Fields.push_back(createFieldType("__FuncPtr", FnPtrType, Loc, AS_public,
- BlockLayout.getElementOffsetInBits(3),
- Unit, Unit));
- Fields.push_back(createFieldType(
- "__descriptor",
- Context.getPointerType(Block.NeedsCopyDispose
- ? Context.getBlockDescriptorExtendedType()
- : Context.getBlockDescriptorType()),
- Loc, AS_public, BlockLayout.getElementOffsetInBits(4), Unit, Unit));
- }
-}
-
-void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- StringRef Name,
- unsigned ArgNo,
- llvm::AllocaInst *Alloca,
- CGBuilderTy &Builder) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- ASTContext &C = CGM.getContext();
- const BlockDecl *blockDecl = block.getBlockDecl();
-
- // Collect some general information about the block's location.
- SourceLocation loc = blockDecl->getCaretLocation();
- llvm::DIFile *tunit = getOrCreateFile(loc);
- unsigned line = getLineNumber(loc);
- unsigned column = getColumnNumber(loc);
-
- // Build the debug-info type for the block literal.
- getDeclContextDescriptor(blockDecl);
-
- const llvm::StructLayout *blockLayout =
- CGM.getDataLayout().getStructLayout(block.StructureType);
-
- SmallVector<llvm::Metadata *, 16> fields;
- collectDefaultFieldsForBlockLiteralDeclare(block, C, loc, *blockLayout, tunit,
- fields);
-
- // We want to sort the captures by offset, not because DWARF
- // requires this, but because we're paranoid about debuggers.
- SmallVector<BlockLayoutChunk, 8> chunks;
-
- // 'this' capture.
- if (blockDecl->capturesCXXThis()) {
- BlockLayoutChunk chunk;
- chunk.OffsetInBits =
- blockLayout->getElementOffsetInBits(block.CXXThisIndex);
- chunk.Capture = nullptr;
- chunks.push_back(chunk);
- }
-
- // Variable captures.
- for (const auto &capture : blockDecl->captures()) {
- const VarDecl *variable = capture.getVariable();
- const CGBlockInfo::Capture &captureInfo = block.getCapture(variable);
-
- // Ignore constant captures.
- if (captureInfo.isConstant())
- continue;
-
- BlockLayoutChunk chunk;
- chunk.OffsetInBits =
- blockLayout->getElementOffsetInBits(captureInfo.getIndex());
- chunk.Capture = &capture;
- chunks.push_back(chunk);
- }
-
- // Sort by offset.
- llvm::array_pod_sort(chunks.begin(), chunks.end());
-
- for (const BlockLayoutChunk &Chunk : chunks) {
- uint64_t offsetInBits = Chunk.OffsetInBits;
- const BlockDecl::Capture *capture = Chunk.Capture;
-
- // If we have a null capture, this must be the C++ 'this' capture.
- if (!capture) {
- QualType type;
- if (auto *Method =
- cast_or_null<CXXMethodDecl>(blockDecl->getNonClosureContext()))
- type = Method->getThisType();
- else if (auto *RDecl = dyn_cast<CXXRecordDecl>(blockDecl->getParent()))
- type = QualType(RDecl->getTypeForDecl(), 0);
- else
- llvm_unreachable("unexpected block declcontext");
-
- fields.push_back(createFieldType("this", type, loc, AS_public,
- offsetInBits, tunit, tunit));
- continue;
- }
-
- const VarDecl *variable = capture->getVariable();
- StringRef name = variable->getName();
-
- llvm::DIType *fieldType;
- if (capture->isByRef()) {
- TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy);
- auto Align = PtrInfo.AlignIsRequired ? PtrInfo.Align : 0;
- // FIXME: This recomputes the layout of the BlockByRefWrapper.
- uint64_t xoffset;
- fieldType =
- EmitTypeForVarWithBlocksAttr(variable, &xoffset).BlockByRefWrapper;
- fieldType = DBuilder.createPointerType(fieldType, PtrInfo.Width);
- fieldType = DBuilder.createMemberType(tunit, name, tunit, line,
- PtrInfo.Width, Align, offsetInBits,
- llvm::DINode::FlagZero, fieldType);
- } else {
- auto Align = getDeclAlignIfRequired(variable, CGM.getContext());
- fieldType = createFieldType(name, variable->getType(), loc, AS_public,
- offsetInBits, Align, tunit, tunit);
- }
- fields.push_back(fieldType);
- }
-
- SmallString<36> typeName;
- llvm::raw_svector_ostream(typeName)
- << "__block_literal_" << CGM.getUniqueBlockCount();
-
- llvm::DINodeArray fieldsArray = DBuilder.getOrCreateArray(fields);
-
- llvm::DIType *type =
- DBuilder.createStructType(tunit, typeName.str(), tunit, line,
- CGM.getContext().toBits(block.BlockSize), 0,
- llvm::DINode::FlagZero, nullptr, fieldsArray);
- type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
-
- // Get overall information about the block.
- llvm::DINode::DIFlags flags = llvm::DINode::FlagArtificial;
- auto *scope = cast<llvm::DILocalScope>(LexicalBlockStack.back());
-
- // Create the descriptor for the parameter.
- auto *debugVar = DBuilder.createParameterVariable(
- scope, Name, ArgNo, tunit, line, type, CGM.getLangOpts().Optimize, flags);
-
- // Insert an llvm.dbg.declare into the current block.
- DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(),
- llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
- Builder.GetInsertBlock());
-}
-
-llvm::DIDerivedType *
-CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
- if (!D->isStaticDataMember())
- return nullptr;
-
- auto MI = StaticDataMemberCache.find(D->getCanonicalDecl());
- if (MI != StaticDataMemberCache.end()) {
- assert(MI->second && "Static data member declaration should still exist");
- return MI->second;
- }
-
- // If the member wasn't found in the cache, lazily construct and add it to the
- // type (used when a limited form of the type is emitted).
- auto DC = D->getDeclContext();
- auto *Ctxt = cast<llvm::DICompositeType>(getDeclContextDescriptor(D));
- return CreateRecordStaticField(D, Ctxt, cast<RecordDecl>(DC));
-}
-
-llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls(
- const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo,
- StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext) {
- llvm::DIGlobalVariableExpression *GVE = nullptr;
-
- for (const auto *Field : RD->fields()) {
- llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit);
- StringRef FieldName = Field->getName();
-
- // Ignore unnamed fields, but recurse into anonymous records.
- if (FieldName.empty()) {
- if (const auto *RT = dyn_cast<RecordType>(Field->getType()))
- GVE = CollectAnonRecordDecls(RT->getDecl(), Unit, LineNo, LinkageName,
- Var, DContext);
- continue;
- }
- // Use VarDecl's Tag, Scope and Line number.
- GVE = DBuilder.createGlobalVariableExpression(
- DContext, FieldName, LinkageName, Unit, LineNo, FieldTy,
- Var->hasLocalLinkage());
- Var->addDebugInfo(GVE);
- }
- return GVE;
-}
-
-void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- const VarDecl *D) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- if (D->hasAttr<NoDebugAttr>())
- return;
-
- // If we already created a DIGlobalVariable for this declaration, just attach
- // it to the llvm::GlobalVariable.
- auto Cached = DeclCache.find(D->getCanonicalDecl());
- if (Cached != DeclCache.end())
- return Var->addDebugInfo(
- cast<llvm::DIGlobalVariableExpression>(Cached->second));
-
- // Create global variable debug descriptor.
- llvm::DIFile *Unit = nullptr;
- llvm::DIScope *DContext = nullptr;
- unsigned LineNo;
- StringRef DeclName, LinkageName;
- QualType T;
- llvm::MDTuple *TemplateParameters = nullptr;
- collectVarDeclProps(D, Unit, LineNo, T, DeclName, LinkageName,
- TemplateParameters, DContext);
-
- // Attempt to store one global variable for the declaration - even if we
- // emit a lot of fields.
- llvm::DIGlobalVariableExpression *GVE = nullptr;
-
- // If this is an anonymous union then we'll want to emit a global
- // variable for each member of the anonymous union so that it's possible
- // to find the name of any field in the union.
- if (T->isUnionType() && DeclName.empty()) {
- const RecordDecl *RD = T->castAs<RecordType>()->getDecl();
- assert(RD->isAnonymousStructOrUnion() &&
- "unnamed non-anonymous struct or union?");
- GVE = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
- } else {
- auto Align = getDeclAlignIfRequired(D, CGM.getContext());
-
- SmallVector<int64_t, 4> Expr;
- unsigned AddressSpace =
- CGM.getContext().getTargetAddressSpace(D->getType());
- AppendAddressSpaceXDeref(AddressSpace, Expr);
-
- GVE = DBuilder.createGlobalVariableExpression(
- DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasLocalLinkage(),
- Expr.empty() ? nullptr : DBuilder.createExpression(Expr),
- getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters,
- Align);
- Var->addDebugInfo(GVE);
- }
- DeclCache[D->getCanonicalDecl()].reset(GVE);
-}
-
-void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
- assert(DebugKind >= codegenoptions::LimitedDebugInfo);
- if (VD->hasAttr<NoDebugAttr>())
- return;
- auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
- // Create the descriptor for the variable.
- llvm::DIFile *Unit = getOrCreateFile(VD->getLocation());
- StringRef Name = VD->getName();
- llvm::DIType *Ty = getOrCreateType(VD->getType(), Unit);
- if (const auto *ECD = dyn_cast<EnumConstantDecl>(VD)) {
- const auto *ED = cast<EnumDecl>(ECD->getDeclContext());
- assert(isa<EnumType>(ED->getTypeForDecl()) && "Enum without EnumType?");
- Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit);
- }
- // Do not use global variables for enums.
- //
- // FIXME: why not?
- if (Ty->getTag() == llvm::dwarf::DW_TAG_enumeration_type)
- return;
- // Do not emit separate definitions for function local const/statics.
- if (isa<FunctionDecl>(VD->getDeclContext()))
- return;
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- auto *VarD = cast<VarDecl>(VD);
- if (VarD->isStaticDataMember()) {
- auto *RD = cast<RecordDecl>(VarD->getDeclContext());
- getDeclContextDescriptor(VarD);
- // Ensure that the type is retained even though it's otherwise unreferenced.
- //
- // FIXME: This is probably unnecessary, since Ty should reference RD
- // through its scope.
- RetainedTypes.push_back(
- CGM.getContext().getRecordType(RD).getAsOpaquePtr());
- return;
- }
-
- llvm::DIScope *DContext = getDeclContextDescriptor(VD);
-
- auto &GV = DeclCache[VD];
- if (GV)
- return;
- llvm::DIExpression *InitExpr = nullptr;
- if (CGM.getContext().getTypeSize(VD->getType()) <= 64) {
- // FIXME: Add a representation for integer constants wider than 64 bits.
- if (Init.isInt())
- InitExpr =
- DBuilder.createConstantValueExpression(Init.getInt().getExtValue());
- else if (Init.isFloat())
- InitExpr = DBuilder.createConstantValueExpression(
- Init.getFloat().bitcastToAPInt().getZExtValue());
- }
-
- llvm::MDTuple *TemplateParameters = nullptr;
-
- if (isa<VarTemplateSpecializationDecl>(VD))
- if (VarD) {
- llvm::DINodeArray parameterNodes = CollectVarTemplateParams(VarD, &*Unit);
- TemplateParameters = parameterNodes.get();
- }
-
- GV.reset(DBuilder.createGlobalVariableExpression(
- DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty,
- true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD),
- TemplateParameters, Align));
-}
-
-llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
- if (!LexicalBlockStack.empty())
- return LexicalBlockStack.back();
- llvm::DIScope *Mod = getParentModuleOrNull(D);
- return getContextDescriptor(D, Mod ? Mod : TheCU);
-}
-
-void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
- return;
- const NamespaceDecl *NSDecl = UD.getNominatedNamespace();
- if (!NSDecl->isAnonymousNamespace() ||
- CGM.getCodeGenOpts().DebugExplicitImport) {
- auto Loc = UD.getLocation();
- DBuilder.createImportedModule(
- getCurrentContextDescriptor(cast<Decl>(UD.getDeclContext())),
- getOrCreateNamespace(NSDecl), getOrCreateFile(Loc), getLineNumber(Loc));
- }
-}
-
-void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
- return;
- assert(UD.shadow_size() &&
- "We shouldn't be codegening an invalid UsingDecl containing no decls");
- // Emitting one decl is sufficient - debuggers can detect that this is an
- // overloaded name & provide lookup for all the overloads.
- const UsingShadowDecl &USD = **UD.shadow_begin();
-
- // FIXME: Skip functions with undeduced auto return type for now since we
- // don't currently have the plumbing for separate declarations & definitions
- // of free functions and mismatched types (auto in the declaration, concrete
- // return type in the definition)
- if (const auto *FD = dyn_cast<FunctionDecl>(USD.getUnderlyingDecl()))
- if (const auto *AT =
- FD->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
- if (AT->getDeducedType().isNull())
- return;
- if (llvm::DINode *Target =
- getDeclarationOrDefinition(USD.getUnderlyingDecl())) {
- auto Loc = USD.getLocation();
- DBuilder.createImportedDeclaration(
- getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
- getOrCreateFile(Loc), getLineNumber(Loc));
- }
-}
-
-void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
- if (CGM.getCodeGenOpts().getDebuggerTuning() != llvm::DebuggerKind::LLDB)
- return;
- if (Module *M = ID.getImportedModule()) {
- auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
- auto Loc = ID.getLocation();
- DBuilder.createImportedDeclaration(
- getCurrentContextDescriptor(cast<Decl>(ID.getDeclContext())),
- getOrCreateModuleRef(Info, DebugTypeExtRefs), getOrCreateFile(Loc),
- getLineNumber(Loc));
- }
-}
-
-llvm::DIImportedEntity *
-CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
- return nullptr;
- auto &VH = NamespaceAliasCache[&NA];
- if (VH)
- return cast<llvm::DIImportedEntity>(VH);
- llvm::DIImportedEntity *R;
- auto Loc = NA.getLocation();
- if (const auto *Underlying =
- dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
- // This could cache & dedup here rather than relying on metadata deduping.
- R = DBuilder.createImportedDeclaration(
- getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
- EmitNamespaceAlias(*Underlying), getOrCreateFile(Loc),
- getLineNumber(Loc), NA.getName());
- else
- R = DBuilder.createImportedDeclaration(
- getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
- getOrCreateNamespace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
- getOrCreateFile(Loc), getLineNumber(Loc), NA.getName());
- VH.reset(R);
- return R;
-}
-
-llvm::DINamespace *
-CGDebugInfo::getOrCreateNamespace(const NamespaceDecl *NSDecl) {
- // Don't canonicalize the NamespaceDecl here: The DINamespace will be uniqued
- // if necessary, and this way multiple declarations of the same namespace in
- // different parent modules stay distinct.
- auto I = NamespaceCache.find(NSDecl);
- if (I != NamespaceCache.end())
- return cast<llvm::DINamespace>(I->second);
-
- llvm::DIScope *Context = getDeclContextDescriptor(NSDecl);
- // Don't trust the context if it is a DIModule (see comment above).
- llvm::DINamespace *NS =
- DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline());
- NamespaceCache[NSDecl].reset(NS);
- return NS;
-}
-
-void CGDebugInfo::setDwoId(uint64_t Signature) {
- assert(TheCU && "no main compile unit");
- TheCU->setDWOId(Signature);
-}
-
-void CGDebugInfo::finalize() {
- // Creating types might create further types - invalidating the current
- // element and the size(), so don't cache/reference them.
- for (size_t i = 0; i != ObjCInterfaceCache.size(); ++i) {
- ObjCInterfaceCacheEntry E = ObjCInterfaceCache[i];
- llvm::DIType *Ty = E.Type->getDecl()->getDefinition()
- ? CreateTypeDefinition(E.Type, E.Unit)
- : E.Decl;
- DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty);
- }
-
- if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
- // Add methods to interface.
- for (const auto &P : ObjCMethodCache) {
- if (P.second.empty())
- continue;
-
- QualType QTy(P.first->getTypeForDecl(), 0);
- auto It = TypeCache.find(QTy.getAsOpaquePtr());
- assert(It != TypeCache.end());
-
- llvm::DICompositeType *InterfaceDecl =
- cast<llvm::DICompositeType>(It->second);
-
- SmallVector<llvm::Metadata *, 16> EltTys;
- auto CurrenetElts = InterfaceDecl->getElements();
- EltTys.append(CurrenetElts.begin(), CurrenetElts.end());
- for (auto &MD : P.second)
- EltTys.push_back(MD);
- llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
- DBuilder.replaceArrays(InterfaceDecl, Elements);
- }
- }
-
- for (const auto &P : ReplaceMap) {
- assert(P.second);
- auto *Ty = cast<llvm::DIType>(P.second);
- assert(Ty->isForwardDecl());
-
- auto It = TypeCache.find(P.first);
- assert(It != TypeCache.end());
- assert(It->second);
-
- DBuilder.replaceTemporary(llvm::TempDIType(Ty),
- cast<llvm::DIType>(It->second));
- }
-
- for (const auto &P : FwdDeclReplaceMap) {
- assert(P.second);
- llvm::TempMDNode FwdDecl(cast<llvm::MDNode>(P.second));
- llvm::Metadata *Repl;
-
- auto It = DeclCache.find(P.first);
- // If there has been no definition for the declaration, call RAUW
- // with ourselves, that will destroy the temporary MDNode and
- // replace it with a standard one, avoiding leaking memory.
- if (It == DeclCache.end())
- Repl = P.second;
- else
- Repl = It->second;
-
- if (auto *GVE = dyn_cast_or_null<llvm::DIGlobalVariableExpression>(Repl))
- Repl = GVE->getVariable();
- DBuilder.replaceTemporary(std::move(FwdDecl), cast<llvm::MDNode>(Repl));
- }
-
- // We keep our own list of retained types, because we need to look
- // up the final type in the type cache.
- for (auto &RT : RetainedTypes)
- if (auto MD = TypeCache[RT])
- DBuilder.retainType(cast<llvm::DIType>(MD));
-
- DBuilder.finalize();
-}
-
-void CGDebugInfo::EmitExplicitCastType(QualType Ty) {
- if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
- return;
-
- if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
- // Don't ignore in case of explicit cast where it is referenced indirectly.
- DBuilder.retainType(DieTy);
-}
-
-llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) {
- if (LexicalBlockStack.empty())
- return llvm::DebugLoc();
-
- llvm::MDNode *Scope = LexicalBlockStack.back();
- return llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc), Scope);
-}
-
-llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const {
- // Call site-related attributes are only useful in optimized programs, and
- // when there's a possibility of debugging backtraces.
- if (!CGM.getLangOpts().Optimize || DebugKind == codegenoptions::NoDebugInfo ||
- DebugKind == codegenoptions::LocTrackingOnly)
- return llvm::DINode::FlagZero;
-
- // Call site-related attributes are available in DWARF v5. Some debuggers,
- // while not fully DWARF v5-compliant, may accept these attributes as if they
- // were part of DWARF v4.
- bool SupportsDWARFv4Ext =
- CGM.getCodeGenOpts().DwarfVersion == 4 &&
- CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB;
- if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5)
- return llvm::DINode::FlagZero;
-
- return llvm::DINode::FlagAllCallsDescribed;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h b/gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h
deleted file mode 100644
index 031e40b9dde..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h
+++ /dev/null
@@ -1,754 +0,0 @@
-//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the source-level debug info generator for llvm translation.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGDEBUGINFO_H
-#define LLVM_CLANG_LIB_CODEGEN_CGDEBUGINFO_H
-
-#include "CGBuilder.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeOrdering.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/IR/DIBuilder.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/ValueHandle.h"
-#include "llvm/Support/Allocator.h"
-
-namespace llvm {
-class MDNode;
-}
-
-namespace clang {
-class ClassTemplateSpecializationDecl;
-class GlobalDecl;
-class ModuleMap;
-class ObjCInterfaceDecl;
-class ObjCIvarDecl;
-class UsingDecl;
-class VarDecl;
-
-namespace CodeGen {
-class CodeGenModule;
-class CodeGenFunction;
-class CGBlockInfo;
-
-/// This class gathers all debug information during compilation and is
-/// responsible for emitting to llvm globals or pass directly to the
-/// backend.
-class CGDebugInfo {
- friend class ApplyDebugLocation;
- friend class SaveAndRestoreLocation;
- CodeGenModule &CGM;
- const codegenoptions::DebugInfoKind DebugKind;
- bool DebugTypeExtRefs;
- llvm::DIBuilder DBuilder;
- llvm::DICompileUnit *TheCU = nullptr;
- ModuleMap *ClangModuleMap = nullptr;
- ExternalASTSource::ASTSourceDescriptor PCHDescriptor;
- SourceLocation CurLoc;
- llvm::MDNode *CurInlinedAt = nullptr;
- llvm::DIType *VTablePtrType = nullptr;
- llvm::DIType *ClassTy = nullptr;
- llvm::DICompositeType *ObjTy = nullptr;
- llvm::DIType *SelTy = nullptr;
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- llvm::DIType *SingletonId = nullptr;
-#include "clang/Basic/OpenCLImageTypes.def"
- llvm::DIType *OCLSamplerDITy = nullptr;
- llvm::DIType *OCLEventDITy = nullptr;
- llvm::DIType *OCLClkEventDITy = nullptr;
- llvm::DIType *OCLQueueDITy = nullptr;
- llvm::DIType *OCLNDRangeDITy = nullptr;
- llvm::DIType *OCLReserveIDDITy = nullptr;
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- llvm::DIType *Id##Ty = nullptr;
-#include "clang/Basic/OpenCLExtensionTypes.def"
-
- /// Cache of previously constructed Types.
- llvm::DenseMap<const void *, llvm::TrackingMDRef> TypeCache;
-
- llvm::SmallDenseMap<llvm::StringRef, llvm::StringRef> DebugPrefixMap;
-
- /// Cache that maps VLA types to size expressions for that type,
- /// represented by instantiated Metadata nodes.
- llvm::SmallDenseMap<QualType, llvm::Metadata *> SizeExprCache;
-
- struct ObjCInterfaceCacheEntry {
- const ObjCInterfaceType *Type;
- llvm::DIType *Decl;
- llvm::DIFile *Unit;
- ObjCInterfaceCacheEntry(const ObjCInterfaceType *Type, llvm::DIType *Decl,
- llvm::DIFile *Unit)
- : Type(Type), Decl(Decl), Unit(Unit) {}
- };
-
- /// Cache of previously constructed interfaces which may change.
- llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache;
-
- /// Cache of forward declarations for methods belonging to the interface.
- llvm::DenseMap<const ObjCInterfaceDecl *, std::vector<llvm::DISubprogram *>>
- ObjCMethodCache;
-
- /// Cache of references to clang modules and precompiled headers.
- llvm::DenseMap<const Module *, llvm::TrackingMDRef> ModuleCache;
-
- /// List of interfaces we want to keep even if orphaned.
- std::vector<void *> RetainedTypes;
-
- /// Cache of forward declared types to RAUW at the end of compilation.
- std::vector<std::pair<const TagType *, llvm::TrackingMDRef>> ReplaceMap;
-
- /// Cache of replaceable forward declarations (functions and
- /// variables) to RAUW at the end of compilation.
- std::vector<std::pair<const DeclaratorDecl *, llvm::TrackingMDRef>>
- FwdDeclReplaceMap;
-
- /// Keep track of our current nested lexical block.
- std::vector<llvm::TypedTrackingMDRef<llvm::DIScope>> LexicalBlockStack;
- llvm::DenseMap<const Decl *, llvm::TrackingMDRef> RegionMap;
- /// Keep track of LexicalBlockStack counter at the beginning of a
- /// function. This is used to pop unbalanced regions at the end of a
- /// function.
- std::vector<unsigned> FnBeginRegionCount;
-
- /// This is a storage for names that are constructed on demand. For
- /// example, C++ destructors, C++ operators etc..
- llvm::BumpPtrAllocator DebugInfoNames;
- StringRef CWDName;
-
- llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache;
- llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache;
- /// Cache declarations relevant to DW_TAG_imported_declarations (C++
- /// using declarations) that aren't covered by other more specific caches.
- llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache;
- llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NamespaceCache;
- llvm::DenseMap<const NamespaceAliasDecl *, llvm::TrackingMDRef>
- NamespaceAliasCache;
- llvm::DenseMap<const Decl *, llvm::TypedTrackingMDRef<llvm::DIDerivedType>>
- StaticDataMemberCache;
-
- /// Helper functions for getOrCreateType.
- /// @{
- /// Currently the checksum of an interface includes the number of
- /// ivars and property accessors.
- llvm::DIType *CreateType(const BuiltinType *Ty);
- llvm::DIType *CreateType(const ComplexType *Ty);
- llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg);
- llvm::DIType *CreateType(const TypedefType *Ty, llvm::DIFile *Fg);
- llvm::DIType *CreateType(const TemplateSpecializationType *Ty,
- llvm::DIFile *Fg);
- llvm::DIType *CreateType(const ObjCObjectPointerType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F);
- /// Get structure or union type.
- llvm::DIType *CreateType(const RecordType *Tyg);
- llvm::DIType *CreateTypeDefinition(const RecordType *Ty);
- llvm::DICompositeType *CreateLimitedType(const RecordType *Ty);
- void CollectContainingType(const CXXRecordDecl *RD,
- llvm::DICompositeType *CT);
- /// Get Objective-C interface type.
- llvm::DIType *CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateTypeDefinition(const ObjCInterfaceType *Ty,
- llvm::DIFile *F);
- /// Get Objective-C object type.
- llvm::DIType *CreateType(const ObjCObjectType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const ObjCTypeParamType *Ty, llvm::DIFile *Unit);
-
- llvm::DIType *CreateType(const VectorType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const ArrayType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const LValueReferenceType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit);
- llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F);
- llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F);
- /// Get enumeration type.
- llvm::DIType *CreateEnumType(const EnumType *Ty);
- llvm::DIType *CreateTypeDefinition(const EnumType *Ty);
- /// Look up the completed type for a self pointer in the TypeCache and
- /// create a copy of it with the ObjectPointer and Artificial flags
- /// set. If the type is not cached, a new one is created. This should
- /// never happen though, since creating a type for the implicit self
- /// argument implies that we already parsed the interface definition
- /// and the ivar declarations in the implementation.
- llvm::DIType *CreateSelfType(const QualType &QualTy, llvm::DIType *Ty);
- /// @}
-
- /// Get the type from the cache or return null type if it doesn't
- /// exist.
- llvm::DIType *getTypeOrNull(const QualType);
- /// Return the debug type for a C++ method.
- /// \arg CXXMethodDecl is of FunctionType. This function type is
- /// not updated to include implicit \c this pointer. Use this routine
- /// to get a method type which includes \c this pointer.
- llvm::DISubroutineType *getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile *F);
- llvm::DISubroutineType *
- getOrCreateInstanceMethodType(QualType ThisPtr, const FunctionProtoType *Func,
- llvm::DIFile *Unit);
- llvm::DISubroutineType *
- getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F);
- /// \return debug info descriptor for vtable.
- llvm::DIType *getOrCreateVTablePtrType(llvm::DIFile *F);
-
- /// \return namespace descriptor for the given namespace decl.
- llvm::DINamespace *getOrCreateNamespace(const NamespaceDecl *N);
- llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty,
- QualType PointeeTy, llvm::DIFile *F);
- llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache);
-
- /// A helper function to create a subprogram for a single member
- /// function GlobalDecl.
- llvm::DISubprogram *CreateCXXMemberFunction(const CXXMethodDecl *Method,
- llvm::DIFile *F,
- llvm::DIType *RecordTy);
-
- /// A helper function to collect debug info for C++ member
- /// functions. This is used while creating debug info entry for a
- /// Record.
- void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DIFile *F,
- SmallVectorImpl<llvm::Metadata *> &E,
- llvm::DIType *T);
-
- /// A helper function to collect debug info for C++ base
- /// classes. This is used while creating debug info entry for a
- /// Record.
- void CollectCXXBases(const CXXRecordDecl *Decl, llvm::DIFile *F,
- SmallVectorImpl<llvm::Metadata *> &EltTys,
- llvm::DIType *RecordTy);
-
- /// Helper function for CollectCXXBases.
- /// Adds debug info entries for types in Bases that are not in SeenTypes.
- void CollectCXXBasesAux(
- const CXXRecordDecl *RD, llvm::DIFile *Unit,
- SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy,
- const CXXRecordDecl::base_class_const_range &Bases,
- llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> &SeenTypes,
- llvm::DINode::DIFlags StartingFlags);
-
- /// A helper function to collect template parameters.
- llvm::DINodeArray CollectTemplateParams(const TemplateParameterList *TPList,
- ArrayRef<TemplateArgument> TAList,
- llvm::DIFile *Unit);
- /// A helper function to collect debug info for function template
- /// parameters.
- llvm::DINodeArray CollectFunctionTemplateParams(const FunctionDecl *FD,
- llvm::DIFile *Unit);
-
- /// A helper function to collect debug info for function template
- /// parameters.
- llvm::DINodeArray CollectVarTemplateParams(const VarDecl *VD,
- llvm::DIFile *Unit);
-
- /// A helper function to collect debug info for template
- /// parameters.
- llvm::DINodeArray
- CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS,
- llvm::DIFile *F);
-
- llvm::DIType *createFieldType(StringRef name, QualType type,
- SourceLocation loc, AccessSpecifier AS,
- uint64_t offsetInBits, uint32_t AlignInBits,
- llvm::DIFile *tunit, llvm::DIScope *scope,
- const RecordDecl *RD = nullptr);
-
- llvm::DIType *createFieldType(StringRef name, QualType type,
- SourceLocation loc, AccessSpecifier AS,
- uint64_t offsetInBits, llvm::DIFile *tunit,
- llvm::DIScope *scope,
- const RecordDecl *RD = nullptr) {
- return createFieldType(name, type, loc, AS, offsetInBits, 0, tunit, scope,
- RD);
- }
-
- /// Create new bit field member.
- llvm::DIType *createBitFieldType(const FieldDecl *BitFieldDecl,
- llvm::DIScope *RecordTy,
- const RecordDecl *RD);
-
- /// Helpers for collecting fields of a record.
- /// @{
- void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
- SmallVectorImpl<llvm::Metadata *> &E,
- llvm::DIType *RecordTy);
- llvm::DIDerivedType *CreateRecordStaticField(const VarDecl *Var,
- llvm::DIType *RecordTy,
- const RecordDecl *RD);
- void CollectRecordNormalField(const FieldDecl *Field, uint64_t OffsetInBits,
- llvm::DIFile *F,
- SmallVectorImpl<llvm::Metadata *> &E,
- llvm::DIType *RecordTy, const RecordDecl *RD);
- void CollectRecordNestedType(const TypeDecl *RD,
- SmallVectorImpl<llvm::Metadata *> &E);
- void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile *F,
- SmallVectorImpl<llvm::Metadata *> &E,
- llvm::DICompositeType *RecordTy);
-
- /// If the C++ class has vtable info then insert appropriate debug
- /// info entry in EltTys vector.
- void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile *F,
- SmallVectorImpl<llvm::Metadata *> &EltTys,
- llvm::DICompositeType *RecordTy);
- /// @}
-
- /// Create a new lexical block node and push it on the stack.
- void CreateLexicalBlock(SourceLocation Loc);
-
- /// If target-specific LLVM \p AddressSpace directly maps to target-specific
- /// DWARF address space, appends extended dereferencing mechanism to complex
- /// expression \p Expr. Otherwise, does nothing.
- ///
- /// Extended dereferencing mechanism is has the following format:
- /// DW_OP_constu <DWARF Address Space> DW_OP_swap DW_OP_xderef
- void AppendAddressSpaceXDeref(unsigned AddressSpace,
- SmallVectorImpl<int64_t> &Expr) const;
-
- /// A helper function to collect debug info for the default elements of a
- /// block.
- ///
- /// \returns The next available field offset after the default elements.
- uint64_t collectDefaultElementTypesForBlockPointer(
- const BlockPointerType *Ty, llvm::DIFile *Unit,
- llvm::DIDerivedType *DescTy, unsigned LineNo,
- SmallVectorImpl<llvm::Metadata *> &EltTys);
-
- /// A helper function to collect debug info for the default fields of a
- /// block.
- void collectDefaultFieldsForBlockLiteralDeclare(
- const CGBlockInfo &Block, const ASTContext &Context, SourceLocation Loc,
- const llvm::StructLayout &BlockLayout, llvm::DIFile *Unit,
- SmallVectorImpl<llvm::Metadata *> &Fields);
-
-public:
- CGDebugInfo(CodeGenModule &CGM);
- ~CGDebugInfo();
-
- void finalize();
-
- /// Remap a given path with the current debug prefix map
- std::string remapDIPath(StringRef) const;
-
- /// Register VLA size expression debug node with the qualified type.
- void registerVLASizeExpression(QualType Ty, llvm::Metadata *SizeExpr) {
- SizeExprCache[Ty] = SizeExpr;
- }
-
- /// Module debugging: Support for building PCMs.
- /// @{
- /// Set the main CU's DwoId field to \p Signature.
- void setDwoId(uint64_t Signature);
-
- /// When generating debug information for a clang module or
- /// precompiled header, this module map will be used to determine
- /// the module of origin of each Decl.
- void setModuleMap(ModuleMap &MMap) { ClangModuleMap = &MMap; }
-
- /// When generating debug information for a clang module or
- /// precompiled header, this module map will be used to determine
- /// the module of origin of each Decl.
- void setPCHDescriptor(ExternalASTSource::ASTSourceDescriptor PCH) {
- PCHDescriptor = PCH;
- }
- /// @}
-
- /// Update the current source location. If \arg loc is invalid it is
- /// ignored.
- void setLocation(SourceLocation Loc);
-
- /// Return the current source location. This does not necessarily correspond
- /// to the IRBuilder's current DebugLoc.
- SourceLocation getLocation() const { return CurLoc; }
-
- /// Update the current inline scope. All subsequent calls to \p EmitLocation
- /// will create a location with this inlinedAt field.
- void setInlinedAt(llvm::MDNode *InlinedAt) { CurInlinedAt = InlinedAt; }
-
- /// \return the current inline scope.
- llvm::MDNode *getInlinedAt() const { return CurInlinedAt; }
-
- // Converts a SourceLocation to a DebugLoc
- llvm::DebugLoc SourceLocToDebugLoc(SourceLocation Loc);
-
- /// Emit metadata to indicate a change in line/column information in
- /// the source file. If the location is invalid, the previous
- /// location will be reused.
- void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc);
-
- /// Emit a call to llvm.dbg.function.start to indicate
- /// start of a new function.
- /// \param Loc The location of the function header.
- /// \param ScopeLoc The location of the function body.
- void EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
- SourceLocation ScopeLoc, QualType FnType,
- llvm::Function *Fn, bool CurFnIsThunk,
- CGBuilderTy &Builder);
-
- /// Start a new scope for an inlined function.
- void EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD);
- /// End an inlined function scope.
- void EmitInlineFunctionEnd(CGBuilderTy &Builder);
-
- /// Emit debug info for a function declaration.
- void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType);
-
- /// Constructs the debug code for exiting a function.
- void EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn);
-
- /// Emit metadata to indicate the beginning of a new lexical block
- /// and push the block onto the stack.
- void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc);
-
- /// Emit metadata to indicate the end of a new lexical block and pop
- /// the current block.
- void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc);
-
- /// Emit call to \c llvm.dbg.declare for an automatic variable
- /// declaration.
- /// Returns a pointer to the DILocalVariable associated with the
- /// llvm.dbg.declare, or nullptr otherwise.
- llvm::DILocalVariable *EmitDeclareOfAutoVariable(const VarDecl *Decl,
- llvm::Value *AI,
- CGBuilderTy &Builder);
-
- /// Emit call to \c llvm.dbg.declare for an imported variable
- /// declaration in a block.
- void EmitDeclareOfBlockDeclRefVariable(
- const VarDecl *variable, llvm::Value *storage, CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint = nullptr);
-
- /// Emit call to \c llvm.dbg.declare for an argument variable
- /// declaration.
- void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
- unsigned ArgNo, CGBuilderTy &Builder);
-
- /// Emit call to \c llvm.dbg.declare for the block-literal argument
- /// to a block invocation function.
- void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- StringRef Name, unsigned ArgNo,
- llvm::AllocaInst *LocalAddr,
- CGBuilderTy &Builder);
-
- /// Emit information about a global variable.
- void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
-
- /// Emit a constant global variable's debug info.
- void EmitGlobalVariable(const ValueDecl *VD, const APValue &Init);
-
- /// Emit C++ using directive.
- void EmitUsingDirective(const UsingDirectiveDecl &UD);
-
- /// Emit the type explicitly casted to.
- void EmitExplicitCastType(QualType Ty);
-
- /// Emit C++ using declaration.
- void EmitUsingDecl(const UsingDecl &UD);
-
- /// Emit an @import declaration.
- void EmitImportDecl(const ImportDecl &ID);
-
- /// Emit C++ namespace alias.
- llvm::DIImportedEntity *EmitNamespaceAlias(const NamespaceAliasDecl &NA);
-
- /// Emit record type's standalone debug info.
- llvm::DIType *getOrCreateRecordType(QualType Ty, SourceLocation L);
-
- /// Emit an Objective-C interface type standalone debug info.
- llvm::DIType *getOrCreateInterfaceType(QualType Ty, SourceLocation Loc);
-
- /// Emit standalone debug info for a type.
- llvm::DIType *getOrCreateStandaloneType(QualType Ty, SourceLocation Loc);
-
- void completeType(const EnumDecl *ED);
- void completeType(const RecordDecl *RD);
- void completeRequiredType(const RecordDecl *RD);
- void completeClassData(const RecordDecl *RD);
- void completeClass(const RecordDecl *RD);
-
- void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
- void completeUnusedClass(const CXXRecordDecl &D);
-
- /// Create debug info for a macro defined by a #define directive or a macro
- /// undefined by a #undef directive.
- llvm::DIMacro *CreateMacro(llvm::DIMacroFile *Parent, unsigned MType,
- SourceLocation LineLoc, StringRef Name,
- StringRef Value);
-
- /// Create debug info for a file referenced by an #include directive.
- llvm::DIMacroFile *CreateTempMacroFile(llvm::DIMacroFile *Parent,
- SourceLocation LineLoc,
- SourceLocation FileLoc);
-
-private:
- /// Emit call to llvm.dbg.declare for a variable declaration.
- /// Returns a pointer to the DILocalVariable associated with the
- /// llvm.dbg.declare, or nullptr otherwise.
- llvm::DILocalVariable *EmitDeclare(const VarDecl *decl, llvm::Value *AI,
- llvm::Optional<unsigned> ArgNo,
- CGBuilderTy &Builder);
-
- struct BlockByRefType {
- /// The wrapper struct used inside the __block_literal struct.
- llvm::DIType *BlockByRefWrapper;
- /// The type as it appears in the source code.
- llvm::DIType *WrappedType;
- };
-
- /// Build up structure info for the byref. See \a BuildByRefType.
- BlockByRefType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
- uint64_t *OffSet);
-
- /// Get context info for the DeclContext of \p Decl.
- llvm::DIScope *getDeclContextDescriptor(const Decl *D);
- /// Get context info for a given DeclContext \p Decl.
- llvm::DIScope *getContextDescriptor(const Decl *Context,
- llvm::DIScope *Default);
-
- llvm::DIScope *getCurrentContextDescriptor(const Decl *Decl);
-
- /// Create a forward decl for a RecordType in a given context.
- llvm::DICompositeType *getOrCreateRecordFwdDecl(const RecordType *,
- llvm::DIScope *);
-
- /// Return current directory name.
- StringRef getCurrentDirname();
-
- /// Create new compile unit.
- void CreateCompileUnit();
-
- /// Compute the file checksum debug info for input file ID.
- Optional<llvm::DIFile::ChecksumKind>
- computeChecksum(FileID FID, SmallString<32> &Checksum) const;
-
- /// Get the source of the given file ID.
- Optional<StringRef> getSource(const SourceManager &SM, FileID FID);
-
- /// Convenience function to get the file debug info descriptor for the input
- /// location.
- llvm::DIFile *getOrCreateFile(SourceLocation Loc);
-
- /// Create a file debug info descriptor for a source file.
- llvm::DIFile *
- createFile(StringRef FileName,
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo,
- Optional<StringRef> Source);
-
- /// Get the type from the cache or create a new type if necessary.
- llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg);
-
- /// Get a reference to a clang module. If \p CreateSkeletonCU is true,
- /// this also creates a split dwarf skeleton compile unit.
- llvm::DIModule *
- getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod,
- bool CreateSkeletonCU);
-
- /// DebugTypeExtRefs: If \p D originated in a clang module, return it.
- llvm::DIModule *getParentModuleOrNull(const Decl *D);
-
- /// Get the type from the cache or create a new partial type if
- /// necessary.
- llvm::DICompositeType *getOrCreateLimitedType(const RecordType *Ty,
- llvm::DIFile *F);
-
- /// Create type metadata for a source language type.
- llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg);
-
- /// Create new member and increase Offset by FType's size.
- llvm::DIType *CreateMemberType(llvm::DIFile *Unit, QualType FType,
- StringRef Name, uint64_t *Offset);
-
- /// Retrieve the DIDescriptor, if any, for the canonical form of this
- /// declaration.
- llvm::DINode *getDeclarationOrDefinition(const Decl *D);
-
- /// \return debug info descriptor to describe method
- /// declaration for the given method definition.
- llvm::DISubprogram *getFunctionDeclaration(const Decl *D);
-
- /// \return debug info descriptor to describe in-class static data
- /// member declaration for the given out-of-class definition. If D
- /// is an out-of-class definition of a static data member of a
- /// class, find its corresponding in-class declaration.
- llvm::DIDerivedType *
- getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
-
- /// Helper that either creates a forward declaration or a stub.
- llvm::DISubprogram *getFunctionFwdDeclOrStub(GlobalDecl GD, bool Stub);
-
- /// Create a subprogram describing the forward declaration
- /// represented in the given FunctionDecl wrapped in a GlobalDecl.
- llvm::DISubprogram *getFunctionForwardDeclaration(GlobalDecl GD);
-
- /// Create a DISubprogram describing the function
- /// represented in the given FunctionDecl wrapped in a GlobalDecl.
- llvm::DISubprogram *getFunctionStub(GlobalDecl GD);
-
- /// Create a global variable describing the forward declaration
- /// represented in the given VarDecl.
- llvm::DIGlobalVariable *
- getGlobalVariableForwardDeclaration(const VarDecl *VD);
-
- /// Return a global variable that represents one of the collection of global
- /// variables created for an anonmyous union.
- ///
- /// Recursively collect all of the member fields of a global
- /// anonymous decl and create static variables for them. The first
- /// time this is called it needs to be on a union and then from
- /// there we can have additional unnamed fields.
- llvm::DIGlobalVariableExpression *
- CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile *Unit,
- unsigned LineNo, StringRef LinkageName,
- llvm::GlobalVariable *Var, llvm::DIScope *DContext);
-
-
- /// Return flags which enable debug info emission for call sites, provided
- /// that it is supported and enabled.
- llvm::DINode::DIFlags getCallSiteRelatedAttrs() const;
-
- /// Get the printing policy for producing names for debug info.
- PrintingPolicy getPrintingPolicy() const;
-
- /// Get function name for the given FunctionDecl. If the name is
- /// constructed on demand (e.g., C++ destructor) then the name is
- /// stored on the side.
- StringRef getFunctionName(const FunctionDecl *FD);
-
- /// Returns the unmangled name of an Objective-C method.
- /// This is the display name for the debugging info.
- StringRef getObjCMethodName(const ObjCMethodDecl *FD);
-
- /// Return selector name. This is used for debugging
- /// info.
- StringRef getSelectorName(Selector S);
-
- /// Get class name including template argument list.
- StringRef getClassName(const RecordDecl *RD);
-
- /// Get the vtable name for the given class.
- StringRef getVTableName(const CXXRecordDecl *Decl);
-
- /// Get line number for the location. If location is invalid
- /// then use current location.
- unsigned getLineNumber(SourceLocation Loc);
-
- /// Get column number for the location. If location is
- /// invalid then use current location.
- /// \param Force Assume DebugColumnInfo option is true.
- unsigned getColumnNumber(SourceLocation Loc, bool Force = false);
-
- /// Collect various properties of a FunctionDecl.
- /// \param GD A GlobalDecl whose getDecl() must return a FunctionDecl.
- void collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
- StringRef &Name, StringRef &LinkageName,
- llvm::DIScope *&FDContext,
- llvm::DINodeArray &TParamsArray,
- llvm::DINode::DIFlags &Flags);
-
- /// Collect various properties of a VarDecl.
- void collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit,
- unsigned &LineNo, QualType &T, StringRef &Name,
- StringRef &LinkageName,
- llvm::MDTuple *&TemplateParameters,
- llvm::DIScope *&VDContext);
-
- /// Allocate a copy of \p A using the DebugInfoNames allocator
- /// and return a reference to it. If multiple arguments are given the strings
- /// are concatenated.
- StringRef internString(StringRef A, StringRef B = StringRef()) {
- char *Data = DebugInfoNames.Allocate<char>(A.size() + B.size());
- if (!A.empty())
- std::memcpy(Data, A.data(), A.size());
- if (!B.empty())
- std::memcpy(Data + A.size(), B.data(), B.size());
- return StringRef(Data, A.size() + B.size());
- }
-};
-
-/// A scoped helper to set the current debug location to the specified
-/// location or preferred location of the specified Expr.
-class ApplyDebugLocation {
-private:
- void init(SourceLocation TemporaryLocation, bool DefaultToEmpty = false);
- ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty,
- SourceLocation TemporaryLocation);
-
- llvm::DebugLoc OriginalLocation;
- CodeGenFunction *CGF;
-
-public:
- /// Set the location to the (valid) TemporaryLocation.
- ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation);
- ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E);
- ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc);
- ApplyDebugLocation(ApplyDebugLocation &&Other) : CGF(Other.CGF) {
- Other.CGF = nullptr;
- }
-
- ~ApplyDebugLocation();
-
- /// Apply TemporaryLocation if it is valid. Otherwise switch
- /// to an artificial debug location that has a valid scope, but no
- /// line information.
- ///
- /// Artificial locations are useful when emitting compiler-generated
- /// helper functions that have no source location associated with
- /// them. The DWARF specification allows the compiler to use the
- /// special line number 0 to indicate code that can not be
- /// attributed to any source location. Note that passing an empty
- /// SourceLocation to CGDebugInfo::setLocation() will result in the
- /// last valid location being reused.
- static ApplyDebugLocation CreateArtificial(CodeGenFunction &CGF) {
- return ApplyDebugLocation(CGF, false, SourceLocation());
- }
- /// Apply TemporaryLocation if it is valid. Otherwise switch
- /// to an artificial debug location that has a valid scope, but no
- /// line information.
- static ApplyDebugLocation
- CreateDefaultArtificial(CodeGenFunction &CGF,
- SourceLocation TemporaryLocation) {
- return ApplyDebugLocation(CGF, false, TemporaryLocation);
- }
-
- /// Set the IRBuilder to not attach debug locations. Note that
- /// passing an empty SourceLocation to \a CGDebugInfo::setLocation()
- /// will result in the last valid location being reused. Note that
- /// all instructions that do not have a location at the beginning of
- /// a function are counted towards to function prologue.
- static ApplyDebugLocation CreateEmpty(CodeGenFunction &CGF) {
- return ApplyDebugLocation(CGF, true, SourceLocation());
- }
-};
-
-/// A scoped helper to set the current debug location to an inlined location.
-class ApplyInlineDebugLocation {
- SourceLocation SavedLocation;
- CodeGenFunction *CGF;
-
-public:
- /// Set up the CodeGenFunction's DebugInfo to produce inline locations for the
- /// function \p InlinedFn. The current debug location becomes the inlined call
- /// site of the inlined function.
- ApplyInlineDebugLocation(CodeGenFunction &CGF, GlobalDecl InlinedFn);
- /// Restore everything back to the original state.
- ~ApplyInlineDebugLocation();
-};
-
-} // namespace CodeGen
-} // namespace clang
-
-#endif // LLVM_CLANG_LIB_CODEGEN_CGDEBUGINFO_H
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGDecl.cpp
deleted file mode 100644
index 790a8df3d7e..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGDecl.cpp
+++ /dev/null
@@ -1,2426 +0,0 @@
-//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Decl nodes as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGBlocks.h"
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-#include "CGDebugInfo.h"
-#include "CGOpenCLRuntime.h"
-#include "CGOpenMPRuntime.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "ConstantEmitter.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclOpenMP.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/Analysis/ValueTracking.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Type.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-void CodeGenFunction::EmitDecl(const Decl &D) {
- switch (D.getKind()) {
- case Decl::BuiltinTemplate:
- case Decl::TranslationUnit:
- case Decl::ExternCContext:
- case Decl::Namespace:
- case Decl::UnresolvedUsingTypename:
- case Decl::ClassTemplateSpecialization:
- case Decl::ClassTemplatePartialSpecialization:
- case Decl::VarTemplateSpecialization:
- case Decl::VarTemplatePartialSpecialization:
- case Decl::TemplateTypeParm:
- case Decl::UnresolvedUsingValue:
- case Decl::NonTypeTemplateParm:
- case Decl::CXXDeductionGuide:
- case Decl::CXXMethod:
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::Field:
- case Decl::MSProperty:
- case Decl::IndirectField:
- case Decl::ObjCIvar:
- case Decl::ObjCAtDefsField:
- case Decl::ParmVar:
- case Decl::ImplicitParam:
- case Decl::ClassTemplate:
- case Decl::VarTemplate:
- case Decl::FunctionTemplate:
- case Decl::TypeAliasTemplate:
- case Decl::TemplateTemplateParm:
- case Decl::ObjCMethod:
- case Decl::ObjCCategory:
- case Decl::ObjCProtocol:
- case Decl::ObjCInterface:
- case Decl::ObjCCategoryImpl:
- case Decl::ObjCImplementation:
- case Decl::ObjCProperty:
- case Decl::ObjCCompatibleAlias:
- case Decl::PragmaComment:
- case Decl::PragmaDetectMismatch:
- case Decl::AccessSpec:
- case Decl::LinkageSpec:
- case Decl::Export:
- case Decl::ObjCPropertyImpl:
- case Decl::FileScopeAsm:
- case Decl::Friend:
- case Decl::FriendTemplate:
- case Decl::Block:
- case Decl::Captured:
- case Decl::ClassScopeFunctionSpecialization:
- case Decl::UsingShadow:
- case Decl::ConstructorUsingShadow:
- case Decl::ObjCTypeParam:
- case Decl::Binding:
- llvm_unreachable("Declaration should not be in declstmts!");
- case Decl::Function: // void X();
- case Decl::Record: // struct/union/class X;
- case Decl::Enum: // enum X;
- case Decl::EnumConstant: // enum ? { X = ? }
- case Decl::CXXRecord: // struct/union/class X; [C++]
- case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
- case Decl::Label: // __label__ x;
- case Decl::Import:
- case Decl::OMPThreadPrivate:
- case Decl::OMPCapturedExpr:
- case Decl::OMPRequires:
- case Decl::Empty:
- // None of these decls require codegen support.
- return;
-
- case Decl::NamespaceAlias:
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitNamespaceAlias(cast<NamespaceAliasDecl>(D));
- return;
- case Decl::Using: // using X; [C++]
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitUsingDecl(cast<UsingDecl>(D));
- return;
- case Decl::UsingPack:
- for (auto *Using : cast<UsingPackDecl>(D).expansions())
- EmitDecl(*Using);
- return;
- case Decl::UsingDirective: // using namespace X; [C++]
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitUsingDirective(cast<UsingDirectiveDecl>(D));
- return;
- case Decl::Var:
- case Decl::Decomposition: {
- const VarDecl &VD = cast<VarDecl>(D);
- assert(VD.isLocalVarDecl() &&
- "Should not see file-scope variables inside a function!");
- EmitVarDecl(VD);
- if (auto *DD = dyn_cast<DecompositionDecl>(&VD))
- for (auto *B : DD->bindings())
- if (auto *HD = B->getHoldingVar())
- EmitVarDecl(*HD);
- return;
- }
-
- case Decl::OMPDeclareReduction:
- return CGM.EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(&D), this);
-
- case Decl::Typedef: // typedef int X;
- case Decl::TypeAlias: { // using X = int; [C++0x]
- const TypedefNameDecl &TD = cast<TypedefNameDecl>(D);
- QualType Ty = TD.getUnderlyingType();
-
- if (Ty->isVariablyModifiedType())
- EmitVariablyModifiedType(Ty);
- }
- }
-}
-
-/// EmitVarDecl - This method handles emission of any variable declaration
-/// inside a function, including static vars etc.
-void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
- if (D.hasExternalStorage())
- // Don't emit it now, allow it to be emitted lazily on its first use.
- return;
-
- // Some function-scope variable does not have static storage but still
- // needs to be emitted like a static variable, e.g. a function-scope
- // variable in constant address space in OpenCL.
- if (D.getStorageDuration() != SD_Automatic) {
- // Static sampler variables translated to function calls.
- if (D.getType()->isSamplerT())
- return;
-
- llvm::GlobalValue::LinkageTypes Linkage =
- CGM.getLLVMLinkageVarDefinition(&D, /*isConstant=*/false);
-
- // FIXME: We need to force the emission/use of a guard variable for
- // some variables even if we can constant-evaluate them because
- // we can't guarantee every translation unit will constant-evaluate them.
-
- return EmitStaticVarDecl(D, Linkage);
- }
-
- if (D.getType().getAddressSpace() == LangAS::opencl_local)
- return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D);
-
- assert(D.hasLocalStorage());
- return EmitAutoVarDecl(D);
-}
-
-static std::string getStaticDeclName(CodeGenModule &CGM, const VarDecl &D) {
- if (CGM.getLangOpts().CPlusPlus)
- return CGM.getMangledName(&D).str();
-
- // If this isn't C++, we don't need a mangled name, just a pretty one.
- assert(!D.isExternallyVisible() && "name shouldn't matter");
- std::string ContextName;
- const DeclContext *DC = D.getDeclContext();
- if (auto *CD = dyn_cast<CapturedDecl>(DC))
- DC = cast<DeclContext>(CD->getNonClosureContext());
- if (const auto *FD = dyn_cast<FunctionDecl>(DC))
- ContextName = CGM.getMangledName(FD);
- else if (const auto *BD = dyn_cast<BlockDecl>(DC))
- ContextName = CGM.getBlockMangledName(GlobalDecl(), BD);
- else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(DC))
- ContextName = OMD->getSelector().getAsString();
- else
- llvm_unreachable("Unknown context for static var decl");
-
- ContextName += "." + D.getNameAsString();
- return ContextName;
-}
-
-llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
- const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage) {
- // In general, we don't always emit static var decls once before we reference
- // them. It is possible to reference them before emitting the function that
- // contains them, and it is possible to emit the containing function multiple
- // times.
- if (llvm::Constant *ExistingGV = StaticLocalDeclMap[&D])
- return ExistingGV;
-
- QualType Ty = D.getType();
- assert(Ty->isConstantSizeType() && "VLAs can't be static");
-
- // Use the label if the variable is renamed with the asm-label extension.
- std::string Name;
- if (D.hasAttr<AsmLabelAttr>())
- Name = getMangledName(&D);
- else
- Name = getStaticDeclName(*this, D);
-
- llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty);
- LangAS AS = GetGlobalVarAddressSpace(&D);
- unsigned TargetAS = getContext().getTargetAddressSpace(AS);
-
- // OpenCL variables in local address space and CUDA shared
- // variables cannot have an initializer.
- llvm::Constant *Init = nullptr;
- if (Ty.getAddressSpace() == LangAS::opencl_local ||
- D.hasAttr<CUDASharedAttr>())
- Init = llvm::UndefValue::get(LTy);
- else
- Init = EmitNullConstant(Ty);
-
- llvm::GlobalVariable *GV = new llvm::GlobalVariable(
- getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name,
- nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
- GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
-
- if (supportsCOMDAT() && GV->isWeakForLinker())
- GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
-
- if (D.getTLSKind())
- setTLSMode(GV, D);
-
- setGVProperties(GV, &D);
-
- // Make sure the result is of the correct type.
- LangAS ExpectedAS = Ty.getAddressSpace();
- llvm::Constant *Addr = GV;
- if (AS != ExpectedAS) {
- Addr = getTargetCodeGenInfo().performAddrSpaceCast(
- *this, GV, AS, ExpectedAS,
- LTy->getPointerTo(getContext().getTargetAddressSpace(ExpectedAS)));
- }
-
- setStaticLocalDeclAddress(&D, Addr);
-
- // Ensure that the static local gets initialized by making sure the parent
- // function gets emitted eventually.
- const Decl *DC = cast<Decl>(D.getDeclContext());
-
- // We can't name blocks or captured statements directly, so try to emit their
- // parents.
- if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC)) {
- DC = DC->getNonClosureContext();
- // FIXME: Ensure that global blocks get emitted.
- if (!DC)
- return Addr;
- }
-
- GlobalDecl GD;
- if (const auto *CD = dyn_cast<CXXConstructorDecl>(DC))
- GD = GlobalDecl(CD, Ctor_Base);
- else if (const auto *DD = dyn_cast<CXXDestructorDecl>(DC))
- GD = GlobalDecl(DD, Dtor_Base);
- else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
- GD = GlobalDecl(FD);
- else {
- // Don't do anything for Obj-C method decls or global closures. We should
- // never defer them.
- assert(isa<ObjCMethodDecl>(DC) && "unexpected parent code decl");
- }
- if (GD.getDecl()) {
- // Disable emission of the parent function for the OpenMP device codegen.
- CGOpenMPRuntime::DisableAutoDeclareTargetRAII NoDeclTarget(*this);
- (void)GetAddrOfGlobal(GD);
- }
-
- return Addr;
-}
-
-/// hasNontrivialDestruction - Determine whether a type's destruction is
-/// non-trivial. If so, and the variable uses static initialization, we must
-/// register its destructor to run on exit.
-static bool hasNontrivialDestruction(QualType T) {
- CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
- return RD && !RD->hasTrivialDestructor();
-}
-
-/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
-/// global variable that has already been created for it. If the initializer
-/// has a different type than GV does, this may free GV and return a different
-/// one. Otherwise it just returns GV.
-llvm::GlobalVariable *
-CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
- llvm::GlobalVariable *GV) {
- ConstantEmitter emitter(*this);
- llvm::Constant *Init = emitter.tryEmitForInitializer(D);
-
- // If constant emission failed, then this should be a C++ static
- // initializer.
- if (!Init) {
- if (!getLangOpts().CPlusPlus)
- CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
- else if (HaveInsertPoint()) {
- // Since we have a static initializer, this global variable can't
- // be constant.
- GV->setConstant(false);
-
- EmitCXXGuardedInit(D, GV, /*PerformInit*/true);
- }
- return GV;
- }
-
- // The initializer may differ in type from the global. Rewrite
- // the global to match the initializer. (We have to do this
- // because some types, like unions, can't be completely represented
- // in the LLVM type system.)
- if (GV->getType()->getElementType() != Init->getType()) {
- llvm::GlobalVariable *OldGV = GV;
-
- GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
- OldGV->isConstant(),
- OldGV->getLinkage(), Init, "",
- /*InsertBefore*/ OldGV,
- OldGV->getThreadLocalMode(),
- CGM.getContext().getTargetAddressSpace(D.getType()));
- GV->setVisibility(OldGV->getVisibility());
- GV->setDSOLocal(OldGV->isDSOLocal());
- GV->setComdat(OldGV->getComdat());
-
- // Steal the name of the old global
- GV->takeName(OldGV);
-
- // Replace all uses of the old global with the new global
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
- OldGV->replaceAllUsesWith(NewPtrForOldDecl);
-
- // Erase the old global, since it is no longer used.
- OldGV->eraseFromParent();
- }
-
- GV->setConstant(CGM.isTypeConstant(D.getType(), true));
- GV->setInitializer(Init);
-
- emitter.finalize(GV);
-
- if (hasNontrivialDestruction(D.getType()) && HaveInsertPoint()) {
- // We have a constant initializer, but a nontrivial destructor. We still
- // need to perform a guarded "initialization" in order to register the
- // destructor.
- EmitCXXGuardedInit(D, GV, /*PerformInit*/false);
- }
-
- return GV;
-}
-
-void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
- llvm::GlobalValue::LinkageTypes Linkage) {
- // Check to see if we already have a global variable for this
- // declaration. This can happen when double-emitting function
- // bodies, e.g. with complete and base constructors.
- llvm::Constant *addr = CGM.getOrCreateStaticVarDecl(D, Linkage);
- CharUnits alignment = getContext().getDeclAlign(&D);
-
- // Store into LocalDeclMap before generating initializer to handle
- // circular references.
- setAddrOfLocalVar(&D, Address(addr, alignment));
-
- // We can't have a VLA here, but we can have a pointer to a VLA,
- // even though that doesn't really make any sense.
- // Make sure to evaluate VLA bounds now so that we have them for later.
- if (D.getType()->isVariablyModifiedType())
- EmitVariablyModifiedType(D.getType());
-
- // Save the type in case adding the initializer forces a type change.
- llvm::Type *expectedType = addr->getType();
-
- llvm::GlobalVariable *var =
- cast<llvm::GlobalVariable>(addr->stripPointerCasts());
-
- // CUDA's local and local static __shared__ variables should not
- // have any non-empty initializers. This is ensured by Sema.
- // Whatever initializer such variable may have when it gets here is
- // a no-op and should not be emitted.
- bool isCudaSharedVar = getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
- D.hasAttr<CUDASharedAttr>();
- // If this value has an initializer, emit it.
- if (D.getInit() && !isCudaSharedVar)
- var = AddInitializerToStaticVarDecl(D, var);
-
- var->setAlignment(alignment.getQuantity());
-
- if (D.hasAttr<AnnotateAttr>())
- CGM.AddGlobalAnnotations(&D, var);
-
- if (auto *SA = D.getAttr<PragmaClangBSSSectionAttr>())
- var->addAttribute("bss-section", SA->getName());
- if (auto *SA = D.getAttr<PragmaClangDataSectionAttr>())
- var->addAttribute("data-section", SA->getName());
- if (auto *SA = D.getAttr<PragmaClangRodataSectionAttr>())
- var->addAttribute("rodata-section", SA->getName());
-
- if (const SectionAttr *SA = D.getAttr<SectionAttr>())
- var->setSection(SA->getName());
-
- if (D.hasAttr<UsedAttr>())
- CGM.addUsedGlobal(var);
-
- // We may have to cast the constant because of the initializer
- // mismatch above.
- //
- // FIXME: It is really dangerous to store this in the map; if anyone
- // RAUW's the GV uses of this constant will be invalid.
- llvm::Constant *castedAddr =
- llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(var, expectedType);
- if (var != castedAddr)
- LocalDeclMap.find(&D)->second = Address(castedAddr, alignment);
- CGM.setStaticLocalDeclAddress(&D, castedAddr);
-
- CGM.getSanitizerMetadata()->reportGlobalToASan(var, D);
-
- // Emit global variable debug descriptor for static vars.
- CGDebugInfo *DI = getDebugInfo();
- if (DI &&
- CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) {
- DI->setLocation(D.getLocation());
- DI->EmitGlobalVariable(var, &D);
- }
-}
-
-namespace {
- struct DestroyObject final : EHScopeStack::Cleanup {
- DestroyObject(Address addr, QualType type,
- CodeGenFunction::Destroyer *destroyer,
- bool useEHCleanupForArray)
- : addr(addr), type(type), destroyer(destroyer),
- useEHCleanupForArray(useEHCleanupForArray) {}
-
- Address addr;
- QualType type;
- CodeGenFunction::Destroyer *destroyer;
- bool useEHCleanupForArray;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Don't use an EH cleanup recursively from an EH cleanup.
- bool useEHCleanupForArray =
- flags.isForNormalCleanup() && this->useEHCleanupForArray;
-
- CGF.emitDestroy(addr, type, destroyer, useEHCleanupForArray);
- }
- };
-
- template <class Derived>
- struct DestroyNRVOVariable : EHScopeStack::Cleanup {
- DestroyNRVOVariable(Address addr, llvm::Value *NRVOFlag)
- : NRVOFlag(NRVOFlag), Loc(addr) {}
-
- llvm::Value *NRVOFlag;
- Address Loc;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Along the exceptions path we always execute the dtor.
- bool NRVO = flags.isForNormalCleanup() && NRVOFlag;
-
- llvm::BasicBlock *SkipDtorBB = nullptr;
- if (NRVO) {
- // If we exited via NRVO, we skip the destructor call.
- llvm::BasicBlock *RunDtorBB = CGF.createBasicBlock("nrvo.unused");
- SkipDtorBB = CGF.createBasicBlock("nrvo.skipdtor");
- llvm::Value *DidNRVO =
- CGF.Builder.CreateFlagLoad(NRVOFlag, "nrvo.val");
- CGF.Builder.CreateCondBr(DidNRVO, SkipDtorBB, RunDtorBB);
- CGF.EmitBlock(RunDtorBB);
- }
-
- static_cast<Derived *>(this)->emitDestructorCall(CGF);
-
- if (NRVO) CGF.EmitBlock(SkipDtorBB);
- }
-
- virtual ~DestroyNRVOVariable() = default;
- };
-
- struct DestroyNRVOVariableCXX final
- : DestroyNRVOVariable<DestroyNRVOVariableCXX> {
- DestroyNRVOVariableCXX(Address addr, const CXXDestructorDecl *Dtor,
- llvm::Value *NRVOFlag)
- : DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, NRVOFlag),
- Dtor(Dtor) {}
-
- const CXXDestructorDecl *Dtor;
-
- void emitDestructorCall(CodeGenFunction &CGF) {
- CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false,
- /*Delegating=*/false, Loc);
- }
- };
-
- struct DestroyNRVOVariableC final
- : DestroyNRVOVariable<DestroyNRVOVariableC> {
- DestroyNRVOVariableC(Address addr, llvm::Value *NRVOFlag, QualType Ty)
- : DestroyNRVOVariable<DestroyNRVOVariableC>(addr, NRVOFlag), Ty(Ty) {}
-
- QualType Ty;
-
- void emitDestructorCall(CodeGenFunction &CGF) {
- CGF.destroyNonTrivialCStruct(CGF, Loc, Ty);
- }
- };
-
- struct CallStackRestore final : EHScopeStack::Cleanup {
- Address Stack;
- CallStackRestore(Address Stack) : Stack(Stack) {}
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- llvm::Value *V = CGF.Builder.CreateLoad(Stack);
- llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
- CGF.Builder.CreateCall(F, V);
- }
- };
-
- struct ExtendGCLifetime final : EHScopeStack::Cleanup {
- const VarDecl &Var;
- ExtendGCLifetime(const VarDecl *var) : Var(*var) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Compute the address of the local variable, in case it's a
- // byref or something.
- DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(&Var), false,
- Var.getType(), VK_LValue, SourceLocation());
- llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE),
- SourceLocation());
- CGF.EmitExtendGCLifetime(value);
- }
- };
-
- struct CallCleanupFunction final : EHScopeStack::Cleanup {
- llvm::Constant *CleanupFn;
- const CGFunctionInfo &FnInfo;
- const VarDecl &Var;
-
- CallCleanupFunction(llvm::Constant *CleanupFn, const CGFunctionInfo *Info,
- const VarDecl *Var)
- : CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(&Var), false,
- Var.getType(), VK_LValue, SourceLocation());
- // Compute the address of the local variable, in case it's a byref
- // or something.
- llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getPointer();
-
- // In some cases, the type of the function argument will be different from
- // the type of the pointer. An example of this is
- // void f(void* arg);
- // __attribute__((cleanup(f))) void *g;
- //
- // To fix this we insert a bitcast here.
- QualType ArgTy = FnInfo.arg_begin()->type;
- llvm::Value *Arg =
- CGF.Builder.CreateBitCast(Addr, CGF.ConvertType(ArgTy));
-
- CallArgList Args;
- Args.add(RValue::get(Arg),
- CGF.getContext().getPointerType(Var.getType()));
- auto Callee = CGCallee::forDirect(CleanupFn);
- CGF.EmitCall(FnInfo, Callee, ReturnValueSlot(), Args);
- }
- };
-} // end anonymous namespace
-
-/// EmitAutoVarWithLifetime - Does the setup required for an automatic
-/// variable with lifetime.
-static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
- Address addr,
- Qualifiers::ObjCLifetime lifetime) {
- switch (lifetime) {
- case Qualifiers::OCL_None:
- llvm_unreachable("present but none");
-
- case Qualifiers::OCL_ExplicitNone:
- // nothing to do
- break;
-
- case Qualifiers::OCL_Strong: {
- CodeGenFunction::Destroyer *destroyer =
- (var.hasAttr<ObjCPreciseLifetimeAttr>()
- ? CodeGenFunction::destroyARCStrongPrecise
- : CodeGenFunction::destroyARCStrongImprecise);
-
- CleanupKind cleanupKind = CGF.getARCCleanupKind();
- CGF.pushDestroy(cleanupKind, addr, var.getType(), destroyer,
- cleanupKind & EHCleanup);
- break;
- }
- case Qualifiers::OCL_Autoreleasing:
- // nothing to do
- break;
-
- case Qualifiers::OCL_Weak:
- // __weak objects always get EH cleanups; otherwise, exceptions
- // could cause really nasty crashes instead of mere leaks.
- CGF.pushDestroy(NormalAndEHCleanup, addr, var.getType(),
- CodeGenFunction::destroyARCWeak,
- /*useEHCleanup*/ true);
- break;
- }
-}
-
-static bool isAccessedBy(const VarDecl &var, const Stmt *s) {
- if (const Expr *e = dyn_cast<Expr>(s)) {
- // Skip the most common kinds of expressions that make
- // hierarchy-walking expensive.
- s = e = e->IgnoreParenCasts();
-
- if (const DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e))
- return (ref->getDecl() == &var);
- if (const BlockExpr *be = dyn_cast<BlockExpr>(e)) {
- const BlockDecl *block = be->getBlockDecl();
- for (const auto &I : block->captures()) {
- if (I.getVariable() == &var)
- return true;
- }
- }
- }
-
- for (const Stmt *SubStmt : s->children())
- // SubStmt might be null; as in missing decl or conditional of an if-stmt.
- if (SubStmt && isAccessedBy(var, SubStmt))
- return true;
-
- return false;
-}
-
-static bool isAccessedBy(const ValueDecl *decl, const Expr *e) {
- if (!decl) return false;
- if (!isa<VarDecl>(decl)) return false;
- const VarDecl *var = cast<VarDecl>(decl);
- return isAccessedBy(*var, e);
-}
-
-static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF,
- const LValue &destLV, const Expr *init) {
- bool needsCast = false;
-
- while (auto castExpr = dyn_cast<CastExpr>(init->IgnoreParens())) {
- switch (castExpr->getCastKind()) {
- // Look through casts that don't require representation changes.
- case CK_NoOp:
- case CK_BitCast:
- case CK_BlockPointerToObjCPointerCast:
- needsCast = true;
- break;
-
- // If we find an l-value to r-value cast from a __weak variable,
- // emit this operation as a copy or move.
- case CK_LValueToRValue: {
- const Expr *srcExpr = castExpr->getSubExpr();
- if (srcExpr->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
- return false;
-
- // Emit the source l-value.
- LValue srcLV = CGF.EmitLValue(srcExpr);
-
- // Handle a formal type change to avoid asserting.
- auto srcAddr = srcLV.getAddress();
- if (needsCast) {
- srcAddr = CGF.Builder.CreateElementBitCast(srcAddr,
- destLV.getAddress().getElementType());
- }
-
- // If it was an l-value, use objc_copyWeak.
- if (srcExpr->getValueKind() == VK_LValue) {
- CGF.EmitARCCopyWeak(destLV.getAddress(), srcAddr);
- } else {
- assert(srcExpr->getValueKind() == VK_XValue);
- CGF.EmitARCMoveWeak(destLV.getAddress(), srcAddr);
- }
- return true;
- }
-
- // Stop at anything else.
- default:
- return false;
- }
-
- init = castExpr->getSubExpr();
- }
- return false;
-}
-
-static void drillIntoBlockVariable(CodeGenFunction &CGF,
- LValue &lvalue,
- const VarDecl *var) {
- lvalue.setAddress(CGF.emitBlockByrefAddress(lvalue.getAddress(), var));
-}
-
-void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS,
- SourceLocation Loc) {
- if (!SanOpts.has(SanitizerKind::NullabilityAssign))
- return;
-
- auto Nullability = LHS.getType()->getNullability(getContext());
- if (!Nullability || *Nullability != NullabilityKind::NonNull)
- return;
-
- // Check if the right hand side of the assignment is nonnull, if the left
- // hand side must be nonnull.
- SanitizerScope SanScope(this);
- llvm::Value *IsNotNull = Builder.CreateIsNotNull(RHS);
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(LHS.getType()),
- llvm::ConstantInt::get(Int8Ty, 0), // The LogAlignment info is unused.
- llvm::ConstantInt::get(Int8Ty, TCK_NonnullAssign)};
- EmitCheck({{IsNotNull, SanitizerKind::NullabilityAssign}},
- SanitizerHandler::TypeMismatch, StaticData, RHS);
-}
-
-void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
- LValue lvalue, bool capturedByInit) {
- Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
- if (!lifetime) {
- llvm::Value *value = EmitScalarExpr(init);
- if (capturedByInit)
- drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- EmitNullabilityCheck(lvalue, value, init->getExprLoc());
- EmitStoreThroughLValue(RValue::get(value), lvalue, true);
- return;
- }
-
- if (const CXXDefaultInitExpr *DIE = dyn_cast<CXXDefaultInitExpr>(init))
- init = DIE->getExpr();
-
- // If we're emitting a value with lifetime, we have to do the
- // initialization *before* we leave the cleanup scopes.
- if (const FullExpr *fe = dyn_cast<FullExpr>(init)) {
- enterFullExpression(fe);
- init = fe->getSubExpr();
- }
- CodeGenFunction::RunCleanupsScope Scope(*this);
-
- // We have to maintain the illusion that the variable is
- // zero-initialized. If the variable might be accessed in its
- // initializer, zero-initialize before running the initializer, then
- // actually perform the initialization with an assign.
- bool accessedByInit = false;
- if (lifetime != Qualifiers::OCL_ExplicitNone)
- accessedByInit = (capturedByInit || isAccessedBy(D, init));
- if (accessedByInit) {
- LValue tempLV = lvalue;
- // Drill down to the __block object if necessary.
- if (capturedByInit) {
- // We can use a simple GEP for this because it can't have been
- // moved yet.
- tempLV.setAddress(emitBlockByrefAddress(tempLV.getAddress(),
- cast<VarDecl>(D),
- /*follow*/ false));
- }
-
- auto ty = cast<llvm::PointerType>(tempLV.getAddress().getElementType());
- llvm::Value *zero = CGM.getNullPointer(ty, tempLV.getType());
-
- // If __weak, we want to use a barrier under certain conditions.
- if (lifetime == Qualifiers::OCL_Weak)
- EmitARCInitWeak(tempLV.getAddress(), zero);
-
- // Otherwise just do a simple store.
- else
- EmitStoreOfScalar(zero, tempLV, /* isInitialization */ true);
- }
-
- // Emit the initializer.
- llvm::Value *value = nullptr;
-
- switch (lifetime) {
- case Qualifiers::OCL_None:
- llvm_unreachable("present but none");
-
- case Qualifiers::OCL_Strong: {
- if (!D || !isa<VarDecl>(D) || !cast<VarDecl>(D)->isARCPseudoStrong()) {
- value = EmitARCRetainScalarExpr(init);
- break;
- }
- // If D is pseudo-strong, treat it like __unsafe_unretained here. This means
- // that we omit the retain, and causes non-autoreleased return values to be
- // immediately released.
- LLVM_FALLTHROUGH;
- }
-
- case Qualifiers::OCL_ExplicitNone:
- value = EmitARCUnsafeUnretainedScalarExpr(init);
- break;
-
- case Qualifiers::OCL_Weak: {
- // If it's not accessed by the initializer, try to emit the
- // initialization with a copy or move.
- if (!accessedByInit && tryEmitARCCopyWeakInit(*this, lvalue, init)) {
- return;
- }
-
- // No way to optimize a producing initializer into this. It's not
- // worth optimizing for, because the value will immediately
- // disappear in the common case.
- value = EmitScalarExpr(init);
-
- if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- if (accessedByInit)
- EmitARCStoreWeak(lvalue.getAddress(), value, /*ignored*/ true);
- else
- EmitARCInitWeak(lvalue.getAddress(), value);
- return;
- }
-
- case Qualifiers::OCL_Autoreleasing:
- value = EmitARCRetainAutoreleaseScalarExpr(init);
- break;
- }
-
- if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
-
- EmitNullabilityCheck(lvalue, value, init->getExprLoc());
-
- // If the variable might have been accessed by its initializer, we
- // might have to initialize with a barrier. We have to do this for
- // both __weak and __strong, but __weak got filtered out above.
- if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
- llvm::Value *oldValue = EmitLoadOfScalar(lvalue, init->getExprLoc());
- EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
- EmitARCRelease(oldValue, ARCImpreciseLifetime);
- return;
- }
-
- EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
-}
-
-/// Decide whether we can emit the non-zero parts of the specified initializer
-/// with equal or fewer than NumStores scalar stores.
-static bool canEmitInitWithFewStoresAfterBZero(llvm::Constant *Init,
- unsigned &NumStores) {
- // Zero and Undef never requires any extra stores.
- if (isa<llvm::ConstantAggregateZero>(Init) ||
- isa<llvm::ConstantPointerNull>(Init) ||
- isa<llvm::UndefValue>(Init))
- return true;
- if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
- isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
- isa<llvm::ConstantExpr>(Init))
- return Init->isNullValue() || NumStores--;
-
- // See if we can emit each element.
- if (isa<llvm::ConstantArray>(Init) || isa<llvm::ConstantStruct>(Init)) {
- for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
- llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
- if (!canEmitInitWithFewStoresAfterBZero(Elt, NumStores))
- return false;
- }
- return true;
- }
-
- if (llvm::ConstantDataSequential *CDS =
- dyn_cast<llvm::ConstantDataSequential>(Init)) {
- for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
- llvm::Constant *Elt = CDS->getElementAsConstant(i);
- if (!canEmitInitWithFewStoresAfterBZero(Elt, NumStores))
- return false;
- }
- return true;
- }
-
- // Anything else is hard and scary.
- return false;
-}
-
-/// For inits that canEmitInitWithFewStoresAfterBZero returned true for, emit
-/// the scalar stores that would be required.
-static void emitStoresForInitAfterBZero(CodeGenModule &CGM,
- llvm::Constant *Init, Address Loc,
- bool isVolatile, CGBuilderTy &Builder) {
- assert(!Init->isNullValue() && !isa<llvm::UndefValue>(Init) &&
- "called emitStoresForInitAfterBZero for zero or undef value.");
-
- if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
- isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
- isa<llvm::ConstantExpr>(Init)) {
- Builder.CreateStore(Init, Loc, isVolatile);
- return;
- }
-
- if (llvm::ConstantDataSequential *CDS =
- dyn_cast<llvm::ConstantDataSequential>(Init)) {
- for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
- llvm::Constant *Elt = CDS->getElementAsConstant(i);
-
- // If necessary, get a pointer to the element and emit it.
- if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
- emitStoresForInitAfterBZero(
- CGM, Elt,
- Builder.CreateConstInBoundsGEP2_32(Loc, 0, i, CGM.getDataLayout()),
- isVolatile, Builder);
- }
- return;
- }
-
- assert((isa<llvm::ConstantStruct>(Init) || isa<llvm::ConstantArray>(Init)) &&
- "Unknown value type!");
-
- for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
- llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
-
- // If necessary, get a pointer to the element and emit it.
- if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
- emitStoresForInitAfterBZero(
- CGM, Elt,
- Builder.CreateConstInBoundsGEP2_32(Loc, 0, i, CGM.getDataLayout()),
- isVolatile, Builder);
- }
-}
-
-/// Decide whether we should use bzero plus some stores to initialize a local
-/// variable instead of using a memcpy from a constant global. It is beneficial
-/// to use bzero if the global is all zeros, or mostly zeros and large.
-static bool shouldUseBZeroPlusStoresToInitialize(llvm::Constant *Init,
- uint64_t GlobalSize) {
- // If a global is all zeros, always use a bzero.
- if (isa<llvm::ConstantAggregateZero>(Init)) return true;
-
- // If a non-zero global is <= 32 bytes, always use a memcpy. If it is large,
- // do it if it will require 6 or fewer scalar stores.
- // TODO: Should budget depends on the size? Avoiding a large global warrants
- // plopping in more stores.
- unsigned StoreBudget = 6;
- uint64_t SizeLimit = 32;
-
- return GlobalSize > SizeLimit &&
- canEmitInitWithFewStoresAfterBZero(Init, StoreBudget);
-}
-
-/// Decide whether we should use memset to initialize a local variable instead
-/// of using a memcpy from a constant global. Assumes we've already decided to
-/// not user bzero.
-/// FIXME We could be more clever, as we are for bzero above, and generate
-/// memset followed by stores. It's unclear that's worth the effort.
-static llvm::Value *shouldUseMemSetToInitialize(llvm::Constant *Init,
- uint64_t GlobalSize) {
- uint64_t SizeLimit = 32;
- if (GlobalSize <= SizeLimit)
- return nullptr;
- return llvm::isBytewiseValue(Init);
-}
-
-static llvm::Constant *patternFor(CodeGenModule &CGM, llvm::Type *Ty) {
- // The following value is a guaranteed unmappable pointer value and has a
- // repeated byte-pattern which makes it easier to synthesize. We use it for
- // pointers as well as integers so that aggregates are likely to be
- // initialized with this repeated value.
- constexpr uint64_t LargeValue = 0xAAAAAAAAAAAAAAAAull;
- // For 32-bit platforms it's a bit trickier because, across systems, only the
- // zero page can reasonably be expected to be unmapped, and even then we need
- // a very low address. We use a smaller value, and that value sadly doesn't
- // have a repeated byte-pattern. We don't use it for integers.
- constexpr uint32_t SmallValue = 0x000000AA;
- // Floating-point values are initialized as NaNs because they propagate. Using
- // a repeated byte pattern means that it will be easier to initialize
- // all-floating-point aggregates and arrays with memset. Further, aggregates
- // which mix integral and a few floats might also initialize with memset
- // followed by a handful of stores for the floats. Using fairly unique NaNs
- // also means they'll be easier to distinguish in a crash.
- constexpr bool NegativeNaN = true;
- constexpr uint64_t NaNPayload = 0xFFFFFFFFFFFFFFFFull;
- if (Ty->isIntOrIntVectorTy()) {
- unsigned BitWidth = cast<llvm::IntegerType>(
- Ty->isVectorTy() ? Ty->getVectorElementType() : Ty)
- ->getBitWidth();
- if (BitWidth <= 64)
- return llvm::ConstantInt::get(Ty, LargeValue);
- return llvm::ConstantInt::get(
- Ty, llvm::APInt::getSplat(BitWidth, llvm::APInt(64, LargeValue)));
- }
- if (Ty->isPtrOrPtrVectorTy()) {
- auto *PtrTy = cast<llvm::PointerType>(
- Ty->isVectorTy() ? Ty->getVectorElementType() : Ty);
- unsigned PtrWidth = CGM.getContext().getTargetInfo().getPointerWidth(
- PtrTy->getAddressSpace());
- llvm::Type *IntTy = llvm::IntegerType::get(CGM.getLLVMContext(), PtrWidth);
- uint64_t IntValue;
- switch (PtrWidth) {
- default:
- llvm_unreachable("pattern initialization of unsupported pointer width");
- case 64:
- IntValue = LargeValue;
- break;
- case 32:
- IntValue = SmallValue;
- break;
- }
- auto *Int = llvm::ConstantInt::get(IntTy, IntValue);
- return llvm::ConstantExpr::getIntToPtr(Int, PtrTy);
- }
- if (Ty->isFPOrFPVectorTy()) {
- unsigned BitWidth = llvm::APFloat::semanticsSizeInBits(
- (Ty->isVectorTy() ? Ty->getVectorElementType() : Ty)
- ->getFltSemantics());
- llvm::APInt Payload(64, NaNPayload);
- if (BitWidth >= 64)
- Payload = llvm::APInt::getSplat(BitWidth, Payload);
- return llvm::ConstantFP::getQNaN(Ty, NegativeNaN, &Payload);
- }
- if (Ty->isArrayTy()) {
- // Note: this doesn't touch tail padding (at the end of an object, before
- // the next array object). It is instead handled by replaceUndef.
- auto *ArrTy = cast<llvm::ArrayType>(Ty);
- llvm::SmallVector<llvm::Constant *, 8> Element(
- ArrTy->getNumElements(), patternFor(CGM, ArrTy->getElementType()));
- return llvm::ConstantArray::get(ArrTy, Element);
- }
-
- // Note: this doesn't touch struct padding. It will initialize as much union
- // padding as is required for the largest type in the union. Padding is
- // instead handled by replaceUndef. Stores to structs with volatile members
- // don't have a volatile qualifier when initialized according to C++. This is
- // fine because stack-based volatiles don't really have volatile semantics
- // anyways, and the initialization shouldn't be observable.
- auto *StructTy = cast<llvm::StructType>(Ty);
- llvm::SmallVector<llvm::Constant *, 8> Struct(StructTy->getNumElements());
- for (unsigned El = 0; El != Struct.size(); ++El)
- Struct[El] = patternFor(CGM, StructTy->getElementType(El));
- return llvm::ConstantStruct::get(StructTy, Struct);
-}
-
-static Address createUnnamedGlobalFrom(CodeGenModule &CGM, const VarDecl &D,
- CGBuilderTy &Builder,
- llvm::Constant *Constant,
- CharUnits Align) {
- auto FunctionName = [&](const DeclContext *DC) -> std::string {
- if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {
- if (const auto *CC = dyn_cast<CXXConstructorDecl>(FD))
- return CC->getNameAsString();
- if (const auto *CD = dyn_cast<CXXDestructorDecl>(FD))
- return CD->getNameAsString();
- return CGM.getMangledName(FD);
- } else if (const auto *OM = dyn_cast<ObjCMethodDecl>(DC)) {
- return OM->getNameAsString();
- } else if (isa<BlockDecl>(DC)) {
- return "<block>";
- } else if (isa<CapturedDecl>(DC)) {
- return "<captured>";
- } else {
- llvm::llvm_unreachable_internal("expected a function or method");
- }
- };
-
- auto *Ty = Constant->getType();
- bool isConstant = true;
- llvm::GlobalVariable *InsertBefore = nullptr;
- unsigned AS = CGM.getContext().getTargetAddressSpace(
- CGM.getStringLiteralAddressSpace());
- llvm::GlobalVariable *GV = new llvm::GlobalVariable(
- CGM.getModule(), Ty, isConstant, llvm::GlobalValue::PrivateLinkage,
- Constant,
- "__const." + FunctionName(D.getParentFunctionOrMethod()) + "." +
- D.getName(),
- InsertBefore, llvm::GlobalValue::NotThreadLocal, AS);
- GV->setAlignment(Align.getQuantity());
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- Address SrcPtr = Address(GV, Align);
- llvm::Type *BP = llvm::PointerType::getInt8PtrTy(CGM.getLLVMContext(), AS);
- if (SrcPtr.getType() != BP)
- SrcPtr = Builder.CreateBitCast(SrcPtr, BP);
- return SrcPtr;
-}
-
-static void emitStoresForConstant(CodeGenModule &CGM, const VarDecl &D,
- Address Loc, bool isVolatile,
- CGBuilderTy &Builder,
- llvm::Constant *constant) {
- auto *Ty = constant->getType();
- bool isScalar = Ty->isIntOrIntVectorTy() || Ty->isPtrOrPtrVectorTy() ||
- Ty->isFPOrFPVectorTy();
- if (isScalar) {
- Builder.CreateStore(constant, Loc, isVolatile);
- return;
- }
-
- auto *Int8Ty = llvm::IntegerType::getInt8Ty(CGM.getLLVMContext());
- auto *IntPtrTy = CGM.getDataLayout().getIntPtrType(CGM.getLLVMContext());
-
- // If the initializer is all or mostly the same, codegen with bzero / memset
- // then do a few stores afterward.
- uint64_t ConstantSize = CGM.getDataLayout().getTypeAllocSize(Ty);
- auto *SizeVal = llvm::ConstantInt::get(IntPtrTy, ConstantSize);
- if (shouldUseBZeroPlusStoresToInitialize(constant, ConstantSize)) {
- Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
- isVolatile);
-
- bool valueAlreadyCorrect =
- constant->isNullValue() || isa<llvm::UndefValue>(constant);
- if (!valueAlreadyCorrect) {
- Loc = Builder.CreateBitCast(Loc, Ty->getPointerTo(Loc.getAddressSpace()));
- emitStoresForInitAfterBZero(CGM, constant, Loc, isVolatile, Builder);
- }
- return;
- }
-
- llvm::Value *Pattern = shouldUseMemSetToInitialize(constant, ConstantSize);
- if (Pattern) {
- uint64_t Value = 0x00;
- if (!isa<llvm::UndefValue>(Pattern)) {
- const llvm::APInt &AP = cast<llvm::ConstantInt>(Pattern)->getValue();
- assert(AP.getBitWidth() <= 8);
- Value = AP.getLimitedValue();
- }
- Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, Value), SizeVal,
- isVolatile);
- return;
- }
-
- Builder.CreateMemCpy(
- Loc,
- createUnnamedGlobalFrom(CGM, D, Builder, constant, Loc.getAlignment()),
- SizeVal, isVolatile);
-}
-
-static void emitStoresForZeroInit(CodeGenModule &CGM, const VarDecl &D,
- Address Loc, bool isVolatile,
- CGBuilderTy &Builder) {
- llvm::Type *ElTy = Loc.getElementType();
- llvm::Constant *constant = llvm::Constant::getNullValue(ElTy);
- emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant);
-}
-
-static void emitStoresForPatternInit(CodeGenModule &CGM, const VarDecl &D,
- Address Loc, bool isVolatile,
- CGBuilderTy &Builder) {
- llvm::Type *ElTy = Loc.getElementType();
- llvm::Constant *constant = patternFor(CGM, ElTy);
- assert(!isa<llvm::UndefValue>(constant));
- emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant);
-}
-
-static bool containsUndef(llvm::Constant *constant) {
- auto *Ty = constant->getType();
- if (isa<llvm::UndefValue>(constant))
- return true;
- if (Ty->isStructTy() || Ty->isArrayTy() || Ty->isVectorTy())
- for (llvm::Use &Op : constant->operands())
- if (containsUndef(cast<llvm::Constant>(Op)))
- return true;
- return false;
-}
-
-static llvm::Constant *replaceUndef(llvm::Constant *constant) {
- // FIXME: when doing pattern initialization, replace undef with 0xAA instead.
- // FIXME: also replace padding between values by creating a new struct type
- // which has no padding.
- auto *Ty = constant->getType();
- if (isa<llvm::UndefValue>(constant))
- return llvm::Constant::getNullValue(Ty);
- if (!(Ty->isStructTy() || Ty->isArrayTy() || Ty->isVectorTy()))
- return constant;
- if (!containsUndef(constant))
- return constant;
- llvm::SmallVector<llvm::Constant *, 8> Values(constant->getNumOperands());
- for (unsigned Op = 0, NumOp = constant->getNumOperands(); Op != NumOp; ++Op) {
- auto *OpValue = cast<llvm::Constant>(constant->getOperand(Op));
- Values[Op] = replaceUndef(OpValue);
- }
- if (Ty->isStructTy())
- return llvm::ConstantStruct::get(cast<llvm::StructType>(Ty), Values);
- if (Ty->isArrayTy())
- return llvm::ConstantArray::get(cast<llvm::ArrayType>(Ty), Values);
- assert(Ty->isVectorTy());
- return llvm::ConstantVector::get(Values);
-}
-
-/// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a
-/// variable declaration with auto, register, or no storage class specifier.
-/// These turn into simple stack objects, or GlobalValues depending on target.
-void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) {
- AutoVarEmission emission = EmitAutoVarAlloca(D);
- EmitAutoVarInit(emission);
- EmitAutoVarCleanups(emission);
-}
-
-/// Emit a lifetime.begin marker if some criteria are satisfied.
-/// \return a pointer to the temporary size Value if a marker was emitted, null
-/// otherwise
-llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
- llvm::Value *Addr) {
- if (!ShouldEmitLifetimeMarkers)
- return nullptr;
-
- assert(Addr->getType()->getPointerAddressSpace() ==
- CGM.getDataLayout().getAllocaAddrSpace() &&
- "Pointer should be in alloca address space");
- llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size);
- Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
- llvm::CallInst *C =
- Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr});
- C->setDoesNotThrow();
- return SizeV;
-}
-
-void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
- assert(Addr->getType()->getPointerAddressSpace() ==
- CGM.getDataLayout().getAllocaAddrSpace() &&
- "Pointer should be in alloca address space");
- Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
- llvm::CallInst *C =
- Builder.CreateCall(CGM.getLLVMLifetimeEndFn(), {Size, Addr});
- C->setDoesNotThrow();
-}
-
-void CodeGenFunction::EmitAndRegisterVariableArrayDimensions(
- CGDebugInfo *DI, const VarDecl &D, bool EmitDebugInfo) {
- // For each dimension stores its QualType and corresponding
- // size-expression Value.
- SmallVector<CodeGenFunction::VlaSizePair, 4> Dimensions;
- SmallVector<IdentifierInfo *, 4> VLAExprNames;
-
- // Break down the array into individual dimensions.
- QualType Type1D = D.getType();
- while (getContext().getAsVariableArrayType(Type1D)) {
- auto VlaSize = getVLAElements1D(Type1D);
- if (auto *C = dyn_cast<llvm::ConstantInt>(VlaSize.NumElts))
- Dimensions.emplace_back(C, Type1D.getUnqualifiedType());
- else {
- // Generate a locally unique name for the size expression.
- Twine Name = Twine("__vla_expr") + Twine(VLAExprCounter++);
- SmallString<12> Buffer;
- StringRef NameRef = Name.toStringRef(Buffer);
- auto &Ident = getContext().Idents.getOwn(NameRef);
- VLAExprNames.push_back(&Ident);
- auto SizeExprAddr =
- CreateDefaultAlignTempAlloca(VlaSize.NumElts->getType(), NameRef);
- Builder.CreateStore(VlaSize.NumElts, SizeExprAddr);
- Dimensions.emplace_back(SizeExprAddr.getPointer(),
- Type1D.getUnqualifiedType());
- }
- Type1D = VlaSize.Type;
- }
-
- if (!EmitDebugInfo)
- return;
-
- // Register each dimension's size-expression with a DILocalVariable,
- // so that it can be used by CGDebugInfo when instantiating a DISubrange
- // to describe this array.
- unsigned NameIdx = 0;
- for (auto &VlaSize : Dimensions) {
- llvm::Metadata *MD;
- if (auto *C = dyn_cast<llvm::ConstantInt>(VlaSize.NumElts))
- MD = llvm::ConstantAsMetadata::get(C);
- else {
- // Create an artificial VarDecl to generate debug info for.
- IdentifierInfo *NameIdent = VLAExprNames[NameIdx++];
- auto VlaExprTy = VlaSize.NumElts->getType()->getPointerElementType();
- auto QT = getContext().getIntTypeForBitwidth(
- VlaExprTy->getScalarSizeInBits(), false);
- auto *ArtificialDecl = VarDecl::Create(
- getContext(), const_cast<DeclContext *>(D.getDeclContext()),
- D.getLocation(), D.getLocation(), NameIdent, QT,
- getContext().CreateTypeSourceInfo(QT), SC_Auto);
- ArtificialDecl->setImplicit();
-
- MD = DI->EmitDeclareOfAutoVariable(ArtificialDecl, VlaSize.NumElts,
- Builder);
- }
- assert(MD && "No Size expression debug node created");
- DI->registerVLASizeExpression(VlaSize.Type, MD);
- }
-}
-
-/// EmitAutoVarAlloca - Emit the alloca and debug information for a
-/// local variable. Does not emit initialization or destruction.
-CodeGenFunction::AutoVarEmission
-CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
- QualType Ty = D.getType();
- assert(
- Ty.getAddressSpace() == LangAS::Default ||
- (Ty.getAddressSpace() == LangAS::opencl_private && getLangOpts().OpenCL));
-
- AutoVarEmission emission(D);
-
- bool isEscapingByRef = D.isEscapingByref();
- emission.IsEscapingByRef = isEscapingByRef;
-
- CharUnits alignment = getContext().getDeclAlign(&D);
-
- // If the type is variably-modified, emit all the VLA sizes for it.
- if (Ty->isVariablyModifiedType())
- EmitVariablyModifiedType(Ty);
-
- auto *DI = getDebugInfo();
- bool EmitDebugInfo = DI && CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo;
-
- Address address = Address::invalid();
- Address AllocaAddr = Address::invalid();
- if (Ty->isConstantSizeType()) {
- bool NRVO = getLangOpts().ElideConstructors &&
- D.isNRVOVariable();
-
- // If this value is an array or struct with a statically determinable
- // constant initializer, there are optimizations we can do.
- //
- // TODO: We should constant-evaluate the initializer of any variable,
- // as long as it is initialized by a constant expression. Currently,
- // isConstantInitializer produces wrong answers for structs with
- // reference or bitfield members, and a few other cases, and checking
- // for POD-ness protects us from some of these.
- if (D.getInit() && (Ty->isArrayType() || Ty->isRecordType()) &&
- (D.isConstexpr() ||
- ((Ty.isPODType(getContext()) ||
- getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
- D.getInit()->isConstantInitializer(getContext(), false)))) {
-
- // If the variable's a const type, and it's neither an NRVO
- // candidate nor a __block variable and has no mutable members,
- // emit it as a global instead.
- // Exception is if a variable is located in non-constant address space
- // in OpenCL.
- if ((!getLangOpts().OpenCL ||
- Ty.getAddressSpace() == LangAS::opencl_constant) &&
- (CGM.getCodeGenOpts().MergeAllConstants && !NRVO &&
- !isEscapingByRef && CGM.isTypeConstant(Ty, true))) {
- EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
-
- // Signal this condition to later callbacks.
- emission.Addr = Address::invalid();
- assert(emission.wasEmittedAsGlobal());
- return emission;
- }
-
- // Otherwise, tell the initialization code that we're in this case.
- emission.IsConstantAggregate = true;
- }
-
- // A normal fixed sized variable becomes an alloca in the entry block,
- // unless:
- // - it's an NRVO variable.
- // - we are compiling OpenMP and it's an OpenMP local variable.
-
- Address OpenMPLocalAddr =
- getLangOpts().OpenMP
- ? CGM.getOpenMPRuntime().getAddressOfLocalVariable(*this, &D)
- : Address::invalid();
- if (getLangOpts().OpenMP && OpenMPLocalAddr.isValid()) {
- address = OpenMPLocalAddr;
- } else if (NRVO) {
- // The named return value optimization: allocate this variable in the
- // return slot, so that we can elide the copy when returning this
- // variable (C++0x [class.copy]p34).
- address = ReturnValue;
-
- if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
- const auto *RD = RecordTy->getDecl();
- const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
- if ((CXXRD && !CXXRD->hasTrivialDestructor()) ||
- RD->isNonTrivialToPrimitiveDestroy()) {
- // Create a flag that is used to indicate when the NRVO was applied
- // to this variable. Set it to zero to indicate that NRVO was not
- // applied.
- llvm::Value *Zero = Builder.getFalse();
- Address NRVOFlag =
- CreateTempAlloca(Zero->getType(), CharUnits::One(), "nrvo");
- EnsureInsertPoint();
- Builder.CreateStore(Zero, NRVOFlag);
-
- // Record the NRVO flag for this variable.
- NRVOFlags[&D] = NRVOFlag.getPointer();
- emission.NRVOFlag = NRVOFlag.getPointer();
- }
- }
- } else {
- CharUnits allocaAlignment;
- llvm::Type *allocaTy;
- if (isEscapingByRef) {
- auto &byrefInfo = getBlockByrefInfo(&D);
- allocaTy = byrefInfo.Type;
- allocaAlignment = byrefInfo.ByrefAlignment;
- } else {
- allocaTy = ConvertTypeForMem(Ty);
- allocaAlignment = alignment;
- }
-
- // Create the alloca. Note that we set the name separately from
- // building the instruction so that it's there even in no-asserts
- // builds.
- address = CreateTempAlloca(allocaTy, allocaAlignment, D.getName(),
- /*ArraySize=*/nullptr, &AllocaAddr);
-
- // Don't emit lifetime markers for MSVC catch parameters. The lifetime of
- // the catch parameter starts in the catchpad instruction, and we can't
- // insert code in those basic blocks.
- bool IsMSCatchParam =
- D.isExceptionVariable() && getTarget().getCXXABI().isMicrosoft();
-
- // Emit a lifetime intrinsic if meaningful. There's no point in doing this
- // if we don't have a valid insertion point (?).
- if (HaveInsertPoint() && !IsMSCatchParam) {
- // If there's a jump into the lifetime of this variable, its lifetime
- // gets broken up into several regions in IR, which requires more work
- // to handle correctly. For now, just omit the intrinsics; this is a
- // rare case, and it's better to just be conservatively correct.
- // PR28267.
- //
- // We have to do this in all language modes if there's a jump past the
- // declaration. We also have to do it in C if there's a jump to an
- // earlier point in the current block because non-VLA lifetimes begin as
- // soon as the containing block is entered, not when its variables
- // actually come into scope; suppressing the lifetime annotations
- // completely in this case is unnecessarily pessimistic, but again, this
- // is rare.
- if (!Bypasses.IsBypassed(&D) &&
- !(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) {
- uint64_t size = CGM.getDataLayout().getTypeAllocSize(allocaTy);
- emission.SizeForLifetimeMarkers =
- EmitLifetimeStart(size, AllocaAddr.getPointer());
- }
- } else {
- assert(!emission.useLifetimeMarkers());
- }
- }
- } else {
- EnsureInsertPoint();
-
- if (!DidCallStackSave) {
- // Save the stack.
- Address Stack =
- CreateTempAlloca(Int8PtrTy, getPointerAlign(), "saved_stack");
-
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave);
- llvm::Value *V = Builder.CreateCall(F);
- Builder.CreateStore(V, Stack);
-
- DidCallStackSave = true;
-
- // Push a cleanup block and restore the stack there.
- // FIXME: in general circumstances, this should be an EH cleanup.
- pushStackRestore(NormalCleanup, Stack);
- }
-
- auto VlaSize = getVLASize(Ty);
- llvm::Type *llvmTy = ConvertTypeForMem(VlaSize.Type);
-
- // Allocate memory for the array.
- address = CreateTempAlloca(llvmTy, alignment, "vla", VlaSize.NumElts,
- &AllocaAddr);
-
- // If we have debug info enabled, properly describe the VLA dimensions for
- // this type by registering the vla size expression for each of the
- // dimensions.
- EmitAndRegisterVariableArrayDimensions(DI, D, EmitDebugInfo);
- }
-
- setAddrOfLocalVar(&D, address);
- emission.Addr = address;
- emission.AllocaAddr = AllocaAddr;
-
- // Emit debug info for local var declaration.
- if (EmitDebugInfo && HaveInsertPoint()) {
- DI->setLocation(D.getLocation());
- (void)DI->EmitDeclareOfAutoVariable(&D, address.getPointer(), Builder);
- }
-
- if (D.hasAttr<AnnotateAttr>())
- EmitVarAnnotations(&D, address.getPointer());
-
- // Make sure we call @llvm.lifetime.end.
- if (emission.useLifetimeMarkers())
- EHStack.pushCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker,
- emission.getOriginalAllocatedAddress(),
- emission.getSizeForLifetimeMarkers());
-
- return emission;
-}
-
-static bool isCapturedBy(const VarDecl &, const Expr *);
-
-/// Determines whether the given __block variable is potentially
-/// captured by the given statement.
-static bool isCapturedBy(const VarDecl &Var, const Stmt *S) {
- if (const Expr *E = dyn_cast<Expr>(S))
- return isCapturedBy(Var, E);
- for (const Stmt *SubStmt : S->children())
- if (isCapturedBy(Var, SubStmt))
- return true;
- return false;
-}
-
-/// Determines whether the given __block variable is potentially
-/// captured by the given expression.
-static bool isCapturedBy(const VarDecl &Var, const Expr *E) {
- // Skip the most common kinds of expressions that make
- // hierarchy-walking expensive.
- E = E->IgnoreParenCasts();
-
- if (const BlockExpr *BE = dyn_cast<BlockExpr>(E)) {
- const BlockDecl *Block = BE->getBlockDecl();
- for (const auto &I : Block->captures()) {
- if (I.getVariable() == &Var)
- return true;
- }
-
- // No need to walk into the subexpressions.
- return false;
- }
-
- if (const StmtExpr *SE = dyn_cast<StmtExpr>(E)) {
- const CompoundStmt *CS = SE->getSubStmt();
- for (const auto *BI : CS->body())
- if (const auto *BIE = dyn_cast<Expr>(BI)) {
- if (isCapturedBy(Var, BIE))
- return true;
- }
- else if (const auto *DS = dyn_cast<DeclStmt>(BI)) {
- // special case declarations
- for (const auto *I : DS->decls()) {
- if (const auto *VD = dyn_cast<VarDecl>((I))) {
- const Expr *Init = VD->getInit();
- if (Init && isCapturedBy(Var, Init))
- return true;
- }
- }
- }
- else
- // FIXME. Make safe assumption assuming arbitrary statements cause capturing.
- // Later, provide code to poke into statements for capture analysis.
- return true;
- return false;
- }
-
- for (const Stmt *SubStmt : E->children())
- if (isCapturedBy(Var, SubStmt))
- return true;
-
- return false;
-}
-
-/// Determine whether the given initializer is trivial in the sense
-/// that it requires no code to be generated.
-bool CodeGenFunction::isTrivialInitializer(const Expr *Init) {
- if (!Init)
- return true;
-
- if (const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
- if (CXXConstructorDecl *Constructor = Construct->getConstructor())
- if (Constructor->isTrivial() &&
- Constructor->isDefaultConstructor() &&
- !Construct->requiresZeroInitialization())
- return true;
-
- return false;
-}
-
-void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
- assert(emission.Variable && "emission was not valid!");
-
- // If this was emitted as a global constant, we're done.
- if (emission.wasEmittedAsGlobal()) return;
-
- const VarDecl &D = *emission.Variable;
- auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, D.getLocation());
- QualType type = D.getType();
-
- bool isVolatile = type.isVolatileQualified();
-
- // If this local has an initializer, emit it now.
- const Expr *Init = D.getInit();
-
- // If we are at an unreachable point, we don't need to emit the initializer
- // unless it contains a label.
- if (!HaveInsertPoint()) {
- if (!Init || !ContainsLabel(Init)) return;
- EnsureInsertPoint();
- }
-
- // Initialize the structure of a __block variable.
- if (emission.IsEscapingByRef)
- emitByrefStructureInit(emission);
-
- // Initialize the variable here if it doesn't have a initializer and it is a
- // C struct that is non-trivial to initialize or an array containing such a
- // struct.
- if (!Init &&
- type.isNonTrivialToPrimitiveDefaultInitialize() ==
- QualType::PDIK_Struct) {
- LValue Dst = MakeAddrLValue(emission.getAllocatedAddress(), type);
- if (emission.IsEscapingByRef)
- drillIntoBlockVariable(*this, Dst, &D);
- defaultInitNonTrivialCStructVar(Dst);
- return;
- }
-
- // Check whether this is a byref variable that's potentially
- // captured and moved by its own initializer. If so, we'll need to
- // emit the initializer first, then copy into the variable.
- bool capturedByInit =
- Init && emission.IsEscapingByRef && isCapturedBy(D, Init);
-
- bool locIsByrefHeader = !capturedByInit;
- const Address Loc =
- locIsByrefHeader ? emission.getObjectAddress(*this) : emission.Addr;
-
- // Note: constexpr already initializes everything correctly.
- LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
- (D.isConstexpr()
- ? LangOptions::TrivialAutoVarInitKind::Uninitialized
- : (D.getAttr<UninitializedAttr>()
- ? LangOptions::TrivialAutoVarInitKind::Uninitialized
- : getContext().getLangOpts().getTrivialAutoVarInit()));
-
- auto initializeWhatIsTechnicallyUninitialized = [&](Address Loc) {
- if (trivialAutoVarInit ==
- LangOptions::TrivialAutoVarInitKind::Uninitialized)
- return;
-
- // Only initialize a __block's storage: we always initialize the header.
- if (emission.IsEscapingByRef && !locIsByrefHeader)
- Loc = emitBlockByrefAddress(Loc, &D, /*follow=*/false);
-
- CharUnits Size = getContext().getTypeSizeInChars(type);
- if (!Size.isZero()) {
- switch (trivialAutoVarInit) {
- case LangOptions::TrivialAutoVarInitKind::Uninitialized:
- llvm_unreachable("Uninitialized handled above");
- case LangOptions::TrivialAutoVarInitKind::Zero:
- emitStoresForZeroInit(CGM, D, Loc, isVolatile, Builder);
- break;
- case LangOptions::TrivialAutoVarInitKind::Pattern:
- emitStoresForPatternInit(CGM, D, Loc, isVolatile, Builder);
- break;
- }
- return;
- }
-
- // VLAs look zero-sized to getTypeInfo. We can't emit constant stores to
- // them, so emit a memcpy with the VLA size to initialize each element.
- // Technically zero-sized or negative-sized VLAs are undefined, and UBSan
- // will catch that code, but there exists code which generates zero-sized
- // VLAs. Be nice and initialize whatever they requested.
- const VariableArrayType *VlaType =
- dyn_cast_or_null<VariableArrayType>(getContext().getAsArrayType(type));
- if (!VlaType)
- return;
- auto VlaSize = getVLASize(VlaType);
- auto SizeVal = VlaSize.NumElts;
- CharUnits EltSize = getContext().getTypeSizeInChars(VlaSize.Type);
- switch (trivialAutoVarInit) {
- case LangOptions::TrivialAutoVarInitKind::Uninitialized:
- llvm_unreachable("Uninitialized handled above");
-
- case LangOptions::TrivialAutoVarInitKind::Zero:
- if (!EltSize.isOne())
- SizeVal = Builder.CreateNUWMul(SizeVal, CGM.getSize(EltSize));
- Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
- isVolatile);
- break;
-
- case LangOptions::TrivialAutoVarInitKind::Pattern: {
- llvm::Type *ElTy = Loc.getElementType();
- llvm::Constant *Constant = patternFor(CGM, ElTy);
- CharUnits ConstantAlign = getContext().getTypeAlignInChars(VlaSize.Type);
- llvm::BasicBlock *SetupBB = createBasicBlock("vla-setup.loop");
- llvm::BasicBlock *LoopBB = createBasicBlock("vla-init.loop");
- llvm::BasicBlock *ContBB = createBasicBlock("vla-init.cont");
- llvm::Value *IsZeroSizedVLA = Builder.CreateICmpEQ(
- SizeVal, llvm::ConstantInt::get(SizeVal->getType(), 0),
- "vla.iszerosized");
- Builder.CreateCondBr(IsZeroSizedVLA, ContBB, SetupBB);
- EmitBlock(SetupBB);
- if (!EltSize.isOne())
- SizeVal = Builder.CreateNUWMul(SizeVal, CGM.getSize(EltSize));
- llvm::Value *BaseSizeInChars =
- llvm::ConstantInt::get(IntPtrTy, EltSize.getQuantity());
- Address Begin = Builder.CreateElementBitCast(Loc, Int8Ty, "vla.begin");
- llvm::Value *End =
- Builder.CreateInBoundsGEP(Begin.getPointer(), SizeVal, "vla.end");
- llvm::BasicBlock *OriginBB = Builder.GetInsertBlock();
- EmitBlock(LoopBB);
- llvm::PHINode *Cur = Builder.CreatePHI(Begin.getType(), 2, "vla.cur");
- Cur->addIncoming(Begin.getPointer(), OriginBB);
- CharUnits CurAlign = Loc.getAlignment().alignmentOfArrayElement(EltSize);
- Builder.CreateMemCpy(
- Address(Cur, CurAlign),
- createUnnamedGlobalFrom(CGM, D, Builder, Constant, ConstantAlign),
- BaseSizeInChars, isVolatile);
- llvm::Value *Next =
- Builder.CreateInBoundsGEP(Int8Ty, Cur, BaseSizeInChars, "vla.next");
- llvm::Value *Done = Builder.CreateICmpEQ(Next, End, "vla-init.isdone");
- Builder.CreateCondBr(Done, ContBB, LoopBB);
- Cur->addIncoming(Next, LoopBB);
- EmitBlock(ContBB);
- } break;
- }
- };
-
- if (isTrivialInitializer(Init)) {
- initializeWhatIsTechnicallyUninitialized(Loc);
- return;
- }
-
- llvm::Constant *constant = nullptr;
- if (emission.IsConstantAggregate || D.isConstexpr()) {
- assert(!capturedByInit && "constant init contains a capturing block?");
- constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(D);
- if (constant && trivialAutoVarInit !=
- LangOptions::TrivialAutoVarInitKind::Uninitialized)
- constant = replaceUndef(constant);
- }
-
- if (!constant) {
- initializeWhatIsTechnicallyUninitialized(Loc);
- LValue lv = MakeAddrLValue(Loc, type);
- lv.setNonGC(true);
- return EmitExprAsInit(Init, &D, lv, capturedByInit);
- }
-
- if (!emission.IsConstantAggregate) {
- // For simple scalar/complex initialization, store the value directly.
- LValue lv = MakeAddrLValue(Loc, type);
- lv.setNonGC(true);
- return EmitStoreThroughLValue(RValue::get(constant), lv, true);
- }
-
- llvm::Type *BP = CGM.Int8Ty->getPointerTo(Loc.getAddressSpace());
- emitStoresForConstant(
- CGM, D, (Loc.getType() == BP) ? Loc : Builder.CreateBitCast(Loc, BP),
- isVolatile, Builder, constant);
-}
-
-/// Emit an expression as an initializer for an object (variable, field, etc.)
-/// at the given location. The expression is not necessarily the normal
-/// initializer for the object, and the address is not necessarily
-/// its normal location.
-///
-/// \param init the initializing expression
-/// \param D the object to act as if we're initializing
-/// \param loc the address to initialize; its type is a pointer
-/// to the LLVM mapping of the object's type
-/// \param alignment the alignment of the address
-/// \param capturedByInit true if \p D is a __block variable
-/// whose address is potentially changed by the initializer
-void CodeGenFunction::EmitExprAsInit(const Expr *init, const ValueDecl *D,
- LValue lvalue, bool capturedByInit) {
- QualType type = D->getType();
-
- if (type->isReferenceType()) {
- RValue rvalue = EmitReferenceBindingToExpr(init);
- if (capturedByInit)
- drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- EmitStoreThroughLValue(rvalue, lvalue, true);
- return;
- }
- switch (getEvaluationKind(type)) {
- case TEK_Scalar:
- EmitScalarInit(init, D, lvalue, capturedByInit);
- return;
- case TEK_Complex: {
- ComplexPairTy complex = EmitComplexExpr(init);
- if (capturedByInit)
- drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- EmitStoreOfComplex(complex, lvalue, /*init*/ true);
- return;
- }
- case TEK_Aggregate:
- if (type->isAtomicType()) {
- EmitAtomicInit(const_cast<Expr*>(init), lvalue);
- } else {
- AggValueSlot::Overlap_t Overlap = AggValueSlot::MayOverlap;
- if (isa<VarDecl>(D))
- Overlap = AggValueSlot::DoesNotOverlap;
- else if (auto *FD = dyn_cast<FieldDecl>(D))
- Overlap = overlapForFieldInit(FD);
- // TODO: how can we delay here if D is captured by its initializer?
- EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- Overlap));
- }
- return;
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-/// Enter a destroy cleanup for the given local variable.
-void CodeGenFunction::emitAutoVarTypeCleanup(
- const CodeGenFunction::AutoVarEmission &emission,
- QualType::DestructionKind dtorKind) {
- assert(dtorKind != QualType::DK_none);
-
- // Note that for __block variables, we want to destroy the
- // original stack object, not the possibly forwarded object.
- Address addr = emission.getObjectAddress(*this);
-
- const VarDecl *var = emission.Variable;
- QualType type = var->getType();
-
- CleanupKind cleanupKind = NormalAndEHCleanup;
- CodeGenFunction::Destroyer *destroyer = nullptr;
-
- switch (dtorKind) {
- case QualType::DK_none:
- llvm_unreachable("no cleanup for trivially-destructible variable");
-
- case QualType::DK_cxx_destructor:
- // If there's an NRVO flag on the emission, we need a different
- // cleanup.
- if (emission.NRVOFlag) {
- assert(!type->isArrayType());
- CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
- EHStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, dtor,
- emission.NRVOFlag);
- return;
- }
- break;
-
- case QualType::DK_objc_strong_lifetime:
- // Suppress cleanups for pseudo-strong variables.
- if (var->isARCPseudoStrong()) return;
-
- // Otherwise, consider whether to use an EH cleanup or not.
- cleanupKind = getARCCleanupKind();
-
- // Use the imprecise destroyer by default.
- if (!var->hasAttr<ObjCPreciseLifetimeAttr>())
- destroyer = CodeGenFunction::destroyARCStrongImprecise;
- break;
-
- case QualType::DK_objc_weak_lifetime:
- break;
-
- case QualType::DK_nontrivial_c_struct:
- destroyer = CodeGenFunction::destroyNonTrivialCStruct;
- if (emission.NRVOFlag) {
- assert(!type->isArrayType());
- EHStack.pushCleanup<DestroyNRVOVariableC>(cleanupKind, addr,
- emission.NRVOFlag, type);
- return;
- }
- break;
- }
-
- // If we haven't chosen a more specific destroyer, use the default.
- if (!destroyer) destroyer = getDestroyer(dtorKind);
-
- // Use an EH cleanup in array destructors iff the destructor itself
- // is being pushed as an EH cleanup.
- bool useEHCleanup = (cleanupKind & EHCleanup);
- EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer,
- useEHCleanup);
-}
-
-void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
- assert(emission.Variable && "emission was not valid!");
-
- // If this was emitted as a global constant, we're done.
- if (emission.wasEmittedAsGlobal()) return;
-
- // If we don't have an insertion point, we're done. Sema prevents
- // us from jumping into any of these scopes anyway.
- if (!HaveInsertPoint()) return;
-
- const VarDecl &D = *emission.Variable;
-
- // Check the type for a cleanup.
- if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
- emitAutoVarTypeCleanup(emission, dtorKind);
-
- // In GC mode, honor objc_precise_lifetime.
- if (getLangOpts().getGC() != LangOptions::NonGC &&
- D.hasAttr<ObjCPreciseLifetimeAttr>()) {
- EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D);
- }
-
- // Handle the cleanup attribute.
- if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
- const FunctionDecl *FD = CA->getFunctionDecl();
-
- llvm::Constant *F = CGM.GetAddrOfFunction(FD);
- assert(F && "Could not find function!");
-
- const CGFunctionInfo &Info = CGM.getTypes().arrangeFunctionDeclaration(FD);
- EHStack.pushCleanup<CallCleanupFunction>(NormalAndEHCleanup, F, &Info, &D);
- }
-
- // If this is a block variable, call _Block_object_destroy
- // (on the unforwarded address). Don't enter this cleanup if we're in pure-GC
- // mode.
- if (emission.IsEscapingByRef &&
- CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
- BlockFieldFlags Flags = BLOCK_FIELD_IS_BYREF;
- if (emission.Variable->getType().isObjCGCWeak())
- Flags |= BLOCK_FIELD_IS_WEAK;
- enterByrefCleanup(NormalAndEHCleanup, emission.Addr, Flags,
- /*LoadBlockVarAddr*/ false,
- cxxDestructorCanThrow(emission.Variable->getType()));
- }
-}
-
-CodeGenFunction::Destroyer *
-CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
- switch (kind) {
- case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor");
- case QualType::DK_cxx_destructor:
- return destroyCXXObject;
- case QualType::DK_objc_strong_lifetime:
- return destroyARCStrongPrecise;
- case QualType::DK_objc_weak_lifetime:
- return destroyARCWeak;
- case QualType::DK_nontrivial_c_struct:
- return destroyNonTrivialCStruct;
- }
- llvm_unreachable("Unknown DestructionKind");
-}
-
-/// pushEHDestroy - Push the standard destructor for the given type as
-/// an EH-only cleanup.
-void CodeGenFunction::pushEHDestroy(QualType::DestructionKind dtorKind,
- Address addr, QualType type) {
- assert(dtorKind && "cannot push destructor for trivial type");
- assert(needsEHCleanup(dtorKind));
-
- pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind), true);
-}
-
-/// pushDestroy - Push the standard destructor for the given type as
-/// at least a normal cleanup.
-void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
- Address addr, QualType type) {
- assert(dtorKind && "cannot push destructor for trivial type");
-
- CleanupKind cleanupKind = getCleanupKind(dtorKind);
- pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind),
- cleanupKind & EHCleanup);
-}
-
-void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr,
- QualType type, Destroyer *destroyer,
- bool useEHCleanupForArray) {
- pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type,
- destroyer, useEHCleanupForArray);
-}
-
-void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) {
- EHStack.pushCleanup<CallStackRestore>(Kind, SPMem);
-}
-
-void CodeGenFunction::pushLifetimeExtendedDestroy(
- CleanupKind cleanupKind, Address addr, QualType type,
- Destroyer *destroyer, bool useEHCleanupForArray) {
- // Push an EH-only cleanup for the object now.
- // FIXME: When popping normal cleanups, we need to keep this EH cleanup
- // around in case a temporary's destructor throws an exception.
- if (cleanupKind & EHCleanup)
- EHStack.pushCleanup<DestroyObject>(
- static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,
- destroyer, useEHCleanupForArray);
-
- // Remember that we need to push a full cleanup for the object at the
- // end of the full-expression.
- pushCleanupAfterFullExpr<DestroyObject>(
- cleanupKind, addr, type, destroyer, useEHCleanupForArray);
-}
-
-/// emitDestroy - Immediately perform the destruction of the given
-/// object.
-///
-/// \param addr - the address of the object; a type*
-/// \param type - the type of the object; if an array type, all
-/// objects are destroyed in reverse order
-/// \param destroyer - the function to call to destroy individual
-/// elements
-/// \param useEHCleanupForArray - whether an EH cleanup should be
-/// used when destroying array elements, in case one of the
-/// destructions throws an exception
-void CodeGenFunction::emitDestroy(Address addr, QualType type,
- Destroyer *destroyer,
- bool useEHCleanupForArray) {
- const ArrayType *arrayType = getContext().getAsArrayType(type);
- if (!arrayType)
- return destroyer(*this, addr, type);
-
- llvm::Value *length = emitArrayLength(arrayType, type, addr);
-
- CharUnits elementAlign =
- addr.getAlignment()
- .alignmentOfArrayElement(getContext().getTypeSizeInChars(type));
-
- // Normally we have to check whether the array is zero-length.
- bool checkZeroLength = true;
-
- // But if the array length is constant, we can suppress that.
- if (llvm::ConstantInt *constLength = dyn_cast<llvm::ConstantInt>(length)) {
- // ...and if it's constant zero, we can just skip the entire thing.
- if (constLength->isZero()) return;
- checkZeroLength = false;
- }
-
- llvm::Value *begin = addr.getPointer();
- llvm::Value *end = Builder.CreateInBoundsGEP(begin, length);
- emitArrayDestroy(begin, end, type, elementAlign, destroyer,
- checkZeroLength, useEHCleanupForArray);
-}
-
-/// emitArrayDestroy - Destroys all the elements of the given array,
-/// beginning from last to first. The array cannot be zero-length.
-///
-/// \param begin - a type* denoting the first element of the array
-/// \param end - a type* denoting one past the end of the array
-/// \param elementType - the element type of the array
-/// \param destroyer - the function to call to destroy elements
-/// \param useEHCleanup - whether to push an EH cleanup to destroy
-/// the remaining elements in case the destruction of a single
-/// element throws
-void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
- llvm::Value *end,
- QualType elementType,
- CharUnits elementAlign,
- Destroyer *destroyer,
- bool checkZeroLength,
- bool useEHCleanup) {
- assert(!elementType->isArrayType());
-
- // The basic structure here is a do-while loop, because we don't
- // need to check for the zero-element case.
- llvm::BasicBlock *bodyBB = createBasicBlock("arraydestroy.body");
- llvm::BasicBlock *doneBB = createBasicBlock("arraydestroy.done");
-
- if (checkZeroLength) {
- llvm::Value *isEmpty = Builder.CreateICmpEQ(begin, end,
- "arraydestroy.isempty");
- Builder.CreateCondBr(isEmpty, doneBB, bodyBB);
- }
-
- // Enter the loop body, making that address the current address.
- llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
- EmitBlock(bodyBB);
- llvm::PHINode *elementPast =
- Builder.CreatePHI(begin->getType(), 2, "arraydestroy.elementPast");
- elementPast->addIncoming(end, entryBB);
-
- // Shift the address back by one element.
- llvm::Value *negativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
- llvm::Value *element = Builder.CreateInBoundsGEP(elementPast, negativeOne,
- "arraydestroy.element");
-
- if (useEHCleanup)
- pushRegularPartialArrayCleanup(begin, element, elementType, elementAlign,
- destroyer);
-
- // Perform the actual destruction there.
- destroyer(*this, Address(element, elementAlign), elementType);
-
- if (useEHCleanup)
- PopCleanupBlock();
-
- // Check whether we've reached the end.
- llvm::Value *done = Builder.CreateICmpEQ(element, begin, "arraydestroy.done");
- Builder.CreateCondBr(done, doneBB, bodyBB);
- elementPast->addIncoming(element, Builder.GetInsertBlock());
-
- // Done.
- EmitBlock(doneBB);
-}
-
-/// Perform partial array destruction as if in an EH cleanup. Unlike
-/// emitArrayDestroy, the element type here may still be an array type.
-static void emitPartialArrayDestroy(CodeGenFunction &CGF,
- llvm::Value *begin, llvm::Value *end,
- QualType type, CharUnits elementAlign,
- CodeGenFunction::Destroyer *destroyer) {
- // If the element type is itself an array, drill down.
- unsigned arrayDepth = 0;
- while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) {
- // VLAs don't require a GEP index to walk into.
- if (!isa<VariableArrayType>(arrayType))
- arrayDepth++;
- type = arrayType->getElementType();
- }
-
- if (arrayDepth) {
- llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
-
- SmallVector<llvm::Value*,4> gepIndices(arrayDepth+1, zero);
- begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices, "pad.arraybegin");
- end = CGF.Builder.CreateInBoundsGEP(end, gepIndices, "pad.arrayend");
- }
-
- // Destroy the array. We don't ever need an EH cleanup because we
- // assume that we're in an EH cleanup ourselves, so a throwing
- // destructor causes an immediate terminate.
- CGF.emitArrayDestroy(begin, end, type, elementAlign, destroyer,
- /*checkZeroLength*/ true, /*useEHCleanup*/ false);
-}
-
-namespace {
- /// RegularPartialArrayDestroy - a cleanup which performs a partial
- /// array destroy where the end pointer is regularly determined and
- /// does not need to be loaded from a local.
- class RegularPartialArrayDestroy final : public EHScopeStack::Cleanup {
- llvm::Value *ArrayBegin;
- llvm::Value *ArrayEnd;
- QualType ElementType;
- CodeGenFunction::Destroyer *Destroyer;
- CharUnits ElementAlign;
- public:
- RegularPartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEnd,
- QualType elementType, CharUnits elementAlign,
- CodeGenFunction::Destroyer *destroyer)
- : ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
- ElementType(elementType), Destroyer(destroyer),
- ElementAlign(elementAlign) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
- ElementType, ElementAlign, Destroyer);
- }
- };
-
- /// IrregularPartialArrayDestroy - a cleanup which performs a
- /// partial array destroy where the end pointer is irregularly
- /// determined and must be loaded from a local.
- class IrregularPartialArrayDestroy final : public EHScopeStack::Cleanup {
- llvm::Value *ArrayBegin;
- Address ArrayEndPointer;
- QualType ElementType;
- CodeGenFunction::Destroyer *Destroyer;
- CharUnits ElementAlign;
- public:
- IrregularPartialArrayDestroy(llvm::Value *arrayBegin,
- Address arrayEndPointer,
- QualType elementType,
- CharUnits elementAlign,
- CodeGenFunction::Destroyer *destroyer)
- : ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
- ElementType(elementType), Destroyer(destroyer),
- ElementAlign(elementAlign) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
- emitPartialArrayDestroy(CGF, ArrayBegin, arrayEnd,
- ElementType, ElementAlign, Destroyer);
- }
- };
-} // end anonymous namespace
-
-/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy
-/// already-constructed elements of the given array. The cleanup
-/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
-///
-/// \param elementType - the immediate element type of the array;
-/// possibly still an array type
-void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
- Address arrayEndPointer,
- QualType elementType,
- CharUnits elementAlign,
- Destroyer *destroyer) {
- pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
- arrayBegin, arrayEndPointer,
- elementType, elementAlign,
- destroyer);
-}
-
-/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
-/// already-constructed elements of the given array. The cleanup
-/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
-///
-/// \param elementType - the immediate element type of the array;
-/// possibly still an array type
-void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
- llvm::Value *arrayEnd,
- QualType elementType,
- CharUnits elementAlign,
- Destroyer *destroyer) {
- pushFullExprCleanup<RegularPartialArrayDestroy>(EHCleanup,
- arrayBegin, arrayEnd,
- elementType, elementAlign,
- destroyer);
-}
-
-/// Lazily declare the @llvm.lifetime.start intrinsic.
-llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() {
- if (LifetimeStartFn)
- return LifetimeStartFn;
- LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(),
- llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy);
- return LifetimeStartFn;
-}
-
-/// Lazily declare the @llvm.lifetime.end intrinsic.
-llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() {
- if (LifetimeEndFn)
- return LifetimeEndFn;
- LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(),
- llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy);
- return LifetimeEndFn;
-}
-
-namespace {
- /// A cleanup to perform a release of an object at the end of a
- /// function. This is used to balance out the incoming +1 of a
- /// ns_consumed argument when we can't reasonably do that just by
- /// not doing the initial retain for a __block argument.
- struct ConsumeARCParameter final : EHScopeStack::Cleanup {
- ConsumeARCParameter(llvm::Value *param,
- ARCPreciseLifetime_t precise)
- : Param(param), Precise(precise) {}
-
- llvm::Value *Param;
- ARCPreciseLifetime_t Precise;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitARCRelease(Param, Precise);
- }
- };
-} // end anonymous namespace
-
-/// Emit an alloca (or GlobalValue depending on target)
-/// for the specified parameter and set up LocalDeclMap.
-void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
- unsigned ArgNo) {
- // FIXME: Why isn't ImplicitParamDecl a ParmVarDecl?
- assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
- "Invalid argument to EmitParmDecl");
-
- Arg.getAnyValue()->setName(D.getName());
-
- QualType Ty = D.getType();
-
- // Use better IR generation for certain implicit parameters.
- if (auto IPD = dyn_cast<ImplicitParamDecl>(&D)) {
- // The only implicit argument a block has is its literal.
- // This may be passed as an inalloca'ed value on Windows x86.
- if (BlockInfo) {
- llvm::Value *V = Arg.isIndirect()
- ? Builder.CreateLoad(Arg.getIndirectAddress())
- : Arg.getDirectValue();
- setBlockContextParameter(IPD, ArgNo, V);
- return;
- }
- }
-
- Address DeclPtr = Address::invalid();
- bool DoStore = false;
- bool IsScalar = hasScalarEvaluationKind(Ty);
- // If we already have a pointer to the argument, reuse the input pointer.
- if (Arg.isIndirect()) {
- DeclPtr = Arg.getIndirectAddress();
- // If we have a prettier pointer type at this point, bitcast to that.
- unsigned AS = DeclPtr.getType()->getAddressSpace();
- llvm::Type *IRTy = ConvertTypeForMem(Ty)->getPointerTo(AS);
- if (DeclPtr.getType() != IRTy)
- DeclPtr = Builder.CreateBitCast(DeclPtr, IRTy, D.getName());
- // Indirect argument is in alloca address space, which may be different
- // from the default address space.
- auto AllocaAS = CGM.getASTAllocaAddressSpace();
- auto *V = DeclPtr.getPointer();
- auto SrcLangAS = getLangOpts().OpenCL ? LangAS::opencl_private : AllocaAS;
- auto DestLangAS =
- getLangOpts().OpenCL ? LangAS::opencl_private : LangAS::Default;
- if (SrcLangAS != DestLangAS) {
- assert(getContext().getTargetAddressSpace(SrcLangAS) ==
- CGM.getDataLayout().getAllocaAddrSpace());
- auto DestAS = getContext().getTargetAddressSpace(DestLangAS);
- auto *T = V->getType()->getPointerElementType()->getPointerTo(DestAS);
- DeclPtr = Address(getTargetHooks().performAddrSpaceCast(
- *this, V, SrcLangAS, DestLangAS, T, true),
- DeclPtr.getAlignment());
- }
-
- // Push a destructor cleanup for this parameter if the ABI requires it.
- // Don't push a cleanup in a thunk for a method that will also emit a
- // cleanup.
- if (hasAggregateEvaluationKind(Ty) && !CurFuncIsThunk &&
- Ty->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
- if (QualType::DestructionKind DtorKind = Ty.isDestructedType()) {
- assert((DtorKind == QualType::DK_cxx_destructor ||
- DtorKind == QualType::DK_nontrivial_c_struct) &&
- "unexpected destructor type");
- pushDestroy(DtorKind, DeclPtr, Ty);
- CalleeDestructedParamCleanups[cast<ParmVarDecl>(&D)] =
- EHStack.stable_begin();
- }
- }
- } else {
- // Check if the parameter address is controlled by OpenMP runtime.
- Address OpenMPLocalAddr =
- getLangOpts().OpenMP
- ? CGM.getOpenMPRuntime().getAddressOfLocalVariable(*this, &D)
- : Address::invalid();
- if (getLangOpts().OpenMP && OpenMPLocalAddr.isValid()) {
- DeclPtr = OpenMPLocalAddr;
- } else {
- // Otherwise, create a temporary to hold the value.
- DeclPtr = CreateMemTemp(Ty, getContext().getDeclAlign(&D),
- D.getName() + ".addr");
- }
- DoStore = true;
- }
-
- llvm::Value *ArgVal = (DoStore ? Arg.getDirectValue() : nullptr);
-
- LValue lv = MakeAddrLValue(DeclPtr, Ty);
- if (IsScalar) {
- Qualifiers qs = Ty.getQualifiers();
- if (Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) {
- // We honor __attribute__((ns_consumed)) for types with lifetime.
- // For __strong, it's handled by just skipping the initial retain;
- // otherwise we have to balance out the initial +1 with an extra
- // cleanup to do the release at the end of the function.
- bool isConsumed = D.hasAttr<NSConsumedAttr>();
-
- // If a parameter is pseudo-strong then we can omit the implicit retain.
- if (D.isARCPseudoStrong()) {
- assert(lt == Qualifiers::OCL_Strong &&
- "pseudo-strong variable isn't strong?");
- assert(qs.hasConst() && "pseudo-strong variable should be const!");
- lt = Qualifiers::OCL_ExplicitNone;
- }
-
- // Load objects passed indirectly.
- if (Arg.isIndirect() && !ArgVal)
- ArgVal = Builder.CreateLoad(DeclPtr);
-
- if (lt == Qualifiers::OCL_Strong) {
- if (!isConsumed) {
- if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
- // use objc_storeStrong(&dest, value) for retaining the
- // object. But first, store a null into 'dest' because
- // objc_storeStrong attempts to release its old value.
- llvm::Value *Null = CGM.EmitNullConstant(D.getType());
- EmitStoreOfScalar(Null, lv, /* isInitialization */ true);
- EmitARCStoreStrongCall(lv.getAddress(), ArgVal, true);
- DoStore = false;
- }
- else
- // Don't use objc_retainBlock for block pointers, because we
- // don't want to Block_copy something just because we got it
- // as a parameter.
- ArgVal = EmitARCRetainNonBlock(ArgVal);
- }
- } else {
- // Push the cleanup for a consumed parameter.
- if (isConsumed) {
- ARCPreciseLifetime_t precise = (D.hasAttr<ObjCPreciseLifetimeAttr>()
- ? ARCPreciseLifetime : ARCImpreciseLifetime);
- EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), ArgVal,
- precise);
- }
-
- if (lt == Qualifiers::OCL_Weak) {
- EmitARCInitWeak(DeclPtr, ArgVal);
- DoStore = false; // The weak init is a store, no need to do two.
- }
- }
-
- // Enter the cleanup scope.
- EmitAutoVarWithLifetime(*this, D, DeclPtr, lt);
- }
- }
-
- // Store the initial value into the alloca.
- if (DoStore)
- EmitStoreOfScalar(ArgVal, lv, /* isInitialization */ true);
-
- setAddrOfLocalVar(&D, DeclPtr);
-
- // Emit debug info for param declaration.
- if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo) {
- DI->EmitDeclareOfArgVariable(&D, DeclPtr.getPointer(), ArgNo, Builder);
- }
- }
-
- if (D.hasAttr<AnnotateAttr>())
- EmitVarAnnotations(&D, DeclPtr.getPointer());
-
- // We can only check return value nullability if all arguments to the
- // function satisfy their nullability preconditions. This makes it necessary
- // to emit null checks for args in the function body itself.
- if (requiresReturnValueNullabilityCheck()) {
- auto Nullability = Ty->getNullability(getContext());
- if (Nullability && *Nullability == NullabilityKind::NonNull) {
- SanitizerScope SanScope(this);
- RetValNullabilityPrecondition =
- Builder.CreateAnd(RetValNullabilityPrecondition,
- Builder.CreateIsNotNull(Arg.getAnyValue()));
- }
- }
-}
-
-void CodeGenModule::EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D,
- CodeGenFunction *CGF) {
- if (!LangOpts.OpenMP || (!LangOpts.EmitAllDecls && !D->isUsed()))
- return;
- getOpenMPRuntime().emitUserDefinedReduction(CGF, D);
-}
-
-void CodeGenModule::EmitOMPRequiresDecl(const OMPRequiresDecl *D) {
- getOpenMPRuntime().checkArchForUnifiedAddressing(*this, D);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp
deleted file mode 100644
index 9aa31f181e9..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp
+++ /dev/null
@@ -1,734 +0,0 @@
-//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with code generation of C++ declarations
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
-#include "CGOpenMPRuntime.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/Support/Path.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
- ConstantAddress DeclPtr) {
- assert(
- (D.hasGlobalStorage() ||
- (D.hasLocalStorage() && CGF.getContext().getLangOpts().OpenCLCPlusPlus)) &&
- "VarDecl must have global or local (in the case of OpenCL) storage!");
- assert(!D.getType()->isReferenceType() &&
- "Should not call EmitDeclInit on a reference!");
-
- QualType type = D.getType();
- LValue lv = CGF.MakeAddrLValue(DeclPtr, type);
-
- const Expr *Init = D.getInit();
- switch (CGF.getEvaluationKind(type)) {
- case TEK_Scalar: {
- CodeGenModule &CGM = CGF.CGM;
- if (lv.isObjCStrong())
- CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
- DeclPtr, D.getTLSKind());
- else if (lv.isObjCWeak())
- CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init),
- DeclPtr);
- else
- CGF.EmitScalarInit(Init, &D, lv, false);
- return;
- }
- case TEK_Complex:
- CGF.EmitComplexExprIntoLValue(Init, lv, /*isInit*/ true);
- return;
- case TEK_Aggregate:
- CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
- return;
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-/// Emit code to cause the destruction of the given variable with
-/// static storage duration.
-static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
- ConstantAddress Addr) {
- // Honor __attribute__((no_destroy)) and bail instead of attempting
- // to emit a reference to a possibly nonexistent destructor, which
- // in turn can cause a crash. This will result in a global constructor
- // that isn't balanced out by a destructor call as intended by the
- // attribute. This also checks for -fno-c++-static-destructors and
- // bails even if the attribute is not present.
- if (D.isNoDestroy(CGF.getContext()))
- return;
-
- CodeGenModule &CGM = CGF.CGM;
-
- // FIXME: __attribute__((cleanup)) ?
-
- QualType Type = D.getType();
- QualType::DestructionKind DtorKind = Type.isDestructedType();
-
- switch (DtorKind) {
- case QualType::DK_none:
- return;
-
- case QualType::DK_cxx_destructor:
- break;
-
- case QualType::DK_objc_strong_lifetime:
- case QualType::DK_objc_weak_lifetime:
- case QualType::DK_nontrivial_c_struct:
- // We don't care about releasing objects during process teardown.
- assert(!D.getTLSKind() && "should have rejected this");
- return;
- }
-
- llvm::Constant *Func;
- llvm::Constant *Argument;
-
- // Special-case non-array C++ destructors, if they have the right signature.
- // Under some ABIs, destructors return this instead of void, and cannot be
- // passed directly to __cxa_atexit if the target does not allow this
- // mismatch.
- const CXXRecordDecl *Record = Type->getAsCXXRecordDecl();
- bool CanRegisterDestructor =
- Record && (!CGM.getCXXABI().HasThisReturn(
- GlobalDecl(Record->getDestructor(), Dtor_Complete)) ||
- CGM.getCXXABI().canCallMismatchedFunctionType());
- // If __cxa_atexit is disabled via a flag, a different helper function is
- // generated elsewhere which uses atexit instead, and it takes the destructor
- // directly.
- bool UsingExternalHelper = !CGM.getCodeGenOpts().CXAAtExit;
- if (Record && (CanRegisterDestructor || UsingExternalHelper)) {
- assert(!Record->hasTrivialDestructor());
- CXXDestructorDecl *Dtor = Record->getDestructor();
-
- Func = CGM.getAddrOfCXXStructor(Dtor, StructorType::Complete);
- Argument = llvm::ConstantExpr::getBitCast(
- Addr.getPointer(), CGF.getTypes().ConvertType(Type)->getPointerTo());
-
- // Otherwise, the standard logic requires a helper function.
- } else {
- Func = CodeGenFunction(CGM)
- .generateDestroyHelper(Addr, Type, CGF.getDestroyer(DtorKind),
- CGF.needsEHCleanup(DtorKind), &D);
- Argument = llvm::Constant::getNullValue(CGF.Int8PtrTy);
- }
-
- CGM.getCXXABI().registerGlobalDtor(CGF, D, Func, Argument);
-}
-
-/// Emit code to cause the variable at the given address to be considered as
-/// constant from this point onwards.
-static void EmitDeclInvariant(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *Addr) {
- return CGF.EmitInvariantStart(
- Addr, CGF.getContext().getTypeSizeInChars(D.getType()));
-}
-
-void CodeGenFunction::EmitInvariantStart(llvm::Constant *Addr, CharUnits Size) {
- // Do not emit the intrinsic if we're not optimizing.
- if (!CGM.getCodeGenOpts().OptimizationLevel)
- return;
-
- // Grab the llvm.invariant.start intrinsic.
- llvm::Intrinsic::ID InvStartID = llvm::Intrinsic::invariant_start;
- // Overloaded address space type.
- llvm::Type *ObjectPtr[1] = {Int8PtrTy};
- llvm::Constant *InvariantStart = CGM.getIntrinsic(InvStartID, ObjectPtr);
-
- // Emit a call with the size in bytes of the object.
- uint64_t Width = Size.getQuantity();
- llvm::Value *Args[2] = { llvm::ConstantInt::getSigned(Int64Ty, Width),
- llvm::ConstantExpr::getBitCast(Addr, Int8PtrTy)};
- Builder.CreateCall(InvariantStart, Args);
-}
-
-void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
- llvm::Constant *DeclPtr,
- bool PerformInit) {
-
- const Expr *Init = D.getInit();
- QualType T = D.getType();
-
- // The address space of a static local variable (DeclPtr) may be different
- // from the address space of the "this" argument of the constructor. In that
- // case, we need an addrspacecast before calling the constructor.
- //
- // struct StructWithCtor {
- // __device__ StructWithCtor() {...}
- // };
- // __device__ void foo() {
- // __shared__ StructWithCtor s;
- // ...
- // }
- //
- // For example, in the above CUDA code, the static local variable s has a
- // "shared" address space qualifier, but the constructor of StructWithCtor
- // expects "this" in the "generic" address space.
- unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(T);
- unsigned ActualAddrSpace = DeclPtr->getType()->getPointerAddressSpace();
- if (ActualAddrSpace != ExpectedAddrSpace) {
- llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(T);
- llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace);
- DeclPtr = llvm::ConstantExpr::getAddrSpaceCast(DeclPtr, PTy);
- }
-
- ConstantAddress DeclAddr(DeclPtr, getContext().getDeclAlign(&D));
-
- if (!T->isReferenceType()) {
- if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd &&
- D.hasAttr<OMPThreadPrivateDeclAttr>()) {
- (void)CGM.getOpenMPRuntime().emitThreadPrivateVarDefinition(
- &D, DeclAddr, D.getAttr<OMPThreadPrivateDeclAttr>()->getLocation(),
- PerformInit, this);
- }
- if (PerformInit)
- EmitDeclInit(*this, D, DeclAddr);
- if (CGM.isTypeConstant(D.getType(), true))
- EmitDeclInvariant(*this, D, DeclPtr);
- else
- EmitDeclDestroy(*this, D, DeclAddr);
- return;
- }
-
- assert(PerformInit && "cannot have constant initializer which needs "
- "destruction for reference");
- RValue RV = EmitReferenceBindingToExpr(Init);
- EmitStoreOfScalar(RV.getScalarVal(), DeclAddr, false, T);
-}
-
-/// Create a stub function, suitable for being passed to atexit,
-/// which passes the given address to the given destructor function.
-llvm::Constant *CodeGenFunction::createAtExitStub(const VarDecl &VD,
- llvm::Constant *dtor,
- llvm::Constant *addr) {
- // Get the destructor function type, void(*)(void).
- llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false);
- SmallString<256> FnName;
- {
- llvm::raw_svector_ostream Out(FnName);
- CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out);
- }
-
- const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
- llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(ty, FnName.str(),
- FI,
- VD.getLocation());
-
- CodeGenFunction CGF(CGM);
-
- CGF.StartFunction(&VD, CGM.getContext().VoidTy, fn, FI, FunctionArgList());
-
- llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
-
- // Make sure the call and the callee agree on calling convention.
- if (llvm::Function *dtorFn =
- dyn_cast<llvm::Function>(dtor->stripPointerCasts()))
- call->setCallingConv(dtorFn->getCallingConv());
-
- CGF.FinishFunction();
-
- return fn;
-}
-
-/// Register a global destructor using the C atexit runtime function.
-void CodeGenFunction::registerGlobalDtorWithAtExit(const VarDecl &VD,
- llvm::Constant *dtor,
- llvm::Constant *addr) {
- // Create a function which calls the destructor.
- llvm::Constant *dtorStub = createAtExitStub(VD, dtor, addr);
- registerGlobalDtorWithAtExit(dtorStub);
-}
-
-void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtorStub) {
- // extern "C" int atexit(void (*f)(void));
- llvm::FunctionType *atexitTy =
- llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
-
- llvm::Constant *atexit =
- CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeList(),
- /*Local=*/true);
- if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit))
- atexitFn->setDoesNotThrow();
-
- EmitNounwindRuntimeCall(atexit, dtorStub);
-}
-
-void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
- llvm::GlobalVariable *DeclPtr,
- bool PerformInit) {
- // If we've been asked to forbid guard variables, emit an error now.
- // This diagnostic is hard-coded for Darwin's use case; we can find
- // better phrasing if someone else needs it.
- if (CGM.getCodeGenOpts().ForbidGuardVariables)
- CGM.Error(D.getLocation(),
- "this initialization requires a guard variable, which "
- "the kernel does not support");
-
- CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
-}
-
-void CodeGenFunction::EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
- llvm::BasicBlock *InitBlock,
- llvm::BasicBlock *NoInitBlock,
- GuardKind Kind,
- const VarDecl *D) {
- assert((Kind == GuardKind::TlsGuard || D) && "no guarded variable");
-
- // A guess at how many times we will enter the initialization of a
- // variable, depending on the kind of variable.
- static const uint64_t InitsPerTLSVar = 1024;
- static const uint64_t InitsPerLocalVar = 1024 * 1024;
-
- llvm::MDNode *Weights;
- if (Kind == GuardKind::VariableGuard && !D->isLocalVarDecl()) {
- // For non-local variables, don't apply any weighting for now. Due to our
- // use of COMDATs, we expect there to be at most one initialization of the
- // variable per DSO, but we have no way to know how many DSOs will try to
- // initialize the variable.
- Weights = nullptr;
- } else {
- uint64_t NumInits;
- // FIXME: For the TLS case, collect and use profiling information to
- // determine a more accurate brach weight.
- if (Kind == GuardKind::TlsGuard || D->getTLSKind())
- NumInits = InitsPerTLSVar;
- else
- NumInits = InitsPerLocalVar;
-
- // The probability of us entering the initializer is
- // 1 / (total number of times we attempt to initialize the variable).
- llvm::MDBuilder MDHelper(CGM.getLLVMContext());
- Weights = MDHelper.createBranchWeights(1, NumInits - 1);
- }
-
- Builder.CreateCondBr(NeedsInit, InitBlock, NoInitBlock, Weights);
-}
-
-llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
- llvm::FunctionType *FTy, const Twine &Name, const CGFunctionInfo &FI,
- SourceLocation Loc, bool TLS) {
- llvm::Function *Fn =
- llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
- Name, &getModule());
- if (!getLangOpts().AppleKext && !TLS) {
- // Set the section if needed.
- if (const char *Section = getTarget().getStaticInitSectionSpecifier())
- Fn->setSection(Section);
- }
-
- SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
- Fn->setCallingConv(getRuntimeCC());
-
- if (!getLangOpts().Exceptions)
- Fn->setDoesNotThrow();
-
- if (getLangOpts().Sanitize.has(SanitizerKind::Address) &&
- !isInSanitizerBlacklist(SanitizerKind::Address, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::KernelAddress) &&
- !isInSanitizerBlacklist(SanitizerKind::KernelAddress, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::HWAddress) &&
- !isInSanitizerBlacklist(SanitizerKind::HWAddress, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::KernelHWAddress) &&
- !isInSanitizerBlacklist(SanitizerKind::KernelHWAddress, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
- !isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SanitizeThread);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
- !isInSanitizerBlacklist(SanitizerKind::Memory, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::KernelMemory) &&
- !isInSanitizerBlacklist(SanitizerKind::KernelMemory, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack) &&
- !isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::SafeStack);
-
- if (getLangOpts().Sanitize.has(SanitizerKind::ShadowCallStack) &&
- !isInSanitizerBlacklist(SanitizerKind::ShadowCallStack, Fn, Loc))
- Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
-
- auto RASignKind = getCodeGenOpts().getSignReturnAddress();
- if (RASignKind != CodeGenOptions::SignReturnAddressScope::None) {
- Fn->addFnAttr("sign-return-address",
- RASignKind == CodeGenOptions::SignReturnAddressScope::All
- ? "all"
- : "non-leaf");
- auto RASignKey = getCodeGenOpts().getSignReturnAddressKey();
- Fn->addFnAttr("sign-return-address-key",
- RASignKey == CodeGenOptions::SignReturnAddressKeyValue::AKey
- ? "a_key"
- : "b_key");
- }
-
- if (getCodeGenOpts().BranchTargetEnforcement)
- Fn->addFnAttr("branch-target-enforcement");
-
- return Fn;
-}
-
-/// Create a global pointer to a function that will initialize a global
-/// variable. The user has requested that this pointer be emitted in a specific
-/// section.
-void CodeGenModule::EmitPointerToInitFunc(const VarDecl *D,
- llvm::GlobalVariable *GV,
- llvm::Function *InitFunc,
- InitSegAttr *ISA) {
- llvm::GlobalVariable *PtrArray = new llvm::GlobalVariable(
- TheModule, InitFunc->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, InitFunc, "__cxx_init_fn_ptr");
- PtrArray->setSection(ISA->getSection());
- addUsedGlobal(PtrArray);
-
- // If the GV is already in a comdat group, then we have to join it.
- if (llvm::Comdat *C = GV->getComdat())
- PtrArray->setComdat(C);
-}
-
-void
-CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
- llvm::GlobalVariable *Addr,
- bool PerformInit) {
-
- // According to E.2.3.1 in CUDA-7.5 Programming guide: __device__,
- // __constant__ and __shared__ variables defined in namespace scope,
- // that are of class type, cannot have a non-empty constructor. All
- // the checks have been done in Sema by now. Whatever initializers
- // are allowed are empty and we just need to ignore them here.
- if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
- (D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>() ||
- D->hasAttr<CUDASharedAttr>()))
- return;
-
- if (getLangOpts().OpenMP &&
- getOpenMPRuntime().emitDeclareTargetVarDefinition(D, Addr, PerformInit))
- return;
-
- // Check if we've already initialized this decl.
- auto I = DelayedCXXInitPosition.find(D);
- if (I != DelayedCXXInitPosition.end() && I->second == ~0U)
- return;
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- SmallString<256> FnName;
- {
- llvm::raw_svector_ostream Out(FnName);
- getCXXABI().getMangleContext().mangleDynamicInitializer(D, Out);
- }
-
- // Create a variable initialization function.
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(FTy, FnName.str(),
- getTypes().arrangeNullaryFunction(),
- D->getLocation());
-
- auto *ISA = D->getAttr<InitSegAttr>();
- CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
- PerformInit);
-
- llvm::GlobalVariable *COMDATKey =
- supportsCOMDAT() && D->isExternallyVisible() ? Addr : nullptr;
-
- if (D->getTLSKind()) {
- // FIXME: Should we support init_priority for thread_local?
- // FIXME: We only need to register one __cxa_thread_atexit function for the
- // entire TU.
- CXXThreadLocalInits.push_back(Fn);
- CXXThreadLocalInitVars.push_back(D);
- } else if (PerformInit && ISA) {
- EmitPointerToInitFunc(D, Addr, Fn, ISA);
- } else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
- OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size());
- PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
- } else if (isTemplateInstantiation(D->getTemplateSpecializationKind())) {
- // C++ [basic.start.init]p2:
- // Definitions of explicitly specialized class template static data
- // members have ordered initialization. Other class template static data
- // members (i.e., implicitly or explicitly instantiated specializations)
- // have unordered initialization.
- //
- // As a consequence, we can put them into their own llvm.global_ctors entry.
- //
- // If the global is externally visible, put the initializer into a COMDAT
- // group with the global being initialized. On most platforms, this is a
- // minor startup time optimization. In the MS C++ ABI, there are no guard
- // variables, so this COMDAT key is required for correctness.
- AddGlobalCtor(Fn, 65535, COMDATKey);
- } else if (D->hasAttr<SelectAnyAttr>()) {
- // SelectAny globals will be comdat-folded. Put the initializer into a
- // COMDAT group associated with the global, so the initializers get folded
- // too.
- AddGlobalCtor(Fn, 65535, COMDATKey);
- } else {
- I = DelayedCXXInitPosition.find(D); // Re-do lookup in case of re-hash.
- if (I == DelayedCXXInitPosition.end()) {
- CXXGlobalInits.push_back(Fn);
- } else if (I->second != ~0U) {
- assert(I->second < CXXGlobalInits.size() &&
- CXXGlobalInits[I->second] == nullptr);
- CXXGlobalInits[I->second] = Fn;
- }
- }
-
- // Remember that we already emitted the initializer for this global.
- DelayedCXXInitPosition[D] = ~0U;
-}
-
-void CodeGenModule::EmitCXXThreadLocalInitFunc() {
- getCXXABI().EmitThreadLocalInitFuncs(
- *this, CXXThreadLocals, CXXThreadLocalInits, CXXThreadLocalInitVars);
-
- CXXThreadLocalInits.clear();
- CXXThreadLocalInitVars.clear();
- CXXThreadLocals.clear();
-}
-
-void
-CodeGenModule::EmitCXXGlobalInitFunc() {
- while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
- CXXGlobalInits.pop_back();
-
- if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty())
- return;
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
-
- // Create our global initialization function.
- if (!PrioritizedCXXGlobalInits.empty()) {
- SmallVector<llvm::Function *, 8> LocalCXXGlobalInits;
- llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
- PrioritizedCXXGlobalInits.end());
- // Iterate over "chunks" of ctors with same priority and emit each chunk
- // into separate function. Note - everything is sorted first by priority,
- // second - by lex order, so we emit ctor functions in proper order.
- for (SmallVectorImpl<GlobalInitData >::iterator
- I = PrioritizedCXXGlobalInits.begin(),
- E = PrioritizedCXXGlobalInits.end(); I != E; ) {
- SmallVectorImpl<GlobalInitData >::iterator
- PrioE = std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp());
-
- LocalCXXGlobalInits.clear();
- unsigned Priority = I->first.priority;
- // Compute the function suffix from priority. Prepend with zeroes to make
- // sure the function names are also ordered as priorities.
- std::string PrioritySuffix = llvm::utostr(Priority);
- // Priority is always <= 65535 (enforced by sema).
- PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
- llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
- FTy, "_GLOBAL__I_" + PrioritySuffix, FI);
-
- for (; I < PrioE; ++I)
- LocalCXXGlobalInits.push_back(I->second);
-
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, LocalCXXGlobalInits);
- AddGlobalCtor(Fn, Priority);
- }
- PrioritizedCXXGlobalInits.clear();
- }
-
- // Include the filename in the symbol name. Including "sub_" matches gcc and
- // makes sure these symbols appear lexicographically behind the symbols with
- // priority emitted above.
- SmallString<128> FileName = llvm::sys::path::filename(getModule().getName());
- if (FileName.empty())
- FileName = "<null>";
-
- for (size_t i = 0; i < FileName.size(); ++i) {
- // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
- // to be the set of C preprocessing numbers.
- if (!isPreprocessingNumberBody(FileName[i]))
- FileName[i] = '_';
- }
-
- llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
- FTy, llvm::Twine("_GLOBAL__sub_I_", FileName), FI);
-
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
- AddGlobalCtor(Fn);
-
- CXXGlobalInits.clear();
-}
-
-void CodeGenModule::EmitCXXGlobalDtorFunc() {
- if (CXXGlobalDtors.empty())
- return;
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
-
- // Create our global destructor function.
- const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a", FI);
-
- CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
- AddGlobalDtor(Fn);
-}
-
-/// Emit the code necessary to initialize the given global variable.
-void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
- const VarDecl *D,
- llvm::GlobalVariable *Addr,
- bool PerformInit) {
- // Check if we need to emit debug info for variable initializer.
- if (D->hasAttr<NoDebugAttr>())
- DebugInfo = nullptr; // disable debug info indefinitely for this function
-
- CurEHLocation = D->getBeginLoc();
-
- StartFunction(GlobalDecl(D), getContext().VoidTy, Fn,
- getTypes().arrangeNullaryFunction(),
- FunctionArgList(), D->getLocation(),
- D->getInit()->getExprLoc());
-
- // Use guarded initialization if the global variable is weak. This
- // occurs for, e.g., instantiated static data members and
- // definitions explicitly marked weak.
- if (Addr->hasWeakLinkage() || Addr->hasLinkOnceLinkage()) {
- EmitCXXGuardedInit(*D, Addr, PerformInit);
- } else {
- EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
- }
-
- FinishFunction();
-}
-
-void
-CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- ArrayRef<llvm::Function *> Decls,
- ConstantAddress Guard) {
- {
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().arrangeNullaryFunction(), FunctionArgList());
- // Emit an artificial location for this function.
- auto AL = ApplyDebugLocation::CreateArtificial(*this);
-
- llvm::BasicBlock *ExitBlock = nullptr;
- if (Guard.isValid()) {
- // If we have a guard variable, check whether we've already performed
- // these initializations. This happens for TLS initialization functions.
- llvm::Value *GuardVal = Builder.CreateLoad(Guard);
- llvm::Value *Uninit = Builder.CreateIsNull(GuardVal,
- "guard.uninitialized");
- llvm::BasicBlock *InitBlock = createBasicBlock("init");
- ExitBlock = createBasicBlock("exit");
- EmitCXXGuardedInitBranch(Uninit, InitBlock, ExitBlock,
- GuardKind::TlsGuard, nullptr);
- EmitBlock(InitBlock);
- // Mark as initialized before initializing anything else. If the
- // initializers use previously-initialized thread_local vars, that's
- // probably supposed to be OK, but the standard doesn't say.
- Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(),1), Guard);
-
- // The guard variable can't ever change again.
- EmitInvariantStart(
- Guard.getPointer(),
- CharUnits::fromQuantity(
- CGM.getDataLayout().getTypeAllocSize(GuardVal->getType())));
- }
-
- RunCleanupsScope Scope(*this);
-
- // When building in Objective-C++ ARC mode, create an autorelease pool
- // around the global initializers.
- if (getLangOpts().ObjCAutoRefCount && getLangOpts().CPlusPlus) {
- llvm::Value *token = EmitObjCAutoreleasePoolPush();
- EmitObjCAutoreleasePoolCleanup(token);
- }
-
- for (unsigned i = 0, e = Decls.size(); i != e; ++i)
- if (Decls[i])
- EmitRuntimeCall(Decls[i]);
-
- Scope.ForceCleanup();
-
- if (ExitBlock) {
- Builder.CreateBr(ExitBlock);
- EmitBlock(ExitBlock);
- }
- }
-
- FinishFunction();
-}
-
-void CodeGenFunction::GenerateCXXGlobalDtorsFunc(
- llvm::Function *Fn,
- const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>>
- &DtorsAndObjects) {
- {
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().arrangeNullaryFunction(), FunctionArgList());
- // Emit an artificial location for this function.
- auto AL = ApplyDebugLocation::CreateArtificial(*this);
-
- // Emit the dtors, in reverse order from construction.
- for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
- llvm::Value *Callee = DtorsAndObjects[e - i - 1].first;
- llvm::CallInst *CI = Builder.CreateCall(Callee,
- DtorsAndObjects[e - i - 1].second);
- // Make sure the call and the callee agree on calling convention.
- if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
- CI->setCallingConv(F->getCallingConv());
- }
- }
-
- FinishFunction();
-}
-
-/// generateDestroyHelper - Generates a helper function which, when
-/// invoked, destroys the given object. The address of the object
-/// should be in global memory.
-llvm::Function *CodeGenFunction::generateDestroyHelper(
- Address addr, QualType type, Destroyer *destroyer,
- bool useEHCleanupForArray, const VarDecl *VD) {
- FunctionArgList args;
- ImplicitParamDecl Dst(getContext(), getContext().VoidPtrTy,
- ImplicitParamDecl::Other);
- args.push_back(&Dst);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(getContext().VoidTy, args);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(
- FTy, "__cxx_global_array_dtor", FI, VD->getLocation());
-
- CurEHLocation = VD->getBeginLoc();
-
- StartFunction(VD, getContext().VoidTy, fn, FI, args);
-
- emitDestroy(addr, type, destroyer, useEHCleanupForArray);
-
- FinishFunction();
-
- return fn;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGException.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGException.cpp
deleted file mode 100644
index 5756e13d262..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGException.cpp
+++ /dev/null
@@ -1,2114 +0,0 @@
-//===--- CGException.cpp - Emit LLVM Code for C++ exceptions ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ exception related code generation.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-#include "CGObjCRuntime.h"
-#include "ConstantEmitter.h"
-#include "TargetInfo.h"
-#include "clang/AST/Mangle.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/TargetBuiltins.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/Support/SaveAndRestore.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-static llvm::Constant *getFreeExceptionFn(CodeGenModule &CGM) {
- // void __cxa_free_exception(void *thrown_exception);
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
-}
-
-static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {
- // void __cxa_call_unexpected(void *thrown_exception);
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
-}
-
-llvm::Constant *CodeGenModule::getTerminateFn() {
- // void __terminate();
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, /*IsVarArgs=*/false);
-
- StringRef name;
-
- // In C++, use std::terminate().
- if (getLangOpts().CPlusPlus &&
- getTarget().getCXXABI().isItaniumFamily()) {
- name = "_ZSt9terminatev";
- } else if (getLangOpts().CPlusPlus &&
- getTarget().getCXXABI().isMicrosoft()) {
- if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015))
- name = "__std_terminate";
- else
- name = "?terminate@@YAXXZ";
- } else if (getLangOpts().ObjC &&
- getLangOpts().ObjCRuntime.hasTerminate())
- name = "objc_terminate";
- else
- name = "abort";
- return CreateRuntimeFunction(FTy, name);
-}
-
-static llvm::Constant *getCatchallRethrowFn(CodeGenModule &CGM,
- StringRef Name) {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, Name);
-}
-
-const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", nullptr };
-const EHPersonality
-EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", nullptr };
-const EHPersonality
-EHPersonality::GNU_C_SEH = { "__gcc_personality_seh0", nullptr };
-const EHPersonality
-EHPersonality::NeXT_ObjC = { "__objc_personality_v0", nullptr };
-const EHPersonality
-EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", nullptr };
-const EHPersonality
-EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", nullptr };
-const EHPersonality
-EHPersonality::GNU_CPlusPlus_SEH = { "__gxx_personality_seh0", nullptr };
-const EHPersonality
-EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};
-const EHPersonality
-EHPersonality::GNU_ObjC_SJLJ = {"__gnu_objc_personality_sj0", "objc_exception_throw"};
-const EHPersonality
-EHPersonality::GNU_ObjC_SEH = {"__gnu_objc_personality_seh0", "objc_exception_throw"};
-const EHPersonality
-EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };
-const EHPersonality
-EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };
-const EHPersonality
-EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr };
-const EHPersonality
-EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr };
-const EHPersonality
-EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr };
-const EHPersonality
-EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr };
-
-static const EHPersonality &getCPersonality(const TargetInfo &Target,
- const LangOptions &L) {
- const llvm::Triple &T = Target.getTriple();
- if (T.isWindowsMSVCEnvironment())
- return EHPersonality::MSVC_CxxFrameHandler3;
- if (L.SjLjExceptions)
- return EHPersonality::GNU_C_SJLJ;
- if (L.DWARFExceptions)
- return EHPersonality::GNU_C;
- if (L.SEHExceptions)
- return EHPersonality::GNU_C_SEH;
- return EHPersonality::GNU_C;
-}
-
-static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
- const LangOptions &L) {
- const llvm::Triple &T = Target.getTriple();
- if (T.isWindowsMSVCEnvironment())
- return EHPersonality::MSVC_CxxFrameHandler3;
-
- switch (L.ObjCRuntime.getKind()) {
- case ObjCRuntime::FragileMacOSX:
- return getCPersonality(Target, L);
- case ObjCRuntime::MacOSX:
- case ObjCRuntime::iOS:
- case ObjCRuntime::WatchOS:
- return EHPersonality::NeXT_ObjC;
- case ObjCRuntime::GNUstep:
- if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
- return EHPersonality::GNUstep_ObjC;
- LLVM_FALLTHROUGH;
- case ObjCRuntime::GCC:
- case ObjCRuntime::ObjFW:
- if (L.SjLjExceptions)
- return EHPersonality::GNU_ObjC_SJLJ;
- if (L.SEHExceptions)
- return EHPersonality::GNU_ObjC_SEH;
- return EHPersonality::GNU_ObjC;
- }
- llvm_unreachable("bad runtime kind");
-}
-
-static const EHPersonality &getCXXPersonality(const TargetInfo &Target,
- const LangOptions &L) {
- const llvm::Triple &T = Target.getTriple();
- if (T.isWindowsMSVCEnvironment())
- return EHPersonality::MSVC_CxxFrameHandler3;
- if (L.SjLjExceptions)
- return EHPersonality::GNU_CPlusPlus_SJLJ;
- if (L.DWARFExceptions)
- return EHPersonality::GNU_CPlusPlus;
- if (L.SEHExceptions)
- return EHPersonality::GNU_CPlusPlus_SEH;
- // Wasm EH is a non-MVP feature for now.
- if (Target.hasFeature("exception-handling") &&
- (T.getArch() == llvm::Triple::wasm32 ||
- T.getArch() == llvm::Triple::wasm64))
- return EHPersonality::GNU_Wasm_CPlusPlus;
- return EHPersonality::GNU_CPlusPlus;
-}
-
-/// Determines the personality function to use when both C++
-/// and Objective-C exceptions are being caught.
-static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
- const LangOptions &L) {
- if (Target.getTriple().isWindowsMSVCEnvironment())
- return EHPersonality::MSVC_CxxFrameHandler3;
-
- switch (L.ObjCRuntime.getKind()) {
- // In the fragile ABI, just use C++ exception handling and hope
- // they're not doing crazy exception mixing.
- case ObjCRuntime::FragileMacOSX:
- return getCXXPersonality(Target, L);
-
- // The ObjC personality defers to the C++ personality for non-ObjC
- // handlers. Unlike the C++ case, we use the same personality
- // function on targets using (backend-driven) SJLJ EH.
- case ObjCRuntime::MacOSX:
- case ObjCRuntime::iOS:
- case ObjCRuntime::WatchOS:
- return getObjCPersonality(Target, L);
-
- case ObjCRuntime::GNUstep:
- return EHPersonality::GNU_ObjCXX;
-
- // The GCC runtime's personality function inherently doesn't support
- // mixed EH. Use the ObjC personality just to avoid returning null.
- case ObjCRuntime::GCC:
- case ObjCRuntime::ObjFW:
- return getObjCPersonality(Target, L);
- }
- llvm_unreachable("bad runtime kind");
-}
-
-static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &T) {
- if (T.getArch() == llvm::Triple::x86)
- return EHPersonality::MSVC_except_handler;
- return EHPersonality::MSVC_C_specific_handler;
-}
-
-const EHPersonality &EHPersonality::get(CodeGenModule &CGM,
- const FunctionDecl *FD) {
- const llvm::Triple &T = CGM.getTarget().getTriple();
- const LangOptions &L = CGM.getLangOpts();
- const TargetInfo &Target = CGM.getTarget();
-
- // Functions using SEH get an SEH personality.
- if (FD && FD->usesSEHTry())
- return getSEHPersonalityMSVC(T);
-
- if (L.ObjC)
- return L.CPlusPlus ? getObjCXXPersonality(Target, L)
- : getObjCPersonality(Target, L);
- return L.CPlusPlus ? getCXXPersonality(Target, L)
- : getCPersonality(Target, L);
-}
-
-const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) {
- const auto *FD = CGF.CurCodeDecl;
- // For outlined finallys and filters, use the SEH personality in case they
- // contain more SEH. This mostly only affects finallys. Filters could
- // hypothetically use gnu statement expressions to sneak in nested SEH.
- FD = FD ? FD : CGF.CurSEHParent;
- return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(FD));
-}
-
-static llvm::Constant *getPersonalityFn(CodeGenModule &CGM,
- const EHPersonality &Personality) {
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true),
- Personality.PersonalityFn,
- llvm::AttributeList(), /*Local=*/true);
-}
-
-static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM,
- const EHPersonality &Personality) {
- llvm::Constant *Fn = getPersonalityFn(CGM, Personality);
- llvm::PointerType* Int8PtrTy = llvm::PointerType::get(
- llvm::Type::getInt8Ty(CGM.getLLVMContext()),
- CGM.getDataLayout().getProgramAddressSpace());
-
- return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
-}
-
-/// Check whether a landingpad instruction only uses C++ features.
-static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) {
- for (unsigned I = 0, E = LPI->getNumClauses(); I != E; ++I) {
- // Look for something that would've been returned by the ObjC
- // runtime's GetEHType() method.
- llvm::Value *Val = LPI->getClause(I)->stripPointerCasts();
- if (LPI->isCatch(I)) {
- // Check if the catch value has the ObjC prefix.
- if (llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Val))
- // ObjC EH selector entries are always global variables with
- // names starting like this.
- if (GV->getName().startswith("OBJC_EHTYPE"))
- return false;
- } else {
- // Check if any of the filter values have the ObjC prefix.
- llvm::Constant *CVal = cast<llvm::Constant>(Val);
- for (llvm::User::op_iterator
- II = CVal->op_begin(), IE = CVal->op_end(); II != IE; ++II) {
- if (llvm::GlobalVariable *GV =
- cast<llvm::GlobalVariable>((*II)->stripPointerCasts()))
- // ObjC EH selector entries are always global variables with
- // names starting like this.
- if (GV->getName().startswith("OBJC_EHTYPE"))
- return false;
- }
- }
- }
- return true;
-}
-
-/// Check whether a personality function could reasonably be swapped
-/// for a C++ personality function.
-static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
- for (llvm::User *U : Fn->users()) {
- // Conditionally white-list bitcasts.
- if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(U)) {
- if (CE->getOpcode() != llvm::Instruction::BitCast) return false;
- if (!PersonalityHasOnlyCXXUses(CE))
- return false;
- continue;
- }
-
- // Otherwise it must be a function.
- llvm::Function *F = dyn_cast<llvm::Function>(U);
- if (!F) return false;
-
- for (auto BB = F->begin(), E = F->end(); BB != E; ++BB) {
- if (BB->isLandingPad())
- if (!LandingPadHasOnlyCXXUses(BB->getLandingPadInst()))
- return false;
- }
- }
-
- return true;
-}
-
-/// Try to use the C++ personality function in ObjC++. Not doing this
-/// can cause some incompatibilities with gcc, which is more
-/// aggressive about only using the ObjC++ personality in a function
-/// when it really needs it.
-void CodeGenModule::SimplifyPersonality() {
- // If we're not in ObjC++ -fexceptions, there's nothing to do.
- if (!LangOpts.CPlusPlus || !LangOpts.ObjC || !LangOpts.Exceptions)
- return;
-
- // Both the problem this endeavors to fix and the way the logic
- // above works is specific to the NeXT runtime.
- if (!LangOpts.ObjCRuntime.isNeXTFamily())
- return;
-
- const EHPersonality &ObjCXX = EHPersonality::get(*this, /*FD=*/nullptr);
- const EHPersonality &CXX = getCXXPersonality(getTarget(), LangOpts);
- if (&ObjCXX == &CXX)
- return;
-
- assert(std::strcmp(ObjCXX.PersonalityFn, CXX.PersonalityFn) != 0 &&
- "Different EHPersonalities using the same personality function.");
-
- llvm::Function *Fn = getModule().getFunction(ObjCXX.PersonalityFn);
-
- // Nothing to do if it's unused.
- if (!Fn || Fn->use_empty()) return;
-
- // Can't do the optimization if it has non-C++ uses.
- if (!PersonalityHasOnlyCXXUses(Fn)) return;
-
- // Create the C++ personality function and kill off the old
- // function.
- llvm::Constant *CXXFn = getPersonalityFn(*this, CXX);
-
- // This can happen if the user is screwing with us.
- if (Fn->getType() != CXXFn->getType()) return;
-
- Fn->replaceAllUsesWith(CXXFn);
- Fn->eraseFromParent();
-}
-
-/// Returns the value to inject into a selector to indicate the
-/// presence of a catch-all.
-static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) {
- // Possibly we should use @llvm.eh.catch.all.value here.
- return llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
-}
-
-namespace {
- /// A cleanup to free the exception object if its initialization
- /// throws.
- struct FreeException final : EHScopeStack::Cleanup {
- llvm::Value *exn;
- FreeException(llvm::Value *exn) : exn(exn) {}
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn);
- }
- };
-} // end anonymous namespace
-
-// Emits an exception expression into the given location. This
-// differs from EmitAnyExprToMem only in that, if a final copy-ctor
-// call is required, an exception within that copy ctor causes
-// std::terminate to be invoked.
-void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) {
- // Make sure the exception object is cleaned up if there's an
- // exception during initialization.
- pushFullExprCleanup<FreeException>(EHCleanup, addr.getPointer());
- EHScopeStack::stable_iterator cleanup = EHStack.stable_begin();
-
- // __cxa_allocate_exception returns a void*; we need to cast this
- // to the appropriate type for the object.
- llvm::Type *ty = ConvertTypeForMem(e->getType())->getPointerTo();
- Address typedAddr = Builder.CreateBitCast(addr, ty);
-
- // FIXME: this isn't quite right! If there's a final unelided call
- // to a copy constructor, then according to [except.terminate]p1 we
- // must call std::terminate() if that constructor throws, because
- // technically that copy occurs after the exception expression is
- // evaluated but before the exception is caught. But the best way
- // to handle that is to teach EmitAggExpr to do the final copy
- // differently if it can't be elided.
- EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
- /*IsInit*/ true);
-
- // Deactivate the cleanup block.
- DeactivateCleanupBlock(cleanup,
- cast<llvm::Instruction>(typedAddr.getPointer()));
-}
-
-Address CodeGenFunction::getExceptionSlot() {
- if (!ExceptionSlot)
- ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot");
- return Address(ExceptionSlot, getPointerAlign());
-}
-
-Address CodeGenFunction::getEHSelectorSlot() {
- if (!EHSelectorSlot)
- EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot");
- return Address(EHSelectorSlot, CharUnits::fromQuantity(4));
-}
-
-llvm::Value *CodeGenFunction::getExceptionFromSlot() {
- return Builder.CreateLoad(getExceptionSlot(), "exn");
-}
-
-llvm::Value *CodeGenFunction::getSelectorFromSlot() {
- return Builder.CreateLoad(getEHSelectorSlot(), "sel");
-}
-
-void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
- bool KeepInsertionPoint) {
- if (const Expr *SubExpr = E->getSubExpr()) {
- QualType ThrowType = SubExpr->getType();
- if (ThrowType->isObjCObjectPointerType()) {
- const Stmt *ThrowStmt = E->getSubExpr();
- const ObjCAtThrowStmt S(E->getExprLoc(), const_cast<Stmt *>(ThrowStmt));
- CGM.getObjCRuntime().EmitThrowStmt(*this, S, false);
- } else {
- CGM.getCXXABI().emitThrow(*this, E);
- }
- } else {
- CGM.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
- }
-
- // throw is an expression, and the expression emitters expect us
- // to leave ourselves at a valid insertion point.
- if (KeepInsertionPoint)
- EmitBlock(createBasicBlock("throw.cont"));
-}
-
-void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
- if (!CGM.getLangOpts().CXXExceptions)
- return;
-
- const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD) {
- // Check if CapturedDecl is nothrow and create terminate scope for it.
- if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
- if (CD->isNothrow())
- EHStack.pushTerminate();
- }
- return;
- }
- const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
- if (!Proto)
- return;
-
- ExceptionSpecificationType EST = Proto->getExceptionSpecType();
- if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) {
- // noexcept functions are simple terminate scopes.
- EHStack.pushTerminate();
- } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
- // TODO: Revisit exception specifications for the MS ABI. There is a way to
- // encode these in an object file but MSVC doesn't do anything with it.
- if (getTarget().getCXXABI().isMicrosoft())
- return;
- unsigned NumExceptions = Proto->getNumExceptions();
- EHFilterScope *Filter = EHStack.pushFilter(NumExceptions);
-
- for (unsigned I = 0; I != NumExceptions; ++I) {
- QualType Ty = Proto->getExceptionType(I);
- QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType();
- llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType,
- /*ForEH=*/true);
- Filter->setFilter(I, EHType);
- }
- }
-}
-
-/// Emit the dispatch block for a filter scope if necessary.
-static void emitFilterDispatchBlock(CodeGenFunction &CGF,
- EHFilterScope &filterScope) {
- llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock();
- if (!dispatchBlock) return;
- if (dispatchBlock->use_empty()) {
- delete dispatchBlock;
- return;
- }
-
- CGF.EmitBlockAfterUses(dispatchBlock);
-
- // If this isn't a catch-all filter, we need to check whether we got
- // here because the filter triggered.
- if (filterScope.getNumFilters()) {
- // Load the selector value.
- llvm::Value *selector = CGF.getSelectorFromSlot();
- llvm::BasicBlock *unexpectedBB = CGF.createBasicBlock("ehspec.unexpected");
-
- llvm::Value *zero = CGF.Builder.getInt32(0);
- llvm::Value *failsFilter =
- CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails");
- CGF.Builder.CreateCondBr(failsFilter, unexpectedBB,
- CGF.getEHResumeBlock(false));
-
- CGF.EmitBlock(unexpectedBB);
- }
-
- // Call __cxa_call_unexpected. This doesn't need to be an invoke
- // because __cxa_call_unexpected magically filters exceptions
- // according to the last landing pad the exception was thrown
- // into. Seriously.
- llvm::Value *exn = CGF.getExceptionFromSlot();
- CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)
- ->setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
-}
-
-void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
- if (!CGM.getLangOpts().CXXExceptions)
- return;
-
- const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD) {
- // Check if CapturedDecl is nothrow and pop terminate scope for it.
- if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
- if (CD->isNothrow())
- EHStack.popTerminate();
- }
- return;
- }
- const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
- if (!Proto)
- return;
-
- ExceptionSpecificationType EST = Proto->getExceptionSpecType();
- if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) {
- EHStack.popTerminate();
- } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
- // TODO: Revisit exception specifications for the MS ABI. There is a way to
- // encode these in an object file but MSVC doesn't do anything with it.
- if (getTarget().getCXXABI().isMicrosoft())
- return;
- EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin());
- emitFilterDispatchBlock(*this, filterScope);
- EHStack.popFilter();
- }
-}
-
-void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
- EnterCXXTryStmt(S);
- EmitStmt(S.getTryBlock());
- ExitCXXTryStmt(S);
-}
-
-void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
- unsigned NumHandlers = S.getNumHandlers();
- EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
-
- for (unsigned I = 0; I != NumHandlers; ++I) {
- const CXXCatchStmt *C = S.getHandler(I);
-
- llvm::BasicBlock *Handler = createBasicBlock("catch");
- if (C->getExceptionDecl()) {
- // FIXME: Dropping the reference type on the type into makes it
- // impossible to correctly implement catch-by-reference
- // semantics for pointers. Unfortunately, this is what all
- // existing compilers do, and it's not clear that the standard
- // personality routine is capable of doing this right. See C++ DR 388:
- // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
- Qualifiers CaughtTypeQuals;
- QualType CaughtType = CGM.getContext().getUnqualifiedArrayType(
- C->getCaughtType().getNonReferenceType(), CaughtTypeQuals);
-
- CatchTypeInfo TypeInfo{nullptr, 0};
- if (CaughtType->isObjCObjectPointerType())
- TypeInfo.RTTI = CGM.getObjCRuntime().GetEHType(CaughtType);
- else
- TypeInfo = CGM.getCXXABI().getAddrOfCXXCatchHandlerType(
- CaughtType, C->getCaughtType());
- CatchScope->setHandler(I, TypeInfo, Handler);
- } else {
- // No exception decl indicates '...', a catch-all.
- CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler);
- }
- }
-}
-
-llvm::BasicBlock *
-CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) {
- if (EHPersonality::get(*this).usesFuncletPads())
- return getFuncletEHDispatchBlock(si);
-
- // The dispatch block for the end of the scope chain is a block that
- // just resumes unwinding.
- if (si == EHStack.stable_end())
- return getEHResumeBlock(true);
-
- // Otherwise, we should look at the actual scope.
- EHScope &scope = *EHStack.find(si);
-
- llvm::BasicBlock *dispatchBlock = scope.getCachedEHDispatchBlock();
- if (!dispatchBlock) {
- switch (scope.getKind()) {
- case EHScope::Catch: {
- // Apply a special case to a single catch-all.
- EHCatchScope &catchScope = cast<EHCatchScope>(scope);
- if (catchScope.getNumHandlers() == 1 &&
- catchScope.getHandler(0).isCatchAll()) {
- dispatchBlock = catchScope.getHandler(0).Block;
-
- // Otherwise, make a dispatch block.
- } else {
- dispatchBlock = createBasicBlock("catch.dispatch");
- }
- break;
- }
-
- case EHScope::Cleanup:
- dispatchBlock = createBasicBlock("ehcleanup");
- break;
-
- case EHScope::Filter:
- dispatchBlock = createBasicBlock("filter.dispatch");
- break;
-
- case EHScope::Terminate:
- dispatchBlock = getTerminateHandler();
- break;
-
- case EHScope::PadEnd:
- llvm_unreachable("PadEnd unnecessary for Itanium!");
- }
- scope.setCachedEHDispatchBlock(dispatchBlock);
- }
- return dispatchBlock;
-}
-
-llvm::BasicBlock *
-CodeGenFunction::getFuncletEHDispatchBlock(EHScopeStack::stable_iterator SI) {
- // Returning nullptr indicates that the previous dispatch block should unwind
- // to caller.
- if (SI == EHStack.stable_end())
- return nullptr;
-
- // Otherwise, we should look at the actual scope.
- EHScope &EHS = *EHStack.find(SI);
-
- llvm::BasicBlock *DispatchBlock = EHS.getCachedEHDispatchBlock();
- if (DispatchBlock)
- return DispatchBlock;
-
- if (EHS.getKind() == EHScope::Terminate)
- DispatchBlock = getTerminateFunclet();
- else
- DispatchBlock = createBasicBlock();
- CGBuilderTy Builder(*this, DispatchBlock);
-
- switch (EHS.getKind()) {
- case EHScope::Catch:
- DispatchBlock->setName("catch.dispatch");
- break;
-
- case EHScope::Cleanup:
- DispatchBlock->setName("ehcleanup");
- break;
-
- case EHScope::Filter:
- llvm_unreachable("exception specifications not handled yet!");
-
- case EHScope::Terminate:
- DispatchBlock->setName("terminate");
- break;
-
- case EHScope::PadEnd:
- llvm_unreachable("PadEnd dispatch block missing!");
- }
- EHS.setCachedEHDispatchBlock(DispatchBlock);
- return DispatchBlock;
-}
-
-/// Check whether this is a non-EH scope, i.e. a scope which doesn't
-/// affect exception handling. Currently, the only non-EH scopes are
-/// normal-only cleanup scopes.
-static bool isNonEHScope(const EHScope &S) {
- switch (S.getKind()) {
- case EHScope::Cleanup:
- return !cast<EHCleanupScope>(S).isEHCleanup();
- case EHScope::Filter:
- case EHScope::Catch:
- case EHScope::Terminate:
- case EHScope::PadEnd:
- return false;
- }
-
- llvm_unreachable("Invalid EHScope Kind!");
-}
-
-llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
- assert(EHStack.requiresLandingPad());
- assert(!EHStack.empty());
-
- // If exceptions are disabled and SEH is not in use, then there is no invoke
- // destination. SEH "works" even if exceptions are off. In practice, this
- // means that C++ destructors and other EH cleanups don't run, which is
- // consistent with MSVC's behavior.
- const LangOptions &LO = CGM.getLangOpts();
- if (!LO.Exceptions) {
- if (!LO.Borland && !LO.MicrosoftExt)
- return nullptr;
- if (!currentFunctionUsesSEHTry())
- return nullptr;
- }
-
- // CUDA device code doesn't have exceptions.
- if (LO.CUDA && LO.CUDAIsDevice)
- return nullptr;
-
- // Check the innermost scope for a cached landing pad. If this is
- // a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad.
- llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad();
- if (LP) return LP;
-
- const EHPersonality &Personality = EHPersonality::get(*this);
-
- if (!CurFn->hasPersonalityFn())
- CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality));
-
- if (Personality.usesFuncletPads()) {
- // We don't need separate landing pads in the funclet model.
- LP = getEHDispatchBlock(EHStack.getInnermostEHScope());
- } else {
- // Build the landing pad for this scope.
- LP = EmitLandingPad();
- }
-
- assert(LP);
-
- // Cache the landing pad on the innermost scope. If this is a
- // non-EH scope, cache the landing pad on the enclosing scope, too.
- for (EHScopeStack::iterator ir = EHStack.begin(); true; ++ir) {
- ir->setCachedLandingPad(LP);
- if (!isNonEHScope(*ir)) break;
- }
-
- return LP;
-}
-
-llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
- assert(EHStack.requiresLandingPad());
-
- EHScope &innermostEHScope = *EHStack.find(EHStack.getInnermostEHScope());
- switch (innermostEHScope.getKind()) {
- case EHScope::Terminate:
- return getTerminateLandingPad();
-
- case EHScope::PadEnd:
- llvm_unreachable("PadEnd unnecessary for Itanium!");
-
- case EHScope::Catch:
- case EHScope::Cleanup:
- case EHScope::Filter:
- if (llvm::BasicBlock *lpad = innermostEHScope.getCachedLandingPad())
- return lpad;
- }
-
- // Save the current IR generation state.
- CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
- auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, CurEHLocation);
-
- // Create and configure the landing pad.
- llvm::BasicBlock *lpad = createBasicBlock("lpad");
- EmitBlock(lpad);
-
- llvm::LandingPadInst *LPadInst =
- Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);
-
- llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0);
- Builder.CreateStore(LPadExn, getExceptionSlot());
- llvm::Value *LPadSel = Builder.CreateExtractValue(LPadInst, 1);
- Builder.CreateStore(LPadSel, getEHSelectorSlot());
-
- // Save the exception pointer. It's safe to use a single exception
- // pointer per function because EH cleanups can never have nested
- // try/catches.
- // Build the landingpad instruction.
-
- // Accumulate all the handlers in scope.
- bool hasCatchAll = false;
- bool hasCleanup = false;
- bool hasFilter = false;
- SmallVector<llvm::Value*, 4> filterTypes;
- llvm::SmallPtrSet<llvm::Value*, 4> catchTypes;
- for (EHScopeStack::iterator I = EHStack.begin(), E = EHStack.end(); I != E;
- ++I) {
-
- switch (I->getKind()) {
- case EHScope::Cleanup:
- // If we have a cleanup, remember that.
- hasCleanup = (hasCleanup || cast<EHCleanupScope>(*I).isEHCleanup());
- continue;
-
- case EHScope::Filter: {
- assert(I.next() == EHStack.end() && "EH filter is not end of EH stack");
- assert(!hasCatchAll && "EH filter reached after catch-all");
-
- // Filter scopes get added to the landingpad in weird ways.
- EHFilterScope &filter = cast<EHFilterScope>(*I);
- hasFilter = true;
-
- // Add all the filter values.
- for (unsigned i = 0, e = filter.getNumFilters(); i != e; ++i)
- filterTypes.push_back(filter.getFilter(i));
- goto done;
- }
-
- case EHScope::Terminate:
- // Terminate scopes are basically catch-alls.
- assert(!hasCatchAll);
- hasCatchAll = true;
- goto done;
-
- case EHScope::Catch:
- break;
-
- case EHScope::PadEnd:
- llvm_unreachable("PadEnd unnecessary for Itanium!");
- }
-
- EHCatchScope &catchScope = cast<EHCatchScope>(*I);
- for (unsigned hi = 0, he = catchScope.getNumHandlers(); hi != he; ++hi) {
- EHCatchScope::Handler handler = catchScope.getHandler(hi);
- assert(handler.Type.Flags == 0 &&
- "landingpads do not support catch handler flags");
-
- // If this is a catch-all, register that and abort.
- if (!handler.Type.RTTI) {
- assert(!hasCatchAll);
- hasCatchAll = true;
- goto done;
- }
-
- // Check whether we already have a handler for this type.
- if (catchTypes.insert(handler.Type.RTTI).second)
- // If not, add it directly to the landingpad.
- LPadInst->addClause(handler.Type.RTTI);
- }
- }
-
- done:
- // If we have a catch-all, add null to the landingpad.
- assert(!(hasCatchAll && hasFilter));
- if (hasCatchAll) {
- LPadInst->addClause(getCatchAllValue(*this));
-
- // If we have an EH filter, we need to add those handlers in the
- // right place in the landingpad, which is to say, at the end.
- } else if (hasFilter) {
- // Create a filter expression: a constant array indicating which filter
- // types there are. The personality routine only lands here if the filter
- // doesn't match.
- SmallVector<llvm::Constant*, 8> Filters;
- llvm::ArrayType *AType =
- llvm::ArrayType::get(!filterTypes.empty() ?
- filterTypes[0]->getType() : Int8PtrTy,
- filterTypes.size());
-
- for (unsigned i = 0, e = filterTypes.size(); i != e; ++i)
- Filters.push_back(cast<llvm::Constant>(filterTypes[i]));
- llvm::Constant *FilterArray = llvm::ConstantArray::get(AType, Filters);
- LPadInst->addClause(FilterArray);
-
- // Also check whether we need a cleanup.
- if (hasCleanup)
- LPadInst->setCleanup(true);
-
- // Otherwise, signal that we at least have cleanups.
- } else if (hasCleanup) {
- LPadInst->setCleanup(true);
- }
-
- assert((LPadInst->getNumClauses() > 0 || LPadInst->isCleanup()) &&
- "landingpad instruction has no clauses!");
-
- // Tell the backend how to generate the landing pad.
- Builder.CreateBr(getEHDispatchBlock(EHStack.getInnermostEHScope()));
-
- // Restore the old IR generation state.
- Builder.restoreIP(savedIP);
-
- return lpad;
-}
-
-static void emitCatchPadBlock(CodeGenFunction &CGF, EHCatchScope &CatchScope) {
- llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock();
- assert(DispatchBlock);
-
- CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP();
- CGF.EmitBlockAfterUses(DispatchBlock);
-
- llvm::Value *ParentPad = CGF.CurrentFuncletPad;
- if (!ParentPad)
- ParentPad = llvm::ConstantTokenNone::get(CGF.getLLVMContext());
- llvm::BasicBlock *UnwindBB =
- CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope());
-
- unsigned NumHandlers = CatchScope.getNumHandlers();
- llvm::CatchSwitchInst *CatchSwitch =
- CGF.Builder.CreateCatchSwitch(ParentPad, UnwindBB, NumHandlers);
-
- // Test against each of the exception types we claim to catch.
- for (unsigned I = 0; I < NumHandlers; ++I) {
- const EHCatchScope::Handler &Handler = CatchScope.getHandler(I);
-
- CatchTypeInfo TypeInfo = Handler.Type;
- if (!TypeInfo.RTTI)
- TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy);
-
- CGF.Builder.SetInsertPoint(Handler.Block);
-
- if (EHPersonality::get(CGF).isMSVCXXPersonality()) {
- CGF.Builder.CreateCatchPad(
- CatchSwitch, {TypeInfo.RTTI, CGF.Builder.getInt32(TypeInfo.Flags),
- llvm::Constant::getNullValue(CGF.VoidPtrTy)});
- } else {
- CGF.Builder.CreateCatchPad(CatchSwitch, {TypeInfo.RTTI});
- }
-
- CatchSwitch->addHandler(Handler.Block);
- }
- CGF.Builder.restoreIP(SavedIP);
-}
-
-// Wasm uses Windows-style EH instructions, but it merges all catch clauses into
-// one big catchpad, within which we use Itanium's landingpad-style selector
-// comparison instructions.
-static void emitWasmCatchPadBlock(CodeGenFunction &CGF,
- EHCatchScope &CatchScope) {
- llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock();
- assert(DispatchBlock);
-
- CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP();
- CGF.EmitBlockAfterUses(DispatchBlock);
-
- llvm::Value *ParentPad = CGF.CurrentFuncletPad;
- if (!ParentPad)
- ParentPad = llvm::ConstantTokenNone::get(CGF.getLLVMContext());
- llvm::BasicBlock *UnwindBB =
- CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope());
-
- unsigned NumHandlers = CatchScope.getNumHandlers();
- llvm::CatchSwitchInst *CatchSwitch =
- CGF.Builder.CreateCatchSwitch(ParentPad, UnwindBB, NumHandlers);
-
- // We don't use a landingpad instruction, so generate intrinsic calls to
- // provide exception and selector values.
- llvm::BasicBlock *WasmCatchStartBlock = CGF.createBasicBlock("catch.start");
- CatchSwitch->addHandler(WasmCatchStartBlock);
- CGF.EmitBlockAfterUses(WasmCatchStartBlock);
-
- // Create a catchpad instruction.
- SmallVector<llvm::Value *, 4> CatchTypes;
- for (unsigned I = 0, E = NumHandlers; I < E; ++I) {
- const EHCatchScope::Handler &Handler = CatchScope.getHandler(I);
- CatchTypeInfo TypeInfo = Handler.Type;
- if (!TypeInfo.RTTI)
- TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy);
- CatchTypes.push_back(TypeInfo.RTTI);
- }
- auto *CPI = CGF.Builder.CreateCatchPad(CatchSwitch, CatchTypes);
-
- // Create calls to wasm.get.exception and wasm.get.ehselector intrinsics.
- // Before they are lowered appropriately later, they provide values for the
- // exception and selector.
- llvm::Value *GetExnFn =
- CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_get_exception);
- llvm::Value *GetSelectorFn =
- CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_get_ehselector);
- llvm::CallInst *Exn = CGF.Builder.CreateCall(GetExnFn, CPI);
- CGF.Builder.CreateStore(Exn, CGF.getExceptionSlot());
- llvm::CallInst *Selector = CGF.Builder.CreateCall(GetSelectorFn, CPI);
-
- llvm::Value *TypeIDFn = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
-
- // If there's only a single catch-all, branch directly to its handler.
- if (CatchScope.getNumHandlers() == 1 &&
- CatchScope.getHandler(0).isCatchAll()) {
- CGF.Builder.CreateBr(CatchScope.getHandler(0).Block);
- CGF.Builder.restoreIP(SavedIP);
- return;
- }
-
- // Test against each of the exception types we claim to catch.
- for (unsigned I = 0, E = NumHandlers;; ++I) {
- assert(I < E && "ran off end of handlers!");
- const EHCatchScope::Handler &Handler = CatchScope.getHandler(I);
- CatchTypeInfo TypeInfo = Handler.Type;
- if (!TypeInfo.RTTI)
- TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy);
-
- // Figure out the next block.
- llvm::BasicBlock *NextBlock;
-
- bool EmitNextBlock = false, NextIsEnd = false;
-
- // If this is the last handler, we're at the end, and the next block is a
- // block that contains a call to the rethrow function, so we can unwind to
- // the enclosing EH scope. The call itself will be generated later.
- if (I + 1 == E) {
- NextBlock = CGF.createBasicBlock("rethrow");
- EmitNextBlock = true;
- NextIsEnd = true;
-
- // If the next handler is a catch-all, we're at the end, and the
- // next block is that handler.
- } else if (CatchScope.getHandler(I + 1).isCatchAll()) {
- NextBlock = CatchScope.getHandler(I + 1).Block;
- NextIsEnd = true;
-
- // Otherwise, we're not at the end and we need a new block.
- } else {
- NextBlock = CGF.createBasicBlock("catch.fallthrough");
- EmitNextBlock = true;
- }
-
- // Figure out the catch type's index in the LSDA's type table.
- llvm::CallInst *TypeIndex = CGF.Builder.CreateCall(TypeIDFn, TypeInfo.RTTI);
- TypeIndex->setDoesNotThrow();
-
- llvm::Value *MatchesTypeIndex =
- CGF.Builder.CreateICmpEQ(Selector, TypeIndex, "matches");
- CGF.Builder.CreateCondBr(MatchesTypeIndex, Handler.Block, NextBlock);
-
- if (EmitNextBlock)
- CGF.EmitBlock(NextBlock);
- if (NextIsEnd)
- break;
- }
-
- CGF.Builder.restoreIP(SavedIP);
-}
-
-/// Emit the structure of the dispatch block for the given catch scope.
-/// It is an invariant that the dispatch block already exists.
-static void emitCatchDispatchBlock(CodeGenFunction &CGF,
- EHCatchScope &catchScope) {
- if (EHPersonality::get(CGF).isWasmPersonality())
- return emitWasmCatchPadBlock(CGF, catchScope);
- if (EHPersonality::get(CGF).usesFuncletPads())
- return emitCatchPadBlock(CGF, catchScope);
-
- llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock();
- assert(dispatchBlock);
-
- // If there's only a single catch-all, getEHDispatchBlock returned
- // that catch-all as the dispatch block.
- if (catchScope.getNumHandlers() == 1 &&
- catchScope.getHandler(0).isCatchAll()) {
- assert(dispatchBlock == catchScope.getHandler(0).Block);
- return;
- }
-
- CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP();
- CGF.EmitBlockAfterUses(dispatchBlock);
-
- // Select the right handler.
- llvm::Value *llvm_eh_typeid_for =
- CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
-
- // Load the selector value.
- llvm::Value *selector = CGF.getSelectorFromSlot();
-
- // Test against each of the exception types we claim to catch.
- for (unsigned i = 0, e = catchScope.getNumHandlers(); ; ++i) {
- assert(i < e && "ran off end of handlers!");
- const EHCatchScope::Handler &handler = catchScope.getHandler(i);
-
- llvm::Value *typeValue = handler.Type.RTTI;
- assert(handler.Type.Flags == 0 &&
- "landingpads do not support catch handler flags");
- assert(typeValue && "fell into catch-all case!");
- typeValue = CGF.Builder.CreateBitCast(typeValue, CGF.Int8PtrTy);
-
- // Figure out the next block.
- bool nextIsEnd;
- llvm::BasicBlock *nextBlock;
-
- // If this is the last handler, we're at the end, and the next
- // block is the block for the enclosing EH scope.
- if (i + 1 == e) {
- nextBlock = CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope());
- nextIsEnd = true;
-
- // If the next handler is a catch-all, we're at the end, and the
- // next block is that handler.
- } else if (catchScope.getHandler(i+1).isCatchAll()) {
- nextBlock = catchScope.getHandler(i+1).Block;
- nextIsEnd = true;
-
- // Otherwise, we're not at the end and we need a new block.
- } else {
- nextBlock = CGF.createBasicBlock("catch.fallthrough");
- nextIsEnd = false;
- }
-
- // Figure out the catch type's index in the LSDA's type table.
- llvm::CallInst *typeIndex =
- CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue);
- typeIndex->setDoesNotThrow();
-
- llvm::Value *matchesTypeIndex =
- CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches");
- CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock);
-
- // If the next handler is a catch-all, we're completely done.
- if (nextIsEnd) {
- CGF.Builder.restoreIP(savedIP);
- return;
- }
- // Otherwise we need to emit and continue at that block.
- CGF.EmitBlock(nextBlock);
- }
-}
-
-void CodeGenFunction::popCatchScope() {
- EHCatchScope &catchScope = cast<EHCatchScope>(*EHStack.begin());
- if (catchScope.hasEHBranches())
- emitCatchDispatchBlock(*this, catchScope);
- EHStack.popCatch();
-}
-
-void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
- unsigned NumHandlers = S.getNumHandlers();
- EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
- assert(CatchScope.getNumHandlers() == NumHandlers);
- llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock();
-
- // If the catch was not required, bail out now.
- if (!CatchScope.hasEHBranches()) {
- CatchScope.clearHandlerBlocks();
- EHStack.popCatch();
- return;
- }
-
- // Emit the structure of the EH dispatch for this catch.
- emitCatchDispatchBlock(*this, CatchScope);
-
- // Copy the handler blocks off before we pop the EH stack. Emitting
- // the handlers might scribble on this memory.
- SmallVector<EHCatchScope::Handler, 8> Handlers(
- CatchScope.begin(), CatchScope.begin() + NumHandlers);
-
- EHStack.popCatch();
-
- // The fall-through block.
- llvm::BasicBlock *ContBB = createBasicBlock("try.cont");
-
- // We just emitted the body of the try; jump to the continue block.
- if (HaveInsertPoint())
- Builder.CreateBr(ContBB);
-
- // Determine if we need an implicit rethrow for all these catch handlers;
- // see the comment below.
- bool doImplicitRethrow = false;
- if (IsFnTryBlock)
- doImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||
- isa<CXXConstructorDecl>(CurCodeDecl);
-
- // Wasm uses Windows-style EH instructions, but merges all catch clauses into
- // one big catchpad. So we save the old funclet pad here before we traverse
- // each catch handler.
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
- llvm::BasicBlock *WasmCatchStartBlock = nullptr;
- if (EHPersonality::get(*this).isWasmPersonality()) {
- auto *CatchSwitch =
- cast<llvm::CatchSwitchInst>(DispatchBlock->getFirstNonPHI());
- WasmCatchStartBlock = CatchSwitch->hasUnwindDest()
- ? CatchSwitch->getSuccessor(1)
- : CatchSwitch->getSuccessor(0);
- auto *CPI = cast<llvm::CatchPadInst>(WasmCatchStartBlock->getFirstNonPHI());
- CurrentFuncletPad = CPI;
- }
-
- // Perversely, we emit the handlers backwards precisely because we
- // want them to appear in source order. In all of these cases, the
- // catch block will have exactly one predecessor, which will be a
- // particular block in the catch dispatch. However, in the case of
- // a catch-all, one of the dispatch blocks will branch to two
- // different handlers, and EmitBlockAfterUses will cause the second
- // handler to be moved before the first.
- bool HasCatchAll = false;
- for (unsigned I = NumHandlers; I != 0; --I) {
- HasCatchAll |= Handlers[I - 1].isCatchAll();
- llvm::BasicBlock *CatchBlock = Handlers[I-1].Block;
- EmitBlockAfterUses(CatchBlock);
-
- // Catch the exception if this isn't a catch-all.
- const CXXCatchStmt *C = S.getHandler(I-1);
-
- // Enter a cleanup scope, including the catch variable and the
- // end-catch.
- RunCleanupsScope CatchScope(*this);
-
- // Initialize the catch variable and set up the cleanups.
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
- CGM.getCXXABI().emitBeginCatch(*this, C);
-
- // Emit the PGO counter increment.
- incrementProfileCounter(C);
-
- // Perform the body of the catch.
- EmitStmt(C->getHandlerBlock());
-
- // [except.handle]p11:
- // The currently handled exception is rethrown if control
- // reaches the end of a handler of the function-try-block of a
- // constructor or destructor.
-
- // It is important that we only do this on fallthrough and not on
- // return. Note that it's illegal to put a return in a
- // constructor function-try-block's catch handler (p14), so this
- // really only applies to destructors.
- if (doImplicitRethrow && HaveInsertPoint()) {
- CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/false);
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
- }
-
- // Fall out through the catch cleanups.
- CatchScope.ForceCleanup();
-
- // Branch out of the try.
- if (HaveInsertPoint())
- Builder.CreateBr(ContBB);
- }
-
- // Because in wasm we merge all catch clauses into one big catchpad, in case
- // none of the types in catch handlers matches after we test against each of
- // them, we should unwind to the next EH enclosing scope. We generate a call
- // to rethrow function here to do that.
- if (EHPersonality::get(*this).isWasmPersonality() && !HasCatchAll) {
- assert(WasmCatchStartBlock);
- // Navigate for the "rethrow" block we created in emitWasmCatchPadBlock().
- // Wasm uses landingpad-style conditional branches to compare selectors, so
- // we follow the false destination for each of the cond branches to reach
- // the rethrow block.
- llvm::BasicBlock *RethrowBlock = WasmCatchStartBlock;
- while (llvm::Instruction *TI = RethrowBlock->getTerminator()) {
- auto *BI = cast<llvm::BranchInst>(TI);
- assert(BI->isConditional());
- RethrowBlock = BI->getSuccessor(1);
- }
- assert(RethrowBlock != WasmCatchStartBlock && RethrowBlock->empty());
- Builder.SetInsertPoint(RethrowBlock);
- CGM.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
- }
-
- EmitBlock(ContBB);
- incrementProfileCounter(&S);
-}
-
-namespace {
- struct CallEndCatchForFinally final : EHScopeStack::Cleanup {
- llvm::Value *ForEHVar;
- llvm::Value *EndCatchFn;
- CallEndCatchForFinally(llvm::Value *ForEHVar, llvm::Value *EndCatchFn)
- : ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch");
- llvm::BasicBlock *CleanupContBB =
- CGF.createBasicBlock("finally.cleanup.cont");
-
- llvm::Value *ShouldEndCatch =
- CGF.Builder.CreateFlagLoad(ForEHVar, "finally.endcatch");
- CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);
- CGF.EmitBlock(EndCatchBB);
- CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw
- CGF.EmitBlock(CleanupContBB);
- }
- };
-
- struct PerformFinally final : EHScopeStack::Cleanup {
- const Stmt *Body;
- llvm::Value *ForEHVar;
- llvm::Value *EndCatchFn;
- llvm::Value *RethrowFn;
- llvm::Value *SavedExnVar;
-
- PerformFinally(const Stmt *Body, llvm::Value *ForEHVar,
- llvm::Value *EndCatchFn,
- llvm::Value *RethrowFn, llvm::Value *SavedExnVar)
- : Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn),
- RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Enter a cleanup to call the end-catch function if one was provided.
- if (EndCatchFn)
- CGF.EHStack.pushCleanup<CallEndCatchForFinally>(NormalAndEHCleanup,
- ForEHVar, EndCatchFn);
-
- // Save the current cleanup destination in case there are
- // cleanups in the finally block.
- llvm::Value *SavedCleanupDest =
- CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot(),
- "cleanup.dest.saved");
-
- // Emit the finally block.
- CGF.EmitStmt(Body);
-
- // If the end of the finally is reachable, check whether this was
- // for EH. If so, rethrow.
- if (CGF.HaveInsertPoint()) {
- llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow");
- llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont");
-
- llvm::Value *ShouldRethrow =
- CGF.Builder.CreateFlagLoad(ForEHVar, "finally.shouldthrow");
- CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB);
-
- CGF.EmitBlock(RethrowBB);
- if (SavedExnVar) {
- CGF.EmitRuntimeCallOrInvoke(RethrowFn,
- CGF.Builder.CreateAlignedLoad(SavedExnVar, CGF.getPointerAlign()));
- } else {
- CGF.EmitRuntimeCallOrInvoke(RethrowFn);
- }
- CGF.Builder.CreateUnreachable();
-
- CGF.EmitBlock(ContBB);
-
- // Restore the cleanup destination.
- CGF.Builder.CreateStore(SavedCleanupDest,
- CGF.getNormalCleanupDestSlot());
- }
-
- // Leave the end-catch cleanup. As an optimization, pretend that
- // the fallthrough path was inaccessible; we've dynamically proven
- // that we're not in the EH case along that path.
- if (EndCatchFn) {
- CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
- CGF.PopCleanupBlock();
- CGF.Builder.restoreIP(SavedIP);
- }
-
- // Now make sure we actually have an insertion point or the
- // cleanup gods will hate us.
- CGF.EnsureInsertPoint();
- }
- };
-} // end anonymous namespace
-
-/// Enters a finally block for an implementation using zero-cost
-/// exceptions. This is mostly general, but hard-codes some
-/// language/ABI-specific behavior in the catch-all sections.
-void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF,
- const Stmt *body,
- llvm::Constant *beginCatchFn,
- llvm::Constant *endCatchFn,
- llvm::Constant *rethrowFn) {
- assert((beginCatchFn != nullptr) == (endCatchFn != nullptr) &&
- "begin/end catch functions not paired");
- assert(rethrowFn && "rethrow function is required");
-
- BeginCatchFn = beginCatchFn;
-
- // The rethrow function has one of the following two types:
- // void (*)()
- // void (*)(void*)
- // In the latter case we need to pass it the exception object.
- // But we can't use the exception slot because the @finally might
- // have a landing pad (which would overwrite the exception slot).
- llvm::FunctionType *rethrowFnTy =
- cast<llvm::FunctionType>(
- cast<llvm::PointerType>(rethrowFn->getType())->getElementType());
- SavedExnVar = nullptr;
- if (rethrowFnTy->getNumParams())
- SavedExnVar = CGF.CreateTempAlloca(CGF.Int8PtrTy, "finally.exn");
-
- // A finally block is a statement which must be executed on any edge
- // out of a given scope. Unlike a cleanup, the finally block may
- // contain arbitrary control flow leading out of itself. In
- // addition, finally blocks should always be executed, even if there
- // are no catch handlers higher on the stack. Therefore, we
- // surround the protected scope with a combination of a normal
- // cleanup (to catch attempts to break out of the block via normal
- // control flow) and an EH catch-all (semantically "outside" any try
- // statement to which the finally block might have been attached).
- // The finally block itself is generated in the context of a cleanup
- // which conditionally leaves the catch-all.
-
- // Jump destination for performing the finally block on an exception
- // edge. We'll never actually reach this block, so unreachable is
- // fine.
- RethrowDest = CGF.getJumpDestInCurrentScope(CGF.getUnreachableBlock());
-
- // Whether the finally block is being executed for EH purposes.
- ForEHVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "finally.for-eh");
- CGF.Builder.CreateFlagStore(false, ForEHVar);
-
- // Enter a normal cleanup which will perform the @finally block.
- CGF.EHStack.pushCleanup<PerformFinally>(NormalCleanup, body,
- ForEHVar, endCatchFn,
- rethrowFn, SavedExnVar);
-
- // Enter a catch-all scope.
- llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall");
- EHCatchScope *catchScope = CGF.EHStack.pushCatch(1);
- catchScope->setCatchAllHandler(0, catchBB);
-}
-
-void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
- // Leave the finally catch-all.
- EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin());
- llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block;
-
- CGF.popCatchScope();
-
- // If there are any references to the catch-all block, emit it.
- if (catchBB->use_empty()) {
- delete catchBB;
- } else {
- CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveAndClearIP();
- CGF.EmitBlock(catchBB);
-
- llvm::Value *exn = nullptr;
-
- // If there's a begin-catch function, call it.
- if (BeginCatchFn) {
- exn = CGF.getExceptionFromSlot();
- CGF.EmitNounwindRuntimeCall(BeginCatchFn, exn);
- }
-
- // If we need to remember the exception pointer to rethrow later, do so.
- if (SavedExnVar) {
- if (!exn) exn = CGF.getExceptionFromSlot();
- CGF.Builder.CreateAlignedStore(exn, SavedExnVar, CGF.getPointerAlign());
- }
-
- // Tell the cleanups in the finally block that we're do this for EH.
- CGF.Builder.CreateFlagStore(true, ForEHVar);
-
- // Thread a jump through the finally cleanup.
- CGF.EmitBranchThroughCleanup(RethrowDest);
-
- CGF.Builder.restoreIP(savedIP);
- }
-
- // Finally, leave the @finally cleanup.
- CGF.PopCleanupBlock();
-}
-
-llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
- if (TerminateLandingPad)
- return TerminateLandingPad;
-
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
-
- // This will get inserted at the end of the function.
- TerminateLandingPad = createBasicBlock("terminate.lpad");
- Builder.SetInsertPoint(TerminateLandingPad);
-
- // Tell the backend that this is a landing pad.
- const EHPersonality &Personality = EHPersonality::get(*this);
-
- if (!CurFn->hasPersonalityFn())
- CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality));
-
- llvm::LandingPadInst *LPadInst =
- Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);
- LPadInst->addClause(getCatchAllValue(*this));
-
- llvm::Value *Exn = nullptr;
- if (getLangOpts().CPlusPlus)
- Exn = Builder.CreateExtractValue(LPadInst, 0);
- llvm::CallInst *terminateCall =
- CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
- terminateCall->setDoesNotReturn();
- Builder.CreateUnreachable();
-
- // Restore the saved insertion state.
- Builder.restoreIP(SavedIP);
-
- return TerminateLandingPad;
-}
-
-llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
- if (TerminateHandler)
- return TerminateHandler;
-
- // Set up the terminate handler. This block is inserted at the very
- // end of the function by FinishFunction.
- TerminateHandler = createBasicBlock("terminate.handler");
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
- Builder.SetInsertPoint(TerminateHandler);
-
- llvm::Value *Exn = nullptr;
- if (getLangOpts().CPlusPlus)
- Exn = getExceptionFromSlot();
- llvm::CallInst *terminateCall =
- CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
- terminateCall->setDoesNotReturn();
- Builder.CreateUnreachable();
-
- // Restore the saved insertion state.
- Builder.restoreIP(SavedIP);
-
- return TerminateHandler;
-}
-
-llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() {
- assert(EHPersonality::get(*this).usesFuncletPads() &&
- "use getTerminateLandingPad for non-funclet EH");
-
- llvm::BasicBlock *&TerminateFunclet = TerminateFunclets[CurrentFuncletPad];
- if (TerminateFunclet)
- return TerminateFunclet;
-
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
-
- // Set up the terminate handler. This block is inserted at the very
- // end of the function by FinishFunction.
- TerminateFunclet = createBasicBlock("terminate.handler");
- Builder.SetInsertPoint(TerminateFunclet);
-
- // Create the cleanuppad using the current parent pad as its token. Use 'none'
- // if this is a top-level terminate scope, which is the common case.
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
- llvm::Value *ParentPad = CurrentFuncletPad;
- if (!ParentPad)
- ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
- CurrentFuncletPad = Builder.CreateCleanupPad(ParentPad);
-
- // Emit the __std_terminate call.
- llvm::Value *Exn = nullptr;
- // In case of wasm personality, we need to pass the exception value to
- // __clang_call_terminate function.
- if (getLangOpts().CPlusPlus &&
- EHPersonality::get(*this).isWasmPersonality()) {
- llvm::Value *GetExnFn =
- CGM.getIntrinsic(llvm::Intrinsic::wasm_get_exception);
- Exn = Builder.CreateCall(GetExnFn, CurrentFuncletPad);
- }
- llvm::CallInst *terminateCall =
- CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
- terminateCall->setDoesNotReturn();
- Builder.CreateUnreachable();
-
- // Restore the saved insertion state.
- Builder.restoreIP(SavedIP);
-
- return TerminateFunclet;
-}
-
-llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
- if (EHResumeBlock) return EHResumeBlock;
-
- CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
-
- // We emit a jump to a notional label at the outermost unwind state.
- EHResumeBlock = createBasicBlock("eh.resume");
- Builder.SetInsertPoint(EHResumeBlock);
-
- const EHPersonality &Personality = EHPersonality::get(*this);
-
- // This can always be a call because we necessarily didn't find
- // anything on the EH stack which needs our help.
- const char *RethrowName = Personality.CatchallRethrowFn;
- if (RethrowName != nullptr && !isCleanup) {
- EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),
- getExceptionFromSlot())->setDoesNotReturn();
- Builder.CreateUnreachable();
- Builder.restoreIP(SavedIP);
- return EHResumeBlock;
- }
-
- // Recreate the landingpad's return value for the 'resume' instruction.
- llvm::Value *Exn = getExceptionFromSlot();
- llvm::Value *Sel = getSelectorFromSlot();
-
- llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), Sel->getType());
- llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
- LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
- LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
-
- Builder.CreateResume(LPadVal);
- Builder.restoreIP(SavedIP);
- return EHResumeBlock;
-}
-
-void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
- EnterSEHTryStmt(S);
- {
- JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
-
- SEHTryEpilogueStack.push_back(&TryExit);
- EmitStmt(S.getTryBlock());
- SEHTryEpilogueStack.pop_back();
-
- if (!TryExit.getBlock()->use_empty())
- EmitBlock(TryExit.getBlock(), /*IsFinished=*/true);
- else
- delete TryExit.getBlock();
- }
- ExitSEHTryStmt(S);
-}
-
-namespace {
-struct PerformSEHFinally final : EHScopeStack::Cleanup {
- llvm::Function *OutlinedFinally;
- PerformSEHFinally(llvm::Function *OutlinedFinally)
- : OutlinedFinally(OutlinedFinally) {}
-
- void Emit(CodeGenFunction &CGF, Flags F) override {
- ASTContext &Context = CGF.getContext();
- CodeGenModule &CGM = CGF.CGM;
-
- CallArgList Args;
-
- // Compute the two argument values.
- QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
- llvm::Value *FP = nullptr;
- // If CFG.IsOutlinedSEHHelper is true, then we are within a finally block.
- if (CGF.IsOutlinedSEHHelper) {
- FP = &CGF.CurFn->arg_begin()[1];
- } else {
- llvm::Value *LocalAddrFn =
- CGM.getIntrinsic(llvm::Intrinsic::localaddress);
- FP = CGF.Builder.CreateCall(LocalAddrFn);
- }
-
- llvm::Value *IsForEH =
- llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
- Args.add(RValue::get(IsForEH), ArgTys[0]);
- Args.add(RValue::get(FP), ArgTys[1]);
-
- // Arrange a two-arg function info and type.
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeBuiltinFunctionCall(Context.VoidTy, Args);
-
- auto Callee = CGCallee::forDirect(OutlinedFinally);
- CGF.EmitCall(FnInfo, Callee, ReturnValueSlot(), Args);
- }
-};
-} // end anonymous namespace
-
-namespace {
-/// Find all local variable captures in the statement.
-struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
- CodeGenFunction &ParentCGF;
- const VarDecl *ParentThis;
- llvm::SmallSetVector<const VarDecl *, 4> Captures;
- Address SEHCodeSlot = Address::invalid();
- CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
- : ParentCGF(ParentCGF), ParentThis(ParentThis) {}
-
- // Return true if we need to do any capturing work.
- bool foundCaptures() {
- return !Captures.empty() || SEHCodeSlot.isValid();
- }
-
- void Visit(const Stmt *S) {
- // See if this is a capture, then recurse.
- ConstStmtVisitor<CaptureFinder>::Visit(S);
- for (const Stmt *Child : S->children())
- if (Child)
- Visit(Child);
- }
-
- void VisitDeclRefExpr(const DeclRefExpr *E) {
- // If this is already a capture, just make sure we capture 'this'.
- if (E->refersToEnclosingVariableOrCapture()) {
- Captures.insert(ParentThis);
- return;
- }
-
- const auto *D = dyn_cast<VarDecl>(E->getDecl());
- if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage())
- Captures.insert(D);
- }
-
- void VisitCXXThisExpr(const CXXThisExpr *E) {
- Captures.insert(ParentThis);
- }
-
- void VisitCallExpr(const CallExpr *E) {
- // We only need to add parent frame allocations for these builtins in x86.
- if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86)
- return;
-
- unsigned ID = E->getBuiltinCallee();
- switch (ID) {
- case Builtin::BI__exception_code:
- case Builtin::BI_exception_code:
- // This is the simple case where we are the outermost finally. All we
- // have to do here is make sure we escape this and recover it in the
- // outlined handler.
- if (!SEHCodeSlot.isValid())
- SEHCodeSlot = ParentCGF.SEHCodeSlotStack.back();
- break;
- }
- }
-};
-} // end anonymous namespace
-
-Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
- Address ParentVar,
- llvm::Value *ParentFP) {
- llvm::CallInst *RecoverCall = nullptr;
- CGBuilderTy Builder(*this, AllocaInsertPt);
- if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar.getPointer())) {
- // Mark the variable escaped if nobody else referenced it and compute the
- // localescape index.
- auto InsertPair = ParentCGF.EscapedLocals.insert(
- std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size()));
- int FrameEscapeIdx = InsertPair.first->second;
- // call i8* @llvm.localrecover(i8* bitcast(@parentFn), i8* %fp, i32 N)
- llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
- &CGM.getModule(), llvm::Intrinsic::localrecover);
- llvm::Constant *ParentI8Fn =
- llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
- RecoverCall = Builder.CreateCall(
- FrameRecoverFn, {ParentI8Fn, ParentFP,
- llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});
-
- } else {
- // If the parent didn't have an alloca, we're doing some nested outlining.
- // Just clone the existing localrecover call, but tweak the FP argument to
- // use our FP value. All other arguments are constants.
- auto *ParentRecover =
- cast<llvm::IntrinsicInst>(ParentVar.getPointer()->stripPointerCasts());
- assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover &&
- "expected alloca or localrecover in parent LocalDeclMap");
- RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
- RecoverCall->setArgOperand(1, ParentFP);
- RecoverCall->insertBefore(AllocaInsertPt);
- }
-
- // Bitcast the variable, rename it, and insert it in the local decl map.
- llvm::Value *ChildVar =
- Builder.CreateBitCast(RecoverCall, ParentVar.getType());
- ChildVar->setName(ParentVar.getName());
- return Address(ChildVar, ParentVar.getAlignment());
-}
-
-void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
- const Stmt *OutlinedStmt,
- bool IsFilter) {
- // Find all captures in the Stmt.
- CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl);
- Finder.Visit(OutlinedStmt);
-
- // We can exit early on x86_64 when there are no captures. We just have to
- // save the exception code in filters so that __exception_code() works.
- if (!Finder.foundCaptures() &&
- CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
- if (IsFilter)
- EmitSEHExceptionCodeSave(ParentCGF, nullptr, nullptr);
- return;
- }
-
- llvm::Value *EntryFP = nullptr;
- CGBuilderTy Builder(CGM, AllocaInsertPt);
- if (IsFilter && CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) {
- // 32-bit SEH filters need to be careful about FP recovery. The end of the
- // EH registration is passed in as the EBP physical register. We can
- // recover that with llvm.frameaddress(1).
- EntryFP = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::frameaddress), {Builder.getInt32(1)});
- } else {
- // Otherwise, for x64 and 32-bit finally functions, the parent FP is the
- // second parameter.
- auto AI = CurFn->arg_begin();
- ++AI;
- EntryFP = &*AI;
- }
-
- llvm::Value *ParentFP = EntryFP;
- if (IsFilter) {
- // Given whatever FP the runtime provided us in EntryFP, recover the true
- // frame pointer of the parent function. We only need to do this in filters,
- // since finally funclets recover the parent FP for us.
- llvm::Function *RecoverFPIntrin =
- CGM.getIntrinsic(llvm::Intrinsic::eh_recoverfp);
- llvm::Constant *ParentI8Fn =
- llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
- ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryFP});
- }
-
- // Create llvm.localrecover calls for all captures.
- for (const VarDecl *VD : Finder.Captures) {
- if (isa<ImplicitParamDecl>(VD)) {
- CGM.ErrorUnsupported(VD, "'this' captured by SEH");
- CXXThisValue = llvm::UndefValue::get(ConvertTypeForMem(VD->getType()));
- continue;
- }
- if (VD->getType()->isVariablyModifiedType()) {
- CGM.ErrorUnsupported(VD, "VLA captured by SEH");
- continue;
- }
- assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&
- "captured non-local variable");
-
- // If this decl hasn't been declared yet, it will be declared in the
- // OutlinedStmt.
- auto I = ParentCGF.LocalDeclMap.find(VD);
- if (I == ParentCGF.LocalDeclMap.end())
- continue;
-
- Address ParentVar = I->second;
- setAddrOfLocalVar(
- VD, recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP));
- }
-
- if (Finder.SEHCodeSlot.isValid()) {
- SEHCodeSlotStack.push_back(
- recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP));
- }
-
- if (IsFilter)
- EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryFP);
-}
-
-/// Arrange a function prototype that can be called by Windows exception
-/// handling personalities. On Win64, the prototype looks like:
-/// RetTy func(void *EHPtrs, void *ParentFP);
-void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
- bool IsFilter,
- const Stmt *OutlinedStmt) {
- SourceLocation StartLoc = OutlinedStmt->getBeginLoc();
-
- // Get the mangled function name.
- SmallString<128> Name;
- {
- llvm::raw_svector_ostream OS(Name);
- const NamedDecl *ParentSEHFn = ParentCGF.CurSEHParent;
- assert(ParentSEHFn && "No CurSEHParent!");
- MangleContext &Mangler = CGM.getCXXABI().getMangleContext();
- if (IsFilter)
- Mangler.mangleSEHFilterExpression(ParentSEHFn, OS);
- else
- Mangler.mangleSEHFinallyBlock(ParentSEHFn, OS);
- }
-
- FunctionArgList Args;
- if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) {
- // All SEH finally functions take two parameters. Win64 filters take two
- // parameters. Win32 filters take no parameters.
- if (IsFilter) {
- Args.push_back(ImplicitParamDecl::Create(
- getContext(), /*DC=*/nullptr, StartLoc,
- &getContext().Idents.get("exception_pointers"),
- getContext().VoidPtrTy, ImplicitParamDecl::Other));
- } else {
- Args.push_back(ImplicitParamDecl::Create(
- getContext(), /*DC=*/nullptr, StartLoc,
- &getContext().Idents.get("abnormal_termination"),
- getContext().UnsignedCharTy, ImplicitParamDecl::Other));
- }
- Args.push_back(ImplicitParamDecl::Create(
- getContext(), /*DC=*/nullptr, StartLoc,
- &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy,
- ImplicitParamDecl::Other));
- }
-
- QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy;
-
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args);
-
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
- llvm::Function *Fn = llvm::Function::Create(
- FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());
-
- IsOutlinedSEHHelper = true;
-
- StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
- OutlinedStmt->getBeginLoc(), OutlinedStmt->getBeginLoc());
- CurSEHParent = ParentCGF.CurSEHParent;
-
- CGM.SetLLVMFunctionAttributes(GlobalDecl(), FnInfo, CurFn);
- EmitCapturedLocals(ParentCGF, OutlinedStmt, IsFilter);
-}
-
-/// Create a stub filter function that will ultimately hold the code of the
-/// filter expression. The EH preparation passes in LLVM will outline the code
-/// from the main function body into this stub.
-llvm::Function *
-CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
- const SEHExceptStmt &Except) {
- const Expr *FilterExpr = Except.getFilterExpr();
- startOutlinedSEHHelper(ParentCGF, true, FilterExpr);
-
- // Emit the original filter expression, convert to i32, and return.
- llvm::Value *R = EmitScalarExpr(FilterExpr);
- R = Builder.CreateIntCast(R, ConvertType(getContext().LongTy),
- FilterExpr->getType()->isSignedIntegerType());
- Builder.CreateStore(R, ReturnValue);
-
- FinishFunction(FilterExpr->getEndLoc());
-
- return CurFn;
-}
-
-llvm::Function *
-CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
- const SEHFinallyStmt &Finally) {
- const Stmt *FinallyBlock = Finally.getBlock();
- startOutlinedSEHHelper(ParentCGF, false, FinallyBlock);
-
- // Emit the original filter expression, convert to i32, and return.
- EmitStmt(FinallyBlock);
-
- FinishFunction(FinallyBlock->getEndLoc());
-
- return CurFn;
-}
-
-void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,
- llvm::Value *ParentFP,
- llvm::Value *EntryFP) {
- // Get the pointer to the EXCEPTION_POINTERS struct. This is returned by the
- // __exception_info intrinsic.
- if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
- // On Win64, the info is passed as the first parameter to the filter.
- SEHInfo = &*CurFn->arg_begin();
- SEHCodeSlotStack.push_back(
- CreateMemTemp(getContext().IntTy, "__exception_code"));
- } else {
- // On Win32, the EBP on entry to the filter points to the end of an
- // exception registration object. It contains 6 32-bit fields, and the info
- // pointer is stored in the second field. So, GEP 20 bytes backwards and
- // load the pointer.
- SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryFP, -20);
- SEHInfo = Builder.CreateBitCast(SEHInfo, Int8PtrTy->getPointerTo());
- SEHInfo = Builder.CreateAlignedLoad(Int8PtrTy, SEHInfo, getPointerAlign());
- SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal(
- ParentCGF, ParentCGF.SEHCodeSlotStack.back(), ParentFP));
- }
-
- // Save the exception code in the exception slot to unify exception access in
- // the filter function and the landing pad.
- // struct EXCEPTION_POINTERS {
- // EXCEPTION_RECORD *ExceptionRecord;
- // CONTEXT *ContextRecord;
- // };
- // int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode;
- llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
- llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy);
- llvm::Value *Ptrs = Builder.CreateBitCast(SEHInfo, PtrsTy->getPointerTo());
- llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0);
- Rec = Builder.CreateAlignedLoad(Rec, getPointerAlign());
- llvm::Value *Code = Builder.CreateAlignedLoad(Rec, getIntAlign());
- assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except");
- Builder.CreateStore(Code, SEHCodeSlotStack.back());
-}
-
-llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() {
- // Sema should diagnose calling this builtin outside of a filter context, but
- // don't crash if we screw up.
- if (!SEHInfo)
- return llvm::UndefValue::get(Int8PtrTy);
- assert(SEHInfo->getType() == Int8PtrTy);
- return SEHInfo;
-}
-
-llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
- assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except");
- return Builder.CreateLoad(SEHCodeSlotStack.back());
-}
-
-llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
- // Abnormal termination is just the first parameter to the outlined finally
- // helper.
- auto AI = CurFn->arg_begin();
- return Builder.CreateZExt(&*AI, Int32Ty);
-}
-
-void CodeGenFunction::pushSEHCleanup(CleanupKind Kind,
- llvm::Function *FinallyFunc) {
- EHStack.pushCleanup<PerformSEHFinally>(Kind, FinallyFunc);
-}
-
-void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
- CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
- if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
- // Outline the finally block.
- llvm::Function *FinallyFunc =
- HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
-
- // Push a cleanup for __finally blocks.
- EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
- return;
- }
-
- // Otherwise, we must have an __except block.
- const SEHExceptStmt *Except = S.getExceptHandler();
- assert(Except);
- EHCatchScope *CatchScope = EHStack.pushCatch(1);
- SEHCodeSlotStack.push_back(
- CreateMemTemp(getContext().IntTy, "__exception_code"));
-
- // If the filter is known to evaluate to 1, then we can use the clause
- // "catch i8* null". We can't do this on x86 because the filter has to save
- // the exception code.
- llvm::Constant *C =
- ConstantEmitter(*this).tryEmitAbstract(Except->getFilterExpr(),
- getContext().IntTy);
- if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C &&
- C->isOneValue()) {
- CatchScope->setCatchAllHandler(0, createBasicBlock("__except"));
- return;
- }
-
- // In general, we have to emit an outlined filter function. Use the function
- // in place of the RTTI typeinfo global that C++ EH uses.
- llvm::Function *FilterFunc =
- HelperCGF.GenerateSEHFilterFunction(*this, *Except);
- llvm::Constant *OpaqueFunc =
- llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
- CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except.ret"));
-}
-
-void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
- // Just pop the cleanup if it's a __finally block.
- if (S.getFinallyHandler()) {
- PopCleanupBlock();
- return;
- }
-
- // Otherwise, we must have an __except block.
- const SEHExceptStmt *Except = S.getExceptHandler();
- assert(Except && "__try must have __finally xor __except");
- EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
-
- // Don't emit the __except block if the __try block lacked invokes.
- // TODO: Model unwind edges from instructions, either with iload / istore or
- // a try body function.
- if (!CatchScope.hasEHBranches()) {
- CatchScope.clearHandlerBlocks();
- EHStack.popCatch();
- SEHCodeSlotStack.pop_back();
- return;
- }
-
- // The fall-through block.
- llvm::BasicBlock *ContBB = createBasicBlock("__try.cont");
-
- // We just emitted the body of the __try; jump to the continue block.
- if (HaveInsertPoint())
- Builder.CreateBr(ContBB);
-
- // Check if our filter function returned true.
- emitCatchDispatchBlock(*this, CatchScope);
-
- // Grab the block before we pop the handler.
- llvm::BasicBlock *CatchPadBB = CatchScope.getHandler(0).Block;
- EHStack.popCatch();
-
- EmitBlockAfterUses(CatchPadBB);
-
- // __except blocks don't get outlined into funclets, so immediately do a
- // catchret.
- llvm::CatchPadInst *CPI =
- cast<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI());
- llvm::BasicBlock *ExceptBB = createBasicBlock("__except");
- Builder.CreateCatchRet(CPI, ExceptBB);
- EmitBlock(ExceptBB);
-
- // On Win64, the exception code is returned in EAX. Copy it into the slot.
- if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
- llvm::Function *SEHCodeIntrin =
- CGM.getIntrinsic(llvm::Intrinsic::eh_exceptioncode);
- llvm::Value *Code = Builder.CreateCall(SEHCodeIntrin, {CPI});
- Builder.CreateStore(Code, SEHCodeSlotStack.back());
- }
-
- // Emit the __except body.
- EmitStmt(Except->getBlock());
-
- // End the lifetime of the exception code.
- SEHCodeSlotStack.pop_back();
-
- if (HaveInsertPoint())
- Builder.CreateBr(ContBB);
-
- EmitBlock(ContBB);
-}
-
-void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {
- // If this code is reachable then emit a stop point (if generating
- // debug info). We have to do this ourselves because we are on the
- // "simple" statement path.
- if (HaveInsertPoint())
- EmitStopPoint(&S);
-
- // This must be a __leave from a __finally block, which we warn on and is UB.
- // Just emit unreachable.
- if (!isSEHTryScope()) {
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
- return;
- }
-
- EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGExpr.cpp
deleted file mode 100644
index 34a921e2dc0..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGExpr.cpp
+++ /dev/null
@@ -1,4942 +0,0 @@
-//===--- CGExpr.cpp - Emit LLVM Code from Expressions ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Expr nodes as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CGCall.h"
-#include "CGCleanup.h"
-#include "CGDebugInfo.h"
-#include "CGObjCRuntime.h"
-#include "CGOpenMPRuntime.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "ConstantEmitter.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/NSAPI.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Transforms/Utils/SanitizerStats.h"
-
-#include <string>
-
-using namespace clang;
-using namespace CodeGen;
-
-//===--------------------------------------------------------------------===//
-// Miscellaneous Helper Methods
-//===--------------------------------------------------------------------===//
-
-llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
- unsigned addressSpace =
- cast<llvm::PointerType>(value->getType())->getAddressSpace();
-
- llvm::PointerType *destType = Int8PtrTy;
- if (addressSpace)
- destType = llvm::Type::getInt8PtrTy(getLLVMContext(), addressSpace);
-
- if (value->getType() == destType) return value;
- return Builder.CreateBitCast(value, destType);
-}
-
-/// CreateTempAlloca - This creates a alloca and inserts it into the entry
-/// block.
-Address CodeGenFunction::CreateTempAllocaWithoutCast(llvm::Type *Ty,
- CharUnits Align,
- const Twine &Name,
- llvm::Value *ArraySize) {
- auto Alloca = CreateTempAlloca(Ty, Name, ArraySize);
- Alloca->setAlignment(Align.getQuantity());
- return Address(Alloca, Align);
-}
-
-/// CreateTempAlloca - This creates a alloca and inserts it into the entry
-/// block. The alloca is casted to default address space if necessary.
-Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
- const Twine &Name,
- llvm::Value *ArraySize,
- Address *AllocaAddr) {
- auto Alloca = CreateTempAllocaWithoutCast(Ty, Align, Name, ArraySize);
- if (AllocaAddr)
- *AllocaAddr = Alloca;
- llvm::Value *V = Alloca.getPointer();
- // Alloca always returns a pointer in alloca address space, which may
- // be different from the type defined by the language. For example,
- // in C++ the auto variables are in the default address space. Therefore
- // cast alloca to the default address space when necessary.
- if (getASTAllocaAddressSpace() != LangAS::Default) {
- auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default);
- llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
- // When ArraySize is nullptr, alloca is inserted at AllocaInsertPt,
- // otherwise alloca is inserted at the current insertion point of the
- // builder.
- if (!ArraySize)
- Builder.SetInsertPoint(AllocaInsertPt);
- V = getTargetHooks().performAddrSpaceCast(
- *this, V, getASTAllocaAddressSpace(), LangAS::Default,
- Ty->getPointerTo(DestAddrSpace), /*non-null*/ true);
- }
-
- return Address(V, Align);
-}
-
-/// CreateTempAlloca - This creates an alloca and inserts it into the entry
-/// block if \p ArraySize is nullptr, otherwise inserts it at the current
-/// insertion point of the builder.
-llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
- const Twine &Name,
- llvm::Value *ArraySize) {
- if (ArraySize)
- return Builder.CreateAlloca(Ty, ArraySize, Name);
- return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
- ArraySize, Name, AllocaInsertPt);
-}
-
-/// CreateDefaultAlignTempAlloca - This creates an alloca with the
-/// default alignment of the corresponding LLVM type, which is *not*
-/// guaranteed to be related in any way to the expected alignment of
-/// an AST type that might have been lowered to Ty.
-Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty,
- const Twine &Name) {
- CharUnits Align =
- CharUnits::fromQuantity(CGM.getDataLayout().getABITypeAlignment(Ty));
- return CreateTempAlloca(Ty, Align, Name);
-}
-
-void CodeGenFunction::InitTempAlloca(Address Var, llvm::Value *Init) {
- assert(isa<llvm::AllocaInst>(Var.getPointer()));
- auto *Store = new llvm::StoreInst(Init, Var.getPointer());
- Store->setAlignment(Var.getAlignment().getQuantity());
- llvm::BasicBlock *Block = AllocaInsertPt->getParent();
- Block->getInstList().insertAfter(AllocaInsertPt->getIterator(), Store);
-}
-
-Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) {
- CharUnits Align = getContext().getTypeAlignInChars(Ty);
- return CreateTempAlloca(ConvertType(Ty), Align, Name);
-}
-
-Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name,
- Address *Alloca) {
- // FIXME: Should we prefer the preferred type alignment here?
- return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name, Alloca);
-}
-
-Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align,
- const Twine &Name, Address *Alloca) {
- return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name,
- /*ArraySize=*/nullptr, Alloca);
-}
-
-Address CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, CharUnits Align,
- const Twine &Name) {
- return CreateTempAllocaWithoutCast(ConvertTypeForMem(Ty), Align, Name);
-}
-
-Address CodeGenFunction::CreateMemTempWithoutCast(QualType Ty,
- const Twine &Name) {
- return CreateMemTempWithoutCast(Ty, getContext().getTypeAlignInChars(Ty),
- Name);
-}
-
-/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
-/// expression and compare the result against zero, returning an Int1Ty value.
-llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
- PGO.setCurrentStmt(E);
- if (const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>()) {
- llvm::Value *MemPtr = EmitScalarExpr(E);
- return CGM.getCXXABI().EmitMemberPointerIsNotNull(*this, MemPtr, MPT);
- }
-
- QualType BoolTy = getContext().BoolTy;
- SourceLocation Loc = E->getExprLoc();
- if (!E->getType()->isAnyComplexType())
- return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy, Loc);
-
- return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(), BoolTy,
- Loc);
-}
-
-/// EmitIgnoredExpr - Emit code to compute the specified expression,
-/// ignoring the result.
-void CodeGenFunction::EmitIgnoredExpr(const Expr *E) {
- if (E->isRValue())
- return (void) EmitAnyExpr(E, AggValueSlot::ignored(), true);
-
- // Just emit it as an l-value and drop the result.
- EmitLValue(E);
-}
-
-/// EmitAnyExpr - Emit code to compute the specified expression which
-/// can have any type. The result is returned as an RValue struct.
-/// If this is an aggregate expression, AggSlot indicates where the
-/// result should be returned.
-RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
- AggValueSlot aggSlot,
- bool ignoreResult) {
- switch (getEvaluationKind(E->getType())) {
- case TEK_Scalar:
- return RValue::get(EmitScalarExpr(E, ignoreResult));
- case TEK_Complex:
- return RValue::getComplex(EmitComplexExpr(E, ignoreResult, ignoreResult));
- case TEK_Aggregate:
- if (!ignoreResult && aggSlot.isIgnored())
- aggSlot = CreateAggTemp(E->getType(), "agg-temp");
- EmitAggExpr(E, aggSlot);
- return aggSlot.asRValue();
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-/// EmitAnyExprToTemp - Similar to EmitAnyExpr(), however, the result will
-/// always be accessible even if no aggregate location is provided.
-RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
- AggValueSlot AggSlot = AggValueSlot::ignored();
-
- if (hasAggregateEvaluationKind(E->getType()))
- AggSlot = CreateAggTemp(E->getType(), "agg.tmp");
- return EmitAnyExpr(E, AggSlot);
-}
-
-/// EmitAnyExprToMem - Evaluate an expression into a given memory
-/// location.
-void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
- Address Location,
- Qualifiers Quals,
- bool IsInit) {
- // FIXME: This function should take an LValue as an argument.
- switch (getEvaluationKind(E->getType())) {
- case TEK_Complex:
- EmitComplexExprIntoLValue(E, MakeAddrLValue(Location, E->getType()),
- /*isInit*/ false);
- return;
-
- case TEK_Aggregate: {
- EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals,
- AggValueSlot::IsDestructed_t(IsInit),
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsAliased_t(!IsInit),
- AggValueSlot::MayOverlap));
- return;
- }
-
- case TEK_Scalar: {
- RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
- LValue LV = MakeAddrLValue(Location, E->getType());
- EmitStoreThroughLValue(RV, LV);
- return;
- }
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-static void
-pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
- const Expr *E, Address ReferenceTemporary) {
- // Objective-C++ ARC:
- // If we are binding a reference to a temporary that has ownership, we
- // need to perform retain/release operations on the temporary.
- //
- // FIXME: This should be looking at E, not M.
- if (auto Lifetime = M->getType().getObjCLifetime()) {
- switch (Lifetime) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- // Carry on to normal cleanup handling.
- break;
-
- case Qualifiers::OCL_Autoreleasing:
- // Nothing to do; cleaned up by an autorelease pool.
- return;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- switch (StorageDuration Duration = M->getStorageDuration()) {
- case SD_Static:
- // Note: we intentionally do not register a cleanup to release
- // the object on program termination.
- return;
-
- case SD_Thread:
- // FIXME: We should probably register a cleanup in this case.
- return;
-
- case SD_Automatic:
- case SD_FullExpression:
- CodeGenFunction::Destroyer *Destroy;
- CleanupKind CleanupKind;
- if (Lifetime == Qualifiers::OCL_Strong) {
- const ValueDecl *VD = M->getExtendingDecl();
- bool Precise =
- VD && isa<VarDecl>(VD) && VD->hasAttr<ObjCPreciseLifetimeAttr>();
- CleanupKind = CGF.getARCCleanupKind();
- Destroy = Precise ? &CodeGenFunction::destroyARCStrongPrecise
- : &CodeGenFunction::destroyARCStrongImprecise;
- } else {
- // __weak objects always get EH cleanups; otherwise, exceptions
- // could cause really nasty crashes instead of mere leaks.
- CleanupKind = NormalAndEHCleanup;
- Destroy = &CodeGenFunction::destroyARCWeak;
- }
- if (Duration == SD_FullExpression)
- CGF.pushDestroy(CleanupKind, ReferenceTemporary,
- M->getType(), *Destroy,
- CleanupKind & EHCleanup);
- else
- CGF.pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary,
- M->getType(),
- *Destroy, CleanupKind & EHCleanup);
- return;
-
- case SD_Dynamic:
- llvm_unreachable("temporary cannot have dynamic storage duration");
- }
- llvm_unreachable("unknown storage duration");
- }
- }
-
- CXXDestructorDecl *ReferenceTemporaryDtor = nullptr;
- if (const RecordType *RT =
- E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
- // Get the destructor for the reference temporary.
- auto *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (!ClassDecl->hasTrivialDestructor())
- ReferenceTemporaryDtor = ClassDecl->getDestructor();
- }
-
- if (!ReferenceTemporaryDtor)
- return;
-
- // Call the destructor for the temporary.
- switch (M->getStorageDuration()) {
- case SD_Static:
- case SD_Thread: {
- llvm::Constant *CleanupFn;
- llvm::Constant *CleanupArg;
- if (E->getType()->isArrayType()) {
- CleanupFn = CodeGenFunction(CGF.CGM).generateDestroyHelper(
- ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject, CGF.getLangOpts().Exceptions,
- dyn_cast_or_null<VarDecl>(M->getExtendingDecl()));
- CleanupArg = llvm::Constant::getNullValue(CGF.Int8PtrTy);
- } else {
- CleanupFn = CGF.CGM.getAddrOfCXXStructor(ReferenceTemporaryDtor,
- StructorType::Complete);
- CleanupArg = cast<llvm::Constant>(ReferenceTemporary.getPointer());
- }
- CGF.CGM.getCXXABI().registerGlobalDtor(
- CGF, *cast<VarDecl>(M->getExtendingDecl()), CleanupFn, CleanupArg);
- break;
- }
-
- case SD_FullExpression:
- CGF.pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject,
- CGF.getLangOpts().Exceptions);
- break;
-
- case SD_Automatic:
- CGF.pushLifetimeExtendedDestroy(NormalAndEHCleanup,
- ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject,
- CGF.getLangOpts().Exceptions);
- break;
-
- case SD_Dynamic:
- llvm_unreachable("temporary cannot have dynamic storage duration");
- }
-}
-
-static Address createReferenceTemporary(CodeGenFunction &CGF,
- const MaterializeTemporaryExpr *M,
- const Expr *Inner,
- Address *Alloca = nullptr) {
- auto &TCG = CGF.getTargetHooks();
- switch (M->getStorageDuration()) {
- case SD_FullExpression:
- case SD_Automatic: {
- // If we have a constant temporary array or record try to promote it into a
- // constant global under the same rules a normal constant would've been
- // promoted. This is easier on the optimizer and generally emits fewer
- // instructions.
- QualType Ty = Inner->getType();
- if (CGF.CGM.getCodeGenOpts().MergeAllConstants &&
- (Ty->isArrayType() || Ty->isRecordType()) &&
- CGF.CGM.isTypeConstant(Ty, true))
- if (auto Init = ConstantEmitter(CGF).tryEmitAbstract(Inner, Ty)) {
- if (auto AddrSpace = CGF.getTarget().getConstantAddressSpace()) {
- auto AS = AddrSpace.getValue();
- auto *GV = new llvm::GlobalVariable(
- CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp", nullptr,
- llvm::GlobalValue::NotThreadLocal,
- CGF.getContext().getTargetAddressSpace(AS));
- CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
- GV->setAlignment(alignment.getQuantity());
- llvm::Constant *C = GV;
- if (AS != LangAS::Default)
- C = TCG.performAddrSpaceCast(
- CGF.CGM, GV, AS, LangAS::Default,
- GV->getValueType()->getPointerTo(
- CGF.getContext().getTargetAddressSpace(LangAS::Default)));
- // FIXME: Should we put the new global into a COMDAT?
- return Address(C, alignment);
- }
- }
- return CGF.CreateMemTemp(Ty, "ref.tmp", Alloca);
- }
- case SD_Thread:
- case SD_Static:
- return CGF.CGM.GetAddrOfGlobalTemporary(M, Inner);
-
- case SD_Dynamic:
- llvm_unreachable("temporary can't have dynamic storage duration");
- }
- llvm_unreachable("unknown storage duration");
-}
-
-LValue CodeGenFunction::
-EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
- const Expr *E = M->GetTemporaryExpr();
-
- assert((!M->getExtendingDecl() || !isa<VarDecl>(M->getExtendingDecl()) ||
- !cast<VarDecl>(M->getExtendingDecl())->isARCPseudoStrong()) &&
- "Reference should never be pseudo-strong!");
-
- // FIXME: ideally this would use EmitAnyExprToMem, however, we cannot do so
- // as that will cause the lifetime adjustment to be lost for ARC
- auto ownership = M->getType().getObjCLifetime();
- if (ownership != Qualifiers::OCL_None &&
- ownership != Qualifiers::OCL_ExplicitNone) {
- Address Object = createReferenceTemporary(*this, M, E);
- if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object.getPointer())) {
- Object = Address(llvm::ConstantExpr::getBitCast(Var,
- ConvertTypeForMem(E->getType())
- ->getPointerTo(Object.getAddressSpace())),
- Object.getAlignment());
-
- // createReferenceTemporary will promote the temporary to a global with a
- // constant initializer if it can. It can only do this to a value of
- // ARC-manageable type if the value is global and therefore "immune" to
- // ref-counting operations. Therefore we have no need to emit either a
- // dynamic initialization or a cleanup and we can just return the address
- // of the temporary.
- if (Var->hasInitializer())
- return MakeAddrLValue(Object, M->getType(), AlignmentSource::Decl);
-
- Var->setInitializer(CGM.EmitNullConstant(E->getType()));
- }
- LValue RefTempDst = MakeAddrLValue(Object, M->getType(),
- AlignmentSource::Decl);
-
- switch (getEvaluationKind(E->getType())) {
- default: llvm_unreachable("expected scalar or aggregate expression");
- case TEK_Scalar:
- EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false);
- break;
- case TEK_Aggregate: {
- EmitAggExpr(E, AggValueSlot::forAddr(Object,
- E->getType().getQualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
- break;
- }
- }
-
- pushTemporaryCleanup(*this, M, E, Object);
- return RefTempDst;
- }
-
- SmallVector<const Expr *, 2> CommaLHSs;
- SmallVector<SubobjectAdjustment, 2> Adjustments;
- E = E->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
-
- for (const auto &Ignored : CommaLHSs)
- EmitIgnoredExpr(Ignored);
-
- if (const auto *opaque = dyn_cast<OpaqueValueExpr>(E)) {
- if (opaque->getType()->isRecordType()) {
- assert(Adjustments.empty());
- return EmitOpaqueValueLValue(opaque);
- }
- }
-
- // Create and initialize the reference temporary.
- Address Alloca = Address::invalid();
- Address Object = createReferenceTemporary(*this, M, E, &Alloca);
- if (auto *Var = dyn_cast<llvm::GlobalVariable>(
- Object.getPointer()->stripPointerCasts())) {
- Object = Address(llvm::ConstantExpr::getBitCast(
- cast<llvm::Constant>(Object.getPointer()),
- ConvertTypeForMem(E->getType())->getPointerTo()),
- Object.getAlignment());
- // If the temporary is a global and has a constant initializer or is a
- // constant temporary that we promoted to a global, we may have already
- // initialized it.
- if (!Var->hasInitializer()) {
- Var->setInitializer(CGM.EmitNullConstant(E->getType()));
- EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
- }
- } else {
- switch (M->getStorageDuration()) {
- case SD_Automatic:
- if (auto *Size = EmitLifetimeStart(
- CGM.getDataLayout().getTypeAllocSize(Alloca.getElementType()),
- Alloca.getPointer())) {
- pushCleanupAfterFullExpr<CallLifetimeEnd>(NormalEHLifetimeMarker,
- Alloca, Size);
- }
- break;
-
- case SD_FullExpression: {
- if (!ShouldEmitLifetimeMarkers)
- break;
-
- // Avoid creating a conditional cleanup just to hold an llvm.lifetime.end
- // marker. Instead, start the lifetime of a conditional temporary earlier
- // so that it's unconditional. Don't do this in ASan's use-after-scope
- // mode so that it gets the more precise lifetime marks. If the type has
- // a non-trivial destructor, we'll have a cleanup block for it anyway,
- // so this typically doesn't help; skip it in that case.
- ConditionalEvaluation *OldConditional = nullptr;
- CGBuilderTy::InsertPoint OldIP;
- if (isInConditionalBranch() && !E->getType().isDestructedType() &&
- !CGM.getCodeGenOpts().SanitizeAddressUseAfterScope) {
- OldConditional = OutermostConditional;
- OutermostConditional = nullptr;
-
- OldIP = Builder.saveIP();
- llvm::BasicBlock *Block = OldConditional->getStartingBlock();
- Builder.restoreIP(CGBuilderTy::InsertPoint(
- Block, llvm::BasicBlock::iterator(Block->back())));
- }
-
- if (auto *Size = EmitLifetimeStart(
- CGM.getDataLayout().getTypeAllocSize(Alloca.getElementType()),
- Alloca.getPointer())) {
- pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, Alloca,
- Size);
- }
-
- if (OldConditional) {
- OutermostConditional = OldConditional;
- Builder.restoreIP(OldIP);
- }
- break;
- }
-
- default:
- break;
- }
- EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
- }
- pushTemporaryCleanup(*this, M, E, Object);
-
- // Perform derived-to-base casts and/or field accesses, to get from the
- // temporary object we created (and, potentially, for which we extended
- // the lifetime) to the subobject we're binding the reference to.
- for (unsigned I = Adjustments.size(); I != 0; --I) {
- SubobjectAdjustment &Adjustment = Adjustments[I-1];
- switch (Adjustment.Kind) {
- case SubobjectAdjustment::DerivedToBaseAdjustment:
- Object =
- GetAddressOfBaseClass(Object, Adjustment.DerivedToBase.DerivedClass,
- Adjustment.DerivedToBase.BasePath->path_begin(),
- Adjustment.DerivedToBase.BasePath->path_end(),
- /*NullCheckValue=*/ false, E->getExprLoc());
- break;
-
- case SubobjectAdjustment::FieldAdjustment: {
- LValue LV = MakeAddrLValue(Object, E->getType(), AlignmentSource::Decl);
- LV = EmitLValueForField(LV, Adjustment.Field);
- assert(LV.isSimple() &&
- "materialized temporary field is not a simple lvalue");
- Object = LV.getAddress();
- break;
- }
-
- case SubobjectAdjustment::MemberPointerAdjustment: {
- llvm::Value *Ptr = EmitScalarExpr(Adjustment.Ptr.RHS);
- Object = EmitCXXMemberDataPointerAddress(E, Object, Ptr,
- Adjustment.Ptr.MPT);
- break;
- }
- }
- }
-
- return MakeAddrLValue(Object, M->getType(), AlignmentSource::Decl);
-}
-
-RValue
-CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E) {
- // Emit the expression as an lvalue.
- LValue LV = EmitLValue(E);
- assert(LV.isSimple());
- llvm::Value *Value = LV.getPointer();
-
- if (sanitizePerformTypeCheck() && !E->getType()->isFunctionType()) {
- // C++11 [dcl.ref]p5 (as amended by core issue 453):
- // If a glvalue to which a reference is directly bound designates neither
- // an existing object or function of an appropriate type nor a region of
- // storage of suitable size and alignment to contain an object of the
- // reference's type, the behavior is undefined.
- QualType Ty = E->getType();
- EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);
- }
-
- return RValue::get(Value);
-}
-
-
-/// getAccessedFieldNo - Given an encoded value and a result number, return the
-/// input field number being accessed.
-unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
- const llvm::Constant *Elts) {
- return cast<llvm::ConstantInt>(Elts->getAggregateElement(Idx))
- ->getZExtValue();
-}
-
-/// Emit the hash_16_bytes function from include/llvm/ADT/Hashing.h.
-static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
- llvm::Value *High) {
- llvm::Value *KMul = Builder.getInt64(0x9ddfea08eb382d69ULL);
- llvm::Value *K47 = Builder.getInt64(47);
- llvm::Value *A0 = Builder.CreateMul(Builder.CreateXor(Low, High), KMul);
- llvm::Value *A1 = Builder.CreateXor(Builder.CreateLShr(A0, K47), A0);
- llvm::Value *B0 = Builder.CreateMul(Builder.CreateXor(High, A1), KMul);
- llvm::Value *B1 = Builder.CreateXor(Builder.CreateLShr(B0, K47), B0);
- return Builder.CreateMul(B1, KMul);
-}
-
-bool CodeGenFunction::isNullPointerAllowed(TypeCheckKind TCK) {
- return TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
- TCK == TCK_UpcastToVirtualBase || TCK == TCK_DynamicOperation;
-}
-
-bool CodeGenFunction::isVptrCheckRequired(TypeCheckKind TCK, QualType Ty) {
- CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- return (RD && RD->hasDefinition() && RD->isDynamicClass()) &&
- (TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
- TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference ||
- TCK == TCK_UpcastToVirtualBase || TCK == TCK_DynamicOperation);
-}
-
-bool CodeGenFunction::sanitizePerformTypeCheck() const {
- return SanOpts.has(SanitizerKind::Null) |
- SanOpts.has(SanitizerKind::Alignment) |
- SanOpts.has(SanitizerKind::ObjectSize) |
- SanOpts.has(SanitizerKind::Vptr);
-}
-
-void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
- llvm::Value *Ptr, QualType Ty,
- CharUnits Alignment,
- SanitizerSet SkippedChecks) {
- if (!sanitizePerformTypeCheck())
- return;
-
- // Don't check pointers outside the default address space. The null check
- // isn't correct, the object-size check isn't supported by LLVM, and we can't
- // communicate the addresses to the runtime handler for the vptr check.
- if (Ptr->getType()->getPointerAddressSpace())
- return;
-
- // Don't check pointers to volatile data. The behavior here is implementation-
- // defined.
- if (Ty.isVolatileQualified())
- return;
-
- SanitizerScope SanScope(this);
-
- SmallVector<std::pair<llvm::Value *, SanitizerMask>, 3> Checks;
- llvm::BasicBlock *Done = nullptr;
-
- // Quickly determine whether we have a pointer to an alloca. It's possible
- // to skip null checks, and some alignment checks, for these pointers. This
- // can reduce compile-time significantly.
- auto PtrToAlloca =
- dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCastsNoFollowAliases());
-
- llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext());
- llvm::Value *IsNonNull = nullptr;
- bool IsGuaranteedNonNull =
- SkippedChecks.has(SanitizerKind::Null) || PtrToAlloca;
- bool AllowNullPointers = isNullPointerAllowed(TCK);
- if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
- !IsGuaranteedNonNull) {
- // The glvalue must not be an empty glvalue.
- IsNonNull = Builder.CreateIsNotNull(Ptr);
-
- // The IR builder can constant-fold the null check if the pointer points to
- // a constant.
- IsGuaranteedNonNull = IsNonNull == True;
-
- // Skip the null check if the pointer is known to be non-null.
- if (!IsGuaranteedNonNull) {
- if (AllowNullPointers) {
- // When performing pointer casts, it's OK if the value is null.
- // Skip the remaining checks in that case.
- Done = createBasicBlock("null");
- llvm::BasicBlock *Rest = createBasicBlock("not.null");
- Builder.CreateCondBr(IsNonNull, Rest, Done);
- EmitBlock(Rest);
- } else {
- Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
- }
- }
- }
-
- if (SanOpts.has(SanitizerKind::ObjectSize) &&
- !SkippedChecks.has(SanitizerKind::ObjectSize) &&
- !Ty->isIncompleteType()) {
- uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
-
- // The glvalue must refer to a large enough storage region.
- // FIXME: If Address Sanitizer is enabled, insert dynamic instrumentation
- // to check this.
- // FIXME: Get object address space
- llvm::Type *Tys[2] = { IntPtrTy, Int8PtrTy };
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys);
- llvm::Value *Min = Builder.getFalse();
- llvm::Value *NullIsUnknown = Builder.getFalse();
- llvm::Value *CastAddr = Builder.CreateBitCast(Ptr, Int8PtrTy);
- llvm::Value *LargeEnough = Builder.CreateICmpUGE(
- Builder.CreateCall(F, {CastAddr, Min, NullIsUnknown}),
- llvm::ConstantInt::get(IntPtrTy, Size));
- Checks.push_back(std::make_pair(LargeEnough, SanitizerKind::ObjectSize));
- }
-
- uint64_t AlignVal = 0;
- llvm::Value *PtrAsInt = nullptr;
-
- if (SanOpts.has(SanitizerKind::Alignment) &&
- !SkippedChecks.has(SanitizerKind::Alignment)) {
- AlignVal = Alignment.getQuantity();
- if (!Ty->isIncompleteType() && !AlignVal)
- AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
-
- // The glvalue must be suitably aligned.
- if (AlignVal > 1 &&
- (!PtrToAlloca || PtrToAlloca->getAlignment() < AlignVal)) {
- PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy);
- llvm::Value *Align = Builder.CreateAnd(
- PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
- llvm::Value *Aligned =
- Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
- if (Aligned != True)
- Checks.push_back(std::make_pair(Aligned, SanitizerKind::Alignment));
- }
- }
-
- if (Checks.size() > 0) {
- // Make sure we're not losing information. Alignment needs to be a power of
- // 2
- assert(!AlignVal || (uint64_t)1 << llvm::Log2_64(AlignVal) == AlignVal);
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty),
- llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2_64(AlignVal) : 1),
- llvm::ConstantInt::get(Int8Ty, TCK)};
- EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData,
- PtrAsInt ? PtrAsInt : Ptr);
- }
-
- // If possible, check that the vptr indicates that there is a subobject of
- // type Ty at offset zero within this object.
- //
- // C++11 [basic.life]p5,6:
- // [For storage which does not refer to an object within its lifetime]
- // The program has undefined behavior if:
- // -- the [pointer or glvalue] is used to access a non-static data member
- // or call a non-static member function
- if (SanOpts.has(SanitizerKind::Vptr) &&
- !SkippedChecks.has(SanitizerKind::Vptr) && isVptrCheckRequired(TCK, Ty)) {
- // Ensure that the pointer is non-null before loading it. If there is no
- // compile-time guarantee, reuse the run-time null check or emit a new one.
- if (!IsGuaranteedNonNull) {
- if (!IsNonNull)
- IsNonNull = Builder.CreateIsNotNull(Ptr);
- if (!Done)
- Done = createBasicBlock("vptr.null");
- llvm::BasicBlock *VptrNotNull = createBasicBlock("vptr.not.null");
- Builder.CreateCondBr(IsNonNull, VptrNotNull, Done);
- EmitBlock(VptrNotNull);
- }
-
- // Compute a hash of the mangled name of the type.
- //
- // FIXME: This is not guaranteed to be deterministic! Move to a
- // fingerprinting mechanism once LLVM provides one. For the time
- // being the implementation happens to be deterministic.
- SmallString<64> MangledName;
- llvm::raw_svector_ostream Out(MangledName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
- Out);
-
- // Blacklist based on the mangled type.
- if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType(
- SanitizerKind::Vptr, Out.str())) {
- llvm::hash_code TypeHash = hash_value(Out.str());
-
- // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
- llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash);
- llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0);
- Address VPtrAddr(Builder.CreateBitCast(Ptr, VPtrTy), getPointerAlign());
- llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr);
- llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty);
-
- llvm::Value *Hash = emitHash16Bytes(Builder, Low, High);
- Hash = Builder.CreateTrunc(Hash, IntPtrTy);
-
- // Look the hash up in our cache.
- const int CacheSize = 128;
- llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize);
- llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable,
- "__ubsan_vptr_type_cache");
- llvm::Value *Slot = Builder.CreateAnd(Hash,
- llvm::ConstantInt::get(IntPtrTy,
- CacheSize-1));
- llvm::Value *Indices[] = { Builder.getInt32(0), Slot };
- llvm::Value *CacheVal =
- Builder.CreateAlignedLoad(Builder.CreateInBoundsGEP(Cache, Indices),
- getPointerAlign());
-
- // If the hash isn't in the cache, call a runtime handler to perform the
- // hard work of checking whether the vptr is for an object of the right
- // type. This will either fill in the cache and return, or produce a
- // diagnostic.
- llvm::Value *EqualHash = Builder.CreateICmpEQ(CacheVal, Hash);
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(Loc),
- EmitCheckTypeDescriptor(Ty),
- CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()),
- llvm::ConstantInt::get(Int8Ty, TCK)
- };
- llvm::Value *DynamicData[] = { Ptr, Hash };
- EmitCheck(std::make_pair(EqualHash, SanitizerKind::Vptr),
- SanitizerHandler::DynamicTypeCacheMiss, StaticData,
- DynamicData);
- }
- }
-
- if (Done) {
- Builder.CreateBr(Done);
- EmitBlock(Done);
- }
-}
-
-/// Determine whether this expression refers to a flexible array member in a
-/// struct. We disable array bounds checks for such members.
-static bool isFlexibleArrayMemberExpr(const Expr *E) {
- // For compatibility with existing code, we treat arrays of length 0 or
- // 1 as flexible array members.
- const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe();
- if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- if (CAT->getSize().ugt(1))
- return false;
- } else if (!isa<IncompleteArrayType>(AT))
- return false;
-
- E = E->IgnoreParens();
-
- // A flexible array member must be the last member in the class.
- if (const auto *ME = dyn_cast<MemberExpr>(E)) {
- // FIXME: If the base type of the member expr is not FD->getParent(),
- // this should not be treated as a flexible array member access.
- if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- RecordDecl::field_iterator FI(
- DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
- return ++FI == FD->getParent()->field_end();
- }
- } else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E)) {
- return IRE->getDecl()->getNextIvar() == nullptr;
- }
-
- return false;
-}
-
-llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E,
- QualType EltTy) {
- ASTContext &C = getContext();
- uint64_t EltSize = C.getTypeSizeInChars(EltTy).getQuantity();
- if (!EltSize)
- return nullptr;
-
- auto *ArrayDeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
- if (!ArrayDeclRef)
- return nullptr;
-
- auto *ParamDecl = dyn_cast<ParmVarDecl>(ArrayDeclRef->getDecl());
- if (!ParamDecl)
- return nullptr;
-
- auto *POSAttr = ParamDecl->getAttr<PassObjectSizeAttr>();
- if (!POSAttr)
- return nullptr;
-
- // Don't load the size if it's a lower bound.
- int POSType = POSAttr->getType();
- if (POSType != 0 && POSType != 1)
- return nullptr;
-
- // Find the implicit size parameter.
- auto PassedSizeIt = SizeArguments.find(ParamDecl);
- if (PassedSizeIt == SizeArguments.end())
- return nullptr;
-
- const ImplicitParamDecl *PassedSizeDecl = PassedSizeIt->second;
- assert(LocalDeclMap.count(PassedSizeDecl) && "Passed size not loadable");
- Address AddrOfSize = LocalDeclMap.find(PassedSizeDecl)->second;
- llvm::Value *SizeInBytes = EmitLoadOfScalar(AddrOfSize, /*Volatile=*/false,
- C.getSizeType(), E->getExprLoc());
- llvm::Value *SizeOfElement =
- llvm::ConstantInt::get(SizeInBytes->getType(), EltSize);
- return Builder.CreateUDiv(SizeInBytes, SizeOfElement);
-}
-
-/// If Base is known to point to the start of an array, return the length of
-/// that array. Return 0 if the length cannot be determined.
-static llvm::Value *getArrayIndexingBound(
- CodeGenFunction &CGF, const Expr *Base, QualType &IndexedType) {
- // For the vector indexing extension, the bound is the number of elements.
- if (const VectorType *VT = Base->getType()->getAs<VectorType>()) {
- IndexedType = Base->getType();
- return CGF.Builder.getInt32(VT->getNumElements());
- }
-
- Base = Base->IgnoreParens();
-
- if (const auto *CE = dyn_cast<CastExpr>(Base)) {
- if (CE->getCastKind() == CK_ArrayToPointerDecay &&
- !isFlexibleArrayMemberExpr(CE->getSubExpr())) {
- IndexedType = CE->getSubExpr()->getType();
- const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe();
- if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
- return CGF.Builder.getInt(CAT->getSize());
- else if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
- return CGF.getVLASize(VAT).NumElts;
- // Ignore pass_object_size here. It's not applicable on decayed pointers.
- }
- }
-
- QualType EltTy{Base->getType()->getPointeeOrArrayElementType(), 0};
- if (llvm::Value *POS = CGF.LoadPassedObjectSize(Base, EltTy)) {
- IndexedType = Base->getType();
- return POS;
- }
-
- return nullptr;
-}
-
-void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
- llvm::Value *Index, QualType IndexType,
- bool Accessed) {
- assert(SanOpts.has(SanitizerKind::ArrayBounds) &&
- "should not be called unless adding bounds checks");
- SanitizerScope SanScope(this);
-
- QualType IndexedType;
- llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType);
- if (!Bound)
- return;
-
- bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
- llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
- llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);
-
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(E->getExprLoc()),
- EmitCheckTypeDescriptor(IndexedType),
- EmitCheckTypeDescriptor(IndexType)
- };
- llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal)
- : Builder.CreateICmpULE(IndexVal, BoundVal);
- EmitCheck(std::make_pair(Check, SanitizerKind::ArrayBounds),
- SanitizerHandler::OutOfBounds, StaticData, Index);
-}
-
-
-CodeGenFunction::ComplexPairTy CodeGenFunction::
-EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
- bool isInc, bool isPre) {
- ComplexPairTy InVal = EmitLoadOfComplex(LV, E->getExprLoc());
-
- llvm::Value *NextVal;
- if (isa<llvm::IntegerType>(InVal.first->getType())) {
- uint64_t AmountVal = isInc ? 1 : -1;
- NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
-
- // Add the inc/dec to the real part.
- NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
- } else {
- QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
- llvm::APFloat FVal(getContext().getFloatTypeSemantics(ElemTy), 1);
- if (!isInc)
- FVal.changeSign();
- NextVal = llvm::ConstantFP::get(getLLVMContext(), FVal);
-
- // Add the inc/dec to the real part.
- NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
- }
-
- ComplexPairTy IncVal(NextVal, InVal.second);
-
- // Store the updated result through the lvalue.
- EmitStoreOfComplex(IncVal, LV, /*init*/ false);
-
- // If this is a postinc, return the value read from memory, otherwise use the
- // updated value.
- return isPre ? IncVal : InVal;
-}
-
-void CodeGenModule::EmitExplicitCastExprType(const ExplicitCastExpr *E,
- CodeGenFunction *CGF) {
- // Bind VLAs in the cast type.
- if (CGF && E->getType()->isVariablyModifiedType())
- CGF->EmitVariablyModifiedType(E->getType());
-
- if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->EmitExplicitCastType(E->getType());
-}
-
-//===----------------------------------------------------------------------===//
-// LValue Expression Emission
-//===----------------------------------------------------------------------===//
-
-/// EmitPointerWithAlignment - Given an expression of pointer type, try to
-/// derive a more accurate bound on the alignment of the pointer.
-Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
- LValueBaseInfo *BaseInfo,
- TBAAAccessInfo *TBAAInfo) {
- // We allow this with ObjC object pointers because of fragile ABIs.
- assert(E->getType()->isPointerType() ||
- E->getType()->isObjCObjectPointerType());
- E = E->IgnoreParens();
-
- // Casts:
- if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
- if (const auto *ECE = dyn_cast<ExplicitCastExpr>(CE))
- CGM.EmitExplicitCastExprType(ECE, this);
-
- switch (CE->getCastKind()) {
- // Non-converting casts (but not C's implicit conversion from void*).
- case CK_BitCast:
- case CK_NoOp:
- case CK_AddressSpaceConversion:
- if (auto PtrTy = CE->getSubExpr()->getType()->getAs<PointerType>()) {
- if (PtrTy->getPointeeType()->isVoidType())
- break;
-
- LValueBaseInfo InnerBaseInfo;
- TBAAAccessInfo InnerTBAAInfo;
- Address Addr = EmitPointerWithAlignment(CE->getSubExpr(),
- &InnerBaseInfo,
- &InnerTBAAInfo);
- if (BaseInfo) *BaseInfo = InnerBaseInfo;
- if (TBAAInfo) *TBAAInfo = InnerTBAAInfo;
-
- if (isa<ExplicitCastExpr>(CE)) {
- LValueBaseInfo TargetTypeBaseInfo;
- TBAAAccessInfo TargetTypeTBAAInfo;
- CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(),
- &TargetTypeBaseInfo,
- &TargetTypeTBAAInfo);
- if (TBAAInfo)
- *TBAAInfo = CGM.mergeTBAAInfoForCast(*TBAAInfo,
- TargetTypeTBAAInfo);
- // If the source l-value is opaque, honor the alignment of the
- // casted-to type.
- if (InnerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) {
- if (BaseInfo)
- BaseInfo->mergeForCast(TargetTypeBaseInfo);
- Addr = Address(Addr.getPointer(), Align);
- }
- }
-
- if (SanOpts.has(SanitizerKind::CFIUnrelatedCast) &&
- CE->getCastKind() == CK_BitCast) {
- if (auto PT = E->getType()->getAs<PointerType>())
- EmitVTablePtrCheckForCast(PT->getPointeeType(), Addr.getPointer(),
- /*MayBeNull=*/true,
- CodeGenFunction::CFITCK_UnrelatedCast,
- CE->getBeginLoc());
- }
- return CE->getCastKind() != CK_AddressSpaceConversion
- ? Builder.CreateBitCast(Addr, ConvertType(E->getType()))
- : Builder.CreateAddrSpaceCast(Addr,
- ConvertType(E->getType()));
- }
- break;
-
- // Array-to-pointer decay.
- case CK_ArrayToPointerDecay:
- return EmitArrayToPointerDecay(CE->getSubExpr(), BaseInfo, TBAAInfo);
-
- // Derived-to-base conversions.
- case CK_UncheckedDerivedToBase:
- case CK_DerivedToBase: {
- // TODO: Support accesses to members of base classes in TBAA. For now, we
- // conservatively pretend that the complete object is of the base class
- // type.
- if (TBAAInfo)
- *TBAAInfo = CGM.getTBAAAccessInfo(E->getType());
- Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), BaseInfo);
- auto Derived = CE->getSubExpr()->getType()->getPointeeCXXRecordDecl();
- return GetAddressOfBaseClass(Addr, Derived,
- CE->path_begin(), CE->path_end(),
- ShouldNullCheckClassCastValue(CE),
- CE->getExprLoc());
- }
-
- // TODO: Is there any reason to treat base-to-derived conversions
- // specially?
- default:
- break;
- }
- }
-
- // Unary &.
- if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
- if (UO->getOpcode() == UO_AddrOf) {
- LValue LV = EmitLValue(UO->getSubExpr());
- if (BaseInfo) *BaseInfo = LV.getBaseInfo();
- if (TBAAInfo) *TBAAInfo = LV.getTBAAInfo();
- return LV.getAddress();
- }
- }
-
- // TODO: conditional operators, comma.
-
- // Otherwise, use the alignment of the type.
- CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), BaseInfo,
- TBAAInfo);
- return Address(EmitScalarExpr(E), Align);
-}
-
-RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
- if (Ty->isVoidType())
- return RValue::get(nullptr);
-
- switch (getEvaluationKind(Ty)) {
- case TEK_Complex: {
- llvm::Type *EltTy =
- ConvertType(Ty->castAs<ComplexType>()->getElementType());
- llvm::Value *U = llvm::UndefValue::get(EltTy);
- return RValue::getComplex(std::make_pair(U, U));
- }
-
- // If this is a use of an undefined aggregate type, the aggregate must have an
- // identifiable address. Just because the contents of the value are undefined
- // doesn't mean that the address can't be taken and compared.
- case TEK_Aggregate: {
- Address DestPtr = CreateMemTemp(Ty, "undef.agg.tmp");
- return RValue::getAggregate(DestPtr);
- }
-
- case TEK_Scalar:
- return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-RValue CodeGenFunction::EmitUnsupportedRValue(const Expr *E,
- const char *Name) {
- ErrorUnsupported(E, Name);
- return GetUndefRValue(E->getType());
-}
-
-LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
- const char *Name) {
- ErrorUnsupported(E, Name);
- llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType()));
- return MakeAddrLValue(Address(llvm::UndefValue::get(Ty), CharUnits::One()),
- E->getType());
-}
-
-bool CodeGenFunction::IsWrappedCXXThis(const Expr *Obj) {
- const Expr *Base = Obj;
- while (!isa<CXXThisExpr>(Base)) {
- // The result of a dynamic_cast can be null.
- if (isa<CXXDynamicCastExpr>(Base))
- return false;
-
- if (const auto *CE = dyn_cast<CastExpr>(Base)) {
- Base = CE->getSubExpr();
- } else if (const auto *PE = dyn_cast<ParenExpr>(Base)) {
- Base = PE->getSubExpr();
- } else if (const auto *UO = dyn_cast<UnaryOperator>(Base)) {
- if (UO->getOpcode() == UO_Extension)
- Base = UO->getSubExpr();
- else
- return false;
- } else {
- return false;
- }
- }
- return true;
-}
-
-LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
- LValue LV;
- if (SanOpts.has(SanitizerKind::ArrayBounds) && isa<ArraySubscriptExpr>(E))
- LV = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E), /*Accessed*/true);
- else
- LV = EmitLValue(E);
- if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple()) {
- SanitizerSet SkippedChecks;
- if (const auto *ME = dyn_cast<MemberExpr>(E)) {
- bool IsBaseCXXThis = IsWrappedCXXThis(ME->getBase());
- if (IsBaseCXXThis)
- SkippedChecks.set(SanitizerKind::Alignment, true);
- if (IsBaseCXXThis || isa<DeclRefExpr>(ME->getBase()))
- SkippedChecks.set(SanitizerKind::Null, true);
- }
- EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(),
- E->getType(), LV.getAlignment(), SkippedChecks);
- }
- return LV;
-}
-
-/// EmitLValue - Emit code to compute a designator that specifies the location
-/// of the expression.
-///
-/// This can return one of two things: a simple address or a bitfield reference.
-/// In either case, the LLVM Value* in the LValue structure is guaranteed to be
-/// an LLVM pointer type.
-///
-/// If this returns a bitfield reference, nothing about the pointee type of the
-/// LLVM value is known: For example, it may not be a pointer to an integer.
-///
-/// If this returns a normal address, and if the lvalue's C type is fixed size,
-/// this method guarantees that the returned pointer type will point to an LLVM
-/// type of the same size of the lvalue's type. If the lvalue has a variable
-/// length type, this is not possible.
-///
-LValue CodeGenFunction::EmitLValue(const Expr *E) {
- ApplyDebugLocation DL(*this, E);
- switch (E->getStmtClass()) {
- default: return EmitUnsupportedLValue(E, "l-value expression");
-
- case Expr::ObjCPropertyRefExprClass:
- llvm_unreachable("cannot emit a property reference directly");
-
- case Expr::ObjCSelectorExprClass:
- return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
- case Expr::ObjCIsaExprClass:
- return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
- case Expr::BinaryOperatorClass:
- return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
- case Expr::CompoundAssignOperatorClass: {
- QualType Ty = E->getType();
- if (const AtomicType *AT = Ty->getAs<AtomicType>())
- Ty = AT->getValueType();
- if (!Ty->isAnyComplexType())
- return EmitCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
- return EmitComplexCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
- }
- case Expr::CallExprClass:
- case Expr::CXXMemberCallExprClass:
- case Expr::CXXOperatorCallExprClass:
- case Expr::UserDefinedLiteralClass:
- return EmitCallExprLValue(cast<CallExpr>(E));
- case Expr::VAArgExprClass:
- return EmitVAArgExprLValue(cast<VAArgExpr>(E));
- case Expr::DeclRefExprClass:
- return EmitDeclRefLValue(cast<DeclRefExpr>(E));
- case Expr::ConstantExprClass:
- return EmitLValue(cast<ConstantExpr>(E)->getSubExpr());
- case Expr::ParenExprClass:
- return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
- case Expr::GenericSelectionExprClass:
- return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr());
- case Expr::PredefinedExprClass:
- return EmitPredefinedLValue(cast<PredefinedExpr>(E));
- case Expr::StringLiteralClass:
- return EmitStringLiteralLValue(cast<StringLiteral>(E));
- case Expr::ObjCEncodeExprClass:
- return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
- case Expr::PseudoObjectExprClass:
- return EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));
- case Expr::InitListExprClass:
- return EmitInitListLValue(cast<InitListExpr>(E));
- case Expr::CXXTemporaryObjectExprClass:
- case Expr::CXXConstructExprClass:
- return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
- case Expr::CXXBindTemporaryExprClass:
- return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
- case Expr::CXXUuidofExprClass:
- return EmitCXXUuidofLValue(cast<CXXUuidofExpr>(E));
- case Expr::LambdaExprClass:
- return EmitLambdaLValue(cast<LambdaExpr>(E));
-
- case Expr::ExprWithCleanupsClass: {
- const auto *cleanups = cast<ExprWithCleanups>(E);
- enterFullExpression(cleanups);
- RunCleanupsScope Scope(*this);
- LValue LV = EmitLValue(cleanups->getSubExpr());
- if (LV.isSimple()) {
- // Defend against branches out of gnu statement expressions surrounded by
- // cleanups.
- llvm::Value *V = LV.getPointer();
- Scope.ForceCleanup({&V});
- return LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(),
- getContext(), LV.getBaseInfo(), LV.getTBAAInfo());
- }
- // FIXME: Is it possible to create an ExprWithCleanups that produces a
- // bitfield lvalue or some other non-simple lvalue?
- return LV;
- }
-
- case Expr::CXXDefaultArgExprClass:
- return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr());
- case Expr::CXXDefaultInitExprClass: {
- CXXDefaultInitExprScope Scope(*this);
- return EmitLValue(cast<CXXDefaultInitExpr>(E)->getExpr());
- }
- case Expr::CXXTypeidExprClass:
- return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E));
-
- case Expr::ObjCMessageExprClass:
- return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
- case Expr::ObjCIvarRefExprClass:
- return EmitObjCIvarRefLValue(cast<ObjCIvarRefExpr>(E));
- case Expr::StmtExprClass:
- return EmitStmtExprLValue(cast<StmtExpr>(E));
- case Expr::UnaryOperatorClass:
- return EmitUnaryOpLValue(cast<UnaryOperator>(E));
- case Expr::ArraySubscriptExprClass:
- return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
- case Expr::OMPArraySectionExprClass:
- return EmitOMPArraySectionExpr(cast<OMPArraySectionExpr>(E));
- case Expr::ExtVectorElementExprClass:
- return EmitExtVectorElementExpr(cast<ExtVectorElementExpr>(E));
- case Expr::MemberExprClass:
- return EmitMemberExpr(cast<MemberExpr>(E));
- case Expr::CompoundLiteralExprClass:
- return EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E));
- case Expr::ConditionalOperatorClass:
- return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
- case Expr::BinaryConditionalOperatorClass:
- return EmitConditionalOperatorLValue(cast<BinaryConditionalOperator>(E));
- case Expr::ChooseExprClass:
- return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr());
- case Expr::OpaqueValueExprClass:
- return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
- case Expr::SubstNonTypeTemplateParmExprClass:
- return EmitLValue(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
- case Expr::ImplicitCastExprClass:
- case Expr::CStyleCastExprClass:
- case Expr::CXXFunctionalCastExprClass:
- case Expr::CXXStaticCastExprClass:
- case Expr::CXXDynamicCastExprClass:
- case Expr::CXXReinterpretCastExprClass:
- case Expr::CXXConstCastExprClass:
- case Expr::ObjCBridgedCastExprClass:
- return EmitCastLValue(cast<CastExpr>(E));
-
- case Expr::MaterializeTemporaryExprClass:
- return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
-
- case Expr::CoawaitExprClass:
- return EmitCoawaitLValue(cast<CoawaitExpr>(E));
- case Expr::CoyieldExprClass:
- return EmitCoyieldLValue(cast<CoyieldExpr>(E));
- }
-}
-
-/// Given an object of the given canonical type, can we safely copy a
-/// value out of it based on its initializer?
-static bool isConstantEmittableObjectType(QualType type) {
- assert(type.isCanonical());
- assert(!type->isReferenceType());
-
- // Must be const-qualified but non-volatile.
- Qualifiers qs = type.getLocalQualifiers();
- if (!qs.hasConst() || qs.hasVolatile()) return false;
-
- // Otherwise, all object types satisfy this except C++ classes with
- // mutable subobjects or non-trivial copy/destroy behavior.
- if (const auto *RT = dyn_cast<RecordType>(type))
- if (const auto *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- if (RD->hasMutableFields() || !RD->isTrivial())
- return false;
-
- return true;
-}
-
-/// Can we constant-emit a load of a reference to a variable of the
-/// given type? This is different from predicates like
-/// Decl::isUsableInConstantExpressions because we do want it to apply
-/// in situations that don't necessarily satisfy the language's rules
-/// for this (e.g. C++'s ODR-use rules). For example, we want to able
-/// to do this with const float variables even if those variables
-/// aren't marked 'constexpr'.
-enum ConstantEmissionKind {
- CEK_None,
- CEK_AsReferenceOnly,
- CEK_AsValueOrReference,
- CEK_AsValueOnly
-};
-static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) {
- type = type.getCanonicalType();
- if (const auto *ref = dyn_cast<ReferenceType>(type)) {
- if (isConstantEmittableObjectType(ref->getPointeeType()))
- return CEK_AsValueOrReference;
- return CEK_AsReferenceOnly;
- }
- if (isConstantEmittableObjectType(type))
- return CEK_AsValueOnly;
- return CEK_None;
-}
-
-/// Try to emit a reference to the given value without producing it as
-/// an l-value. This is actually more than an optimization: we can't
-/// produce an l-value for variables that we never actually captured
-/// in a block or lambda, which means const int variables or constexpr
-/// literals or similar.
-CodeGenFunction::ConstantEmission
-CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
- ValueDecl *value = refExpr->getDecl();
-
- // The value needs to be an enum constant or a constant variable.
- ConstantEmissionKind CEK;
- if (isa<ParmVarDecl>(value)) {
- CEK = CEK_None;
- } else if (auto *var = dyn_cast<VarDecl>(value)) {
- CEK = checkVarTypeForConstantEmission(var->getType());
- } else if (isa<EnumConstantDecl>(value)) {
- CEK = CEK_AsValueOnly;
- } else {
- CEK = CEK_None;
- }
- if (CEK == CEK_None) return ConstantEmission();
-
- Expr::EvalResult result;
- bool resultIsReference;
- QualType resultType;
-
- // It's best to evaluate all the way as an r-value if that's permitted.
- if (CEK != CEK_AsReferenceOnly &&
- refExpr->EvaluateAsRValue(result, getContext())) {
- resultIsReference = false;
- resultType = refExpr->getType();
-
- // Otherwise, try to evaluate as an l-value.
- } else if (CEK != CEK_AsValueOnly &&
- refExpr->EvaluateAsLValue(result, getContext())) {
- resultIsReference = true;
- resultType = value->getType();
-
- // Failure.
- } else {
- return ConstantEmission();
- }
-
- // In any case, if the initializer has side-effects, abandon ship.
- if (result.HasSideEffects)
- return ConstantEmission();
-
- // Emit as a constant.
- auto C = ConstantEmitter(*this).emitAbstract(refExpr->getLocation(),
- result.Val, resultType);
-
- // Make sure we emit a debug reference to the global variable.
- // This should probably fire even for
- if (isa<VarDecl>(value)) {
- if (!getContext().DeclMustBeEmitted(cast<VarDecl>(value)))
- EmitDeclRefExprDbgValue(refExpr, result.Val);
- } else {
- assert(isa<EnumConstantDecl>(value));
- EmitDeclRefExprDbgValue(refExpr, result.Val);
- }
-
- // If we emitted a reference constant, we need to dereference that.
- if (resultIsReference)
- return ConstantEmission::forReference(C);
-
- return ConstantEmission::forValue(C);
-}
-
-static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
- const MemberExpr *ME) {
- if (auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
- // Try to emit static variable member expressions as DREs.
- return DeclRefExpr::Create(
- CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
- /*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
- ME->getType(), ME->getValueKind());
- }
- return nullptr;
-}
-
-CodeGenFunction::ConstantEmission
-CodeGenFunction::tryEmitAsConstant(const MemberExpr *ME) {
- if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, ME))
- return tryEmitAsConstant(DRE);
- return ConstantEmission();
-}
-
-llvm::Value *CodeGenFunction::emitScalarConstant(
- const CodeGenFunction::ConstantEmission &Constant, Expr *E) {
- assert(Constant && "not a constant");
- if (Constant.isReference())
- return EmitLoadOfLValue(Constant.getReferenceLValue(*this, E),
- E->getExprLoc())
- .getScalarVal();
- return Constant.getValue();
-}
-
-llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue,
- SourceLocation Loc) {
- return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getType(), Loc, lvalue.getBaseInfo(),
- lvalue.getTBAAInfo(), lvalue.isNontemporal());
-}
-
-static bool hasBooleanRepresentation(QualType Ty) {
- if (Ty->isBooleanType())
- return true;
-
- if (const EnumType *ET = Ty->getAs<EnumType>())
- return ET->getDecl()->getIntegerType()->isBooleanType();
-
- if (const AtomicType *AT = Ty->getAs<AtomicType>())
- return hasBooleanRepresentation(AT->getValueType());
-
- return false;
-}
-
-static bool getRangeForType(CodeGenFunction &CGF, QualType Ty,
- llvm::APInt &Min, llvm::APInt &End,
- bool StrictEnums, bool IsBool) {
- const EnumType *ET = Ty->getAs<EnumType>();
- bool IsRegularCPlusPlusEnum = CGF.getLangOpts().CPlusPlus && StrictEnums &&
- ET && !ET->getDecl()->isFixed();
- if (!IsBool && !IsRegularCPlusPlusEnum)
- return false;
-
- if (IsBool) {
- Min = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
- End = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
- } else {
- const EnumDecl *ED = ET->getDecl();
- llvm::Type *LTy = CGF.ConvertTypeForMem(ED->getIntegerType());
- unsigned Bitwidth = LTy->getScalarSizeInBits();
- unsigned NumNegativeBits = ED->getNumNegativeBits();
- unsigned NumPositiveBits = ED->getNumPositiveBits();
-
- if (NumNegativeBits) {
- unsigned NumBits = std::max(NumNegativeBits, NumPositiveBits + 1);
- assert(NumBits <= Bitwidth);
- End = llvm::APInt(Bitwidth, 1) << (NumBits - 1);
- Min = -End;
- } else {
- assert(NumPositiveBits <= Bitwidth);
- End = llvm::APInt(Bitwidth, 1) << NumPositiveBits;
- Min = llvm::APInt(Bitwidth, 0);
- }
- }
- return true;
-}
-
-llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
- llvm::APInt Min, End;
- if (!getRangeForType(*this, Ty, Min, End, CGM.getCodeGenOpts().StrictEnums,
- hasBooleanRepresentation(Ty)))
- return nullptr;
-
- llvm::MDBuilder MDHelper(getLLVMContext());
- return MDHelper.createRange(Min, End);
-}
-
-bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
- SourceLocation Loc) {
- bool HasBoolCheck = SanOpts.has(SanitizerKind::Bool);
- bool HasEnumCheck = SanOpts.has(SanitizerKind::Enum);
- if (!HasBoolCheck && !HasEnumCheck)
- return false;
-
- bool IsBool = hasBooleanRepresentation(Ty) ||
- NSAPI(CGM.getContext()).isObjCBOOLType(Ty);
- bool NeedsBoolCheck = HasBoolCheck && IsBool;
- bool NeedsEnumCheck = HasEnumCheck && Ty->getAs<EnumType>();
- if (!NeedsBoolCheck && !NeedsEnumCheck)
- return false;
-
- // Single-bit booleans don't need to be checked. Special-case this to avoid
- // a bit width mismatch when handling bitfield values. This is handled by
- // EmitFromMemory for the non-bitfield case.
- if (IsBool &&
- cast<llvm::IntegerType>(Value->getType())->getBitWidth() == 1)
- return false;
-
- llvm::APInt Min, End;
- if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool))
- return true;
-
- auto &Ctx = getLLVMContext();
- SanitizerScope SanScope(this);
- llvm::Value *Check;
- --End;
- if (!Min) {
- Check = Builder.CreateICmpULE(Value, llvm::ConstantInt::get(Ctx, End));
- } else {
- llvm::Value *Upper =
- Builder.CreateICmpSLE(Value, llvm::ConstantInt::get(Ctx, End));
- llvm::Value *Lower =
- Builder.CreateICmpSGE(Value, llvm::ConstantInt::get(Ctx, Min));
- Check = Builder.CreateAnd(Upper, Lower);
- }
- llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc),
- EmitCheckTypeDescriptor(Ty)};
- SanitizerMask Kind =
- NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool;
- EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue,
- StaticArgs, EmitCheckValue(Value));
- return true;
-}
-
-llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
- QualType Ty,
- SourceLocation Loc,
- LValueBaseInfo BaseInfo,
- TBAAAccessInfo TBAAInfo,
- bool isNontemporal) {
- if (!CGM.getCodeGenOpts().PreserveVec3Type) {
- // For better performance, handle vector loads differently.
- if (Ty->isVectorType()) {
- const llvm::Type *EltTy = Addr.getElementType();
-
- const auto *VTy = cast<llvm::VectorType>(EltTy);
-
- // Handle vectors of size 3 like size 4 for better performance.
- if (VTy->getNumElements() == 3) {
-
- // Bitcast to vec4 type.
- llvm::VectorType *vec4Ty =
- llvm::VectorType::get(VTy->getElementType(), 4);
- Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4");
- // Now load value.
- llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4");
-
- // Shuffle vector to get vec3.
- V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
- {0, 1, 2}, "extractVec");
- return EmitFromMemory(V, Ty);
- }
- }
- }
-
- // Atomic operations have to be done on integral types.
- LValue AtomicLValue =
- LValue::MakeAddr(Addr, Ty, getContext(), BaseInfo, TBAAInfo);
- if (Ty->isAtomicType() || LValueIsSuitableForInlineAtomic(AtomicLValue)) {
- return EmitAtomicLoad(AtomicLValue, Loc).getScalarVal();
- }
-
- llvm::LoadInst *Load = Builder.CreateLoad(Addr, Volatile);
- if (isNontemporal) {
- llvm::MDNode *Node = llvm::MDNode::get(
- Load->getContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
- Load->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
- }
-
- CGM.DecorateInstructionWithTBAA(Load, TBAAInfo);
-
- if (EmitScalarRangeCheck(Load, Ty, Loc)) {
- // In order to prevent the optimizer from throwing away the check, don't
- // attach range metadata to the load.
- } else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
- if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
- Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
-
- return EmitFromMemory(Load, Ty);
-}
-
-llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
- // Bool has a different representation in memory than in registers.
- if (hasBooleanRepresentation(Ty)) {
- // This should really always be an i1, but sometimes it's already
- // an i8, and it's awkward to track those cases down.
- if (Value->getType()->isIntegerTy(1))
- return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "frombool");
- assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
- "wrong value rep of bool");
- }
-
- return Value;
-}
-
-llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
- // Bool has a different representation in memory than in registers.
- if (hasBooleanRepresentation(Ty)) {
- assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
- "wrong value rep of bool");
- return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool");
- }
-
- return Value;
-}
-
-void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
- bool Volatile, QualType Ty,
- LValueBaseInfo BaseInfo,
- TBAAAccessInfo TBAAInfo,
- bool isInit, bool isNontemporal) {
- if (!CGM.getCodeGenOpts().PreserveVec3Type) {
- // Handle vectors differently to get better performance.
- if (Ty->isVectorType()) {
- llvm::Type *SrcTy = Value->getType();
- auto *VecTy = dyn_cast<llvm::VectorType>(SrcTy);
- // Handle vec3 special.
- if (VecTy && VecTy->getNumElements() == 3) {
- // Our source is a vec3, do a shuffle vector to make it a vec4.
- llvm::Constant *Mask[] = {Builder.getInt32(0), Builder.getInt32(1),
- Builder.getInt32(2),
- llvm::UndefValue::get(Builder.getInt32Ty())};
- llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
- Value = Builder.CreateShuffleVector(Value, llvm::UndefValue::get(VecTy),
- MaskV, "extractVec");
- SrcTy = llvm::VectorType::get(VecTy->getElementType(), 4);
- }
- if (Addr.getElementType() != SrcTy) {
- Addr = Builder.CreateElementBitCast(Addr, SrcTy, "storetmp");
- }
- }
- }
-
- Value = EmitToMemory(Value, Ty);
-
- LValue AtomicLValue =
- LValue::MakeAddr(Addr, Ty, getContext(), BaseInfo, TBAAInfo);
- if (Ty->isAtomicType() ||
- (!isInit && LValueIsSuitableForInlineAtomic(AtomicLValue))) {
- EmitAtomicStore(RValue::get(Value), AtomicLValue, isInit);
- return;
- }
-
- llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
- if (isNontemporal) {
- llvm::MDNode *Node =
- llvm::MDNode::get(Store->getContext(),
- llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
- Store->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
- }
-
- CGM.DecorateInstructionWithTBAA(Store, TBAAInfo);
-}
-
-void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
- bool isInit) {
- EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getType(), lvalue.getBaseInfo(),
- lvalue.getTBAAInfo(), isInit, lvalue.isNontemporal());
-}
-
-/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
-/// method emits the address of the lvalue, then loads the result as an rvalue,
-/// returning the rvalue.
-RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
- if (LV.isObjCWeak()) {
- // load of a __weak object.
- Address AddrWeakObj = LV.getAddress();
- return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this,
- AddrWeakObj));
- }
- if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
- // In MRC mode, we do a load+autorelease.
- if (!getLangOpts().ObjCAutoRefCount) {
- return RValue::get(EmitARCLoadWeak(LV.getAddress()));
- }
-
- // In ARC mode, we load retained and then consume the value.
- llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress());
- Object = EmitObjCConsumeObject(LV.getType(), Object);
- return RValue::get(Object);
- }
-
- if (LV.isSimple()) {
- assert(!LV.getType()->isFunctionType());
-
- // Everything needs a load.
- return RValue::get(EmitLoadOfScalar(LV, Loc));
- }
-
- if (LV.isVectorElt()) {
- llvm::LoadInst *Load = Builder.CreateLoad(LV.getVectorAddress(),
- LV.isVolatileQualified());
- return RValue::get(Builder.CreateExtractElement(Load, LV.getVectorIdx(),
- "vecext"));
- }
-
- // If this is a reference to a subset of the elements of a vector, either
- // shuffle the input or extract/insert them as appropriate.
- if (LV.isExtVectorElt())
- return EmitLoadOfExtVectorElementLValue(LV);
-
- // Global Register variables always invoke intrinsics
- if (LV.isGlobalReg())
- return EmitLoadOfGlobalRegLValue(LV);
-
- assert(LV.isBitField() && "Unknown LValue type!");
- return EmitLoadOfBitfieldLValue(LV, Loc);
-}
-
-RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
- SourceLocation Loc) {
- const CGBitFieldInfo &Info = LV.getBitFieldInfo();
-
- // Get the output type.
- llvm::Type *ResLTy = ConvertType(LV.getType());
-
- Address Ptr = LV.getBitFieldAddress();
- llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "bf.load");
-
- if (Info.IsSigned) {
- assert(static_cast<unsigned>(Info.Offset + Info.Size) <= Info.StorageSize);
- unsigned HighBits = Info.StorageSize - Info.Offset - Info.Size;
- if (HighBits)
- Val = Builder.CreateShl(Val, HighBits, "bf.shl");
- if (Info.Offset + HighBits)
- Val = Builder.CreateAShr(Val, Info.Offset + HighBits, "bf.ashr");
- } else {
- if (Info.Offset)
- Val = Builder.CreateLShr(Val, Info.Offset, "bf.lshr");
- if (static_cast<unsigned>(Info.Offset) + Info.Size < Info.StorageSize)
- Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(Info.StorageSize,
- Info.Size),
- "bf.clear");
- }
- Val = Builder.CreateIntCast(Val, ResLTy, Info.IsSigned, "bf.cast");
- EmitScalarRangeCheck(Val, LV.getType(), Loc);
- return RValue::get(Val);
-}
-
-// If this is a reference to a subset of the elements of a vector, create an
-// appropriate shufflevector.
-RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
- llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddress(),
- LV.isVolatileQualified());
-
- const llvm::Constant *Elts = LV.getExtVectorElts();
-
- // If the result of the expression is a non-vector type, we must be extracting
- // a single element. Just codegen as an extractelement.
- const VectorType *ExprVT = LV.getType()->getAs<VectorType>();
- if (!ExprVT) {
- unsigned InIdx = getAccessedFieldNo(0, Elts);
- llvm::Value *Elt = llvm::ConstantInt::get(SizeTy, InIdx);
- return RValue::get(Builder.CreateExtractElement(Vec, Elt));
- }
-
- // Always use shuffle vector to try to retain the original program structure
- unsigned NumResultElts = ExprVT->getNumElements();
-
- SmallVector<llvm::Constant*, 4> Mask;
- for (unsigned i = 0; i != NumResultElts; ++i)
- Mask.push_back(Builder.getInt32(getAccessedFieldNo(i, Elts)));
-
- llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
- Vec = Builder.CreateShuffleVector(Vec, llvm::UndefValue::get(Vec->getType()),
- MaskV);
- return RValue::get(Vec);
-}
-
-/// Generates lvalue for partial ext_vector access.
-Address CodeGenFunction::EmitExtVectorElementLValue(LValue LV) {
- Address VectorAddress = LV.getExtVectorAddress();
- const VectorType *ExprVT = LV.getType()->getAs<VectorType>();
- QualType EQT = ExprVT->getElementType();
- llvm::Type *VectorElementTy = CGM.getTypes().ConvertType(EQT);
-
- Address CastToPointerElement =
- Builder.CreateElementBitCast(VectorAddress, VectorElementTy,
- "conv.ptr.element");
-
- const llvm::Constant *Elts = LV.getExtVectorElts();
- unsigned ix = getAccessedFieldNo(0, Elts);
-
- Address VectorBasePtrPlusIx =
- Builder.CreateConstInBoundsGEP(CastToPointerElement, ix,
- getContext().getTypeSizeInChars(EQT),
- "vector.elt");
-
- return VectorBasePtrPlusIx;
-}
-
-/// Load of global gamed gegisters are always calls to intrinsics.
-RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) {
- assert((LV.getType()->isIntegerType() || LV.getType()->isPointerType()) &&
- "Bad type for register variable");
- llvm::MDNode *RegName = cast<llvm::MDNode>(
- cast<llvm::MetadataAsValue>(LV.getGlobalReg())->getMetadata());
-
- // We accept integer and pointer types only
- llvm::Type *OrigTy = CGM.getTypes().ConvertType(LV.getType());
- llvm::Type *Ty = OrigTy;
- if (OrigTy->isPointerTy())
- Ty = CGM.getTypes().getDataLayout().getIntPtrType(OrigTy);
- llvm::Type *Types[] = { Ty };
-
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
- llvm::Value *Call = Builder.CreateCall(
- F, llvm::MetadataAsValue::get(Ty->getContext(), RegName));
- if (OrigTy->isPointerTy())
- Call = Builder.CreateIntToPtr(Call, OrigTy);
- return RValue::get(Call);
-}
-
-
-/// EmitStoreThroughLValue - Store the specified rvalue into the specified
-/// lvalue, where both are guaranteed to the have the same type, and that type
-/// is 'Ty'.
-void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
- bool isInit) {
- if (!Dst.isSimple()) {
- if (Dst.isVectorElt()) {
- // Read/modify/write the vector, inserting the new element.
- llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddress(),
- Dst.isVolatileQualified());
- Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
- Dst.getVectorIdx(), "vecins");
- Builder.CreateStore(Vec, Dst.getVectorAddress(),
- Dst.isVolatileQualified());
- return;
- }
-
- // If this is an update of extended vector elements, insert them as
- // appropriate.
- if (Dst.isExtVectorElt())
- return EmitStoreThroughExtVectorComponentLValue(Src, Dst);
-
- if (Dst.isGlobalReg())
- return EmitStoreThroughGlobalRegLValue(Src, Dst);
-
- assert(Dst.isBitField() && "Unknown LValue type");
- return EmitStoreThroughBitfieldLValue(Src, Dst);
- }
-
- // There's special magic for assigning into an ARC-qualified l-value.
- if (Qualifiers::ObjCLifetime Lifetime = Dst.getQuals().getObjCLifetime()) {
- switch (Lifetime) {
- case Qualifiers::OCL_None:
- llvm_unreachable("present but none");
-
- case Qualifiers::OCL_ExplicitNone:
- // nothing special
- break;
-
- case Qualifiers::OCL_Strong:
- if (isInit) {
- Src = RValue::get(EmitARCRetain(Dst.getType(), Src.getScalarVal()));
- break;
- }
- EmitARCStoreStrong(Dst, Src.getScalarVal(), /*ignore*/ true);
- return;
-
- case Qualifiers::OCL_Weak:
- if (isInit)
- // Initialize and then skip the primitive store.
- EmitARCInitWeak(Dst.getAddress(), Src.getScalarVal());
- else
- EmitARCStoreWeak(Dst.getAddress(), Src.getScalarVal(), /*ignore*/ true);
- return;
-
- case Qualifiers::OCL_Autoreleasing:
- Src = RValue::get(EmitObjCExtendObjectLifetime(Dst.getType(),
- Src.getScalarVal()));
- // fall into the normal path
- break;
- }
- }
-
- if (Dst.isObjCWeak() && !Dst.isNonGC()) {
- // load of a __weak object.
- Address LvalueDst = Dst.getAddress();
- llvm::Value *src = Src.getScalarVal();
- CGM.getObjCRuntime().EmitObjCWeakAssign(*this, src, LvalueDst);
- return;
- }
-
- if (Dst.isObjCStrong() && !Dst.isNonGC()) {
- // load of a __strong object.
- Address LvalueDst = Dst.getAddress();
- llvm::Value *src = Src.getScalarVal();
- if (Dst.isObjCIvar()) {
- assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL");
- llvm::Type *ResultType = IntPtrTy;
- Address dst = EmitPointerWithAlignment(Dst.getBaseIvarExp());
- llvm::Value *RHS = dst.getPointer();
- RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
- llvm::Value *LHS =
- Builder.CreatePtrToInt(LvalueDst.getPointer(), ResultType,
- "sub.ptr.lhs.cast");
- llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset");
- CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst,
- BytesBetween);
- } else if (Dst.isGlobalObjCRef()) {
- CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst,
- Dst.isThreadLocalRef());
- }
- else
- CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst);
- return;
- }
-
- assert(Src.isScalar() && "Can't emit an agg store with this method");
- EmitStoreOfScalar(Src.getScalarVal(), Dst, isInit);
-}
-
-void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
- llvm::Value **Result) {
- const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
- llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
- Address Ptr = Dst.getBitFieldAddress();
-
- // Get the source value, truncated to the width of the bit-field.
- llvm::Value *SrcVal = Src.getScalarVal();
-
- // Cast the source to the storage type and shift it into place.
- SrcVal = Builder.CreateIntCast(SrcVal, Ptr.getElementType(),
- /*IsSigned=*/false);
- llvm::Value *MaskedVal = SrcVal;
-
- // See if there are other bits in the bitfield's storage we'll need to load
- // and mask together with source before storing.
- if (Info.StorageSize != Info.Size) {
- assert(Info.StorageSize > Info.Size && "Invalid bitfield size.");
- llvm::Value *Val =
- Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), "bf.load");
-
- // Mask the source value as needed.
- if (!hasBooleanRepresentation(Dst.getType()))
- SrcVal = Builder.CreateAnd(SrcVal,
- llvm::APInt::getLowBitsSet(Info.StorageSize,
- Info.Size),
- "bf.value");
- MaskedVal = SrcVal;
- if (Info.Offset)
- SrcVal = Builder.CreateShl(SrcVal, Info.Offset, "bf.shl");
-
- // Mask out the original value.
- Val = Builder.CreateAnd(Val,
- ~llvm::APInt::getBitsSet(Info.StorageSize,
- Info.Offset,
- Info.Offset + Info.Size),
- "bf.clear");
-
- // Or together the unchanged values and the source value.
- SrcVal = Builder.CreateOr(Val, SrcVal, "bf.set");
- } else {
- assert(Info.Offset == 0);
- }
-
- // Write the new value back out.
- Builder.CreateStore(SrcVal, Ptr, Dst.isVolatileQualified());
-
- // Return the new value of the bit-field, if requested.
- if (Result) {
- llvm::Value *ResultVal = MaskedVal;
-
- // Sign extend the value if needed.
- if (Info.IsSigned) {
- assert(Info.Size <= Info.StorageSize);
- unsigned HighBits = Info.StorageSize - Info.Size;
- if (HighBits) {
- ResultVal = Builder.CreateShl(ResultVal, HighBits, "bf.result.shl");
- ResultVal = Builder.CreateAShr(ResultVal, HighBits, "bf.result.ashr");
- }
- }
-
- ResultVal = Builder.CreateIntCast(ResultVal, ResLTy, Info.IsSigned,
- "bf.result.cast");
- *Result = EmitFromMemory(ResultVal, Dst.getType());
- }
-}
-
-void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
- LValue Dst) {
- // This access turns into a read/modify/write of the vector. Load the input
- // value now.
- llvm::Value *Vec = Builder.CreateLoad(Dst.getExtVectorAddress(),
- Dst.isVolatileQualified());
- const llvm::Constant *Elts = Dst.getExtVectorElts();
-
- llvm::Value *SrcVal = Src.getScalarVal();
-
- if (const VectorType *VTy = Dst.getType()->getAs<VectorType>()) {
- unsigned NumSrcElts = VTy->getNumElements();
- unsigned NumDstElts = Vec->getType()->getVectorNumElements();
- if (NumDstElts == NumSrcElts) {
- // Use shuffle vector is the src and destination are the same number of
- // elements and restore the vector mask since it is on the side it will be
- // stored.
- SmallVector<llvm::Constant*, 4> Mask(NumDstElts);
- for (unsigned i = 0; i != NumSrcElts; ++i)
- Mask[getAccessedFieldNo(i, Elts)] = Builder.getInt32(i);
-
- llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
- Vec = Builder.CreateShuffleVector(SrcVal,
- llvm::UndefValue::get(Vec->getType()),
- MaskV);
- } else if (NumDstElts > NumSrcElts) {
- // Extended the source vector to the same length and then shuffle it
- // into the destination.
- // FIXME: since we're shuffling with undef, can we just use the indices
- // into that? This could be simpler.
- SmallVector<llvm::Constant*, 4> ExtMask;
- for (unsigned i = 0; i != NumSrcElts; ++i)
- ExtMask.push_back(Builder.getInt32(i));
- ExtMask.resize(NumDstElts, llvm::UndefValue::get(Int32Ty));
- llvm::Value *ExtMaskV = llvm::ConstantVector::get(ExtMask);
- llvm::Value *ExtSrcVal =
- Builder.CreateShuffleVector(SrcVal,
- llvm::UndefValue::get(SrcVal->getType()),
- ExtMaskV);
- // build identity
- SmallVector<llvm::Constant*, 4> Mask;
- for (unsigned i = 0; i != NumDstElts; ++i)
- Mask.push_back(Builder.getInt32(i));
-
- // When the vector size is odd and .odd or .hi is used, the last element
- // of the Elts constant array will be one past the size of the vector.
- // Ignore the last element here, if it is greater than the mask size.
- if (getAccessedFieldNo(NumSrcElts - 1, Elts) == Mask.size())
- NumSrcElts--;
-
- // modify when what gets shuffled in
- for (unsigned i = 0; i != NumSrcElts; ++i)
- Mask[getAccessedFieldNo(i, Elts)] = Builder.getInt32(i+NumDstElts);
- llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
- Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV);
- } else {
- // We should never shorten the vector
- llvm_unreachable("unexpected shorten vector length");
- }
- } else {
- // If the Src is a scalar (not a vector) it must be updating one element.
- unsigned InIdx = getAccessedFieldNo(0, Elts);
- llvm::Value *Elt = llvm::ConstantInt::get(SizeTy, InIdx);
- Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt);
- }
-
- Builder.CreateStore(Vec, Dst.getExtVectorAddress(),
- Dst.isVolatileQualified());
-}
-
-/// Store of global named registers are always calls to intrinsics.
-void CodeGenFunction::EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst) {
- assert((Dst.getType()->isIntegerType() || Dst.getType()->isPointerType()) &&
- "Bad type for register variable");
- llvm::MDNode *RegName = cast<llvm::MDNode>(
- cast<llvm::MetadataAsValue>(Dst.getGlobalReg())->getMetadata());
- assert(RegName && "Register LValue is not metadata");
-
- // We accept integer and pointer types only
- llvm::Type *OrigTy = CGM.getTypes().ConvertType(Dst.getType());
- llvm::Type *Ty = OrigTy;
- if (OrigTy->isPointerTy())
- Ty = CGM.getTypes().getDataLayout().getIntPtrType(OrigTy);
- llvm::Type *Types[] = { Ty };
-
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
- llvm::Value *Value = Src.getScalarVal();
- if (OrigTy->isPointerTy())
- Value = Builder.CreatePtrToInt(Value, Ty);
- Builder.CreateCall(
- F, {llvm::MetadataAsValue::get(Ty->getContext(), RegName), Value});
-}
-
-// setObjCGCLValueClass - sets class of the lvalue for the purpose of
-// generating write-barries API. It is currently a global, ivar,
-// or neither.
-static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
- LValue &LV,
- bool IsMemberAccess=false) {
- if (Ctx.getLangOpts().getGC() == LangOptions::NonGC)
- return;
-
- if (isa<ObjCIvarRefExpr>(E)) {
- QualType ExpTy = E->getType();
- if (IsMemberAccess && ExpTy->isPointerType()) {
- // If ivar is a structure pointer, assigning to field of
- // this struct follows gcc's behavior and makes it a non-ivar
- // writer-barrier conservatively.
- ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
- if (ExpTy->isRecordType()) {
- LV.setObjCIvar(false);
- return;
- }
- }
- LV.setObjCIvar(true);
- auto *Exp = cast<ObjCIvarRefExpr>(const_cast<Expr *>(E));
- LV.setBaseIvarExp(Exp->getBase());
- LV.setObjCArray(E->getType()->isArrayType());
- return;
- }
-
- if (const auto *Exp = dyn_cast<DeclRefExpr>(E)) {
- if (const auto *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
- if (VD->hasGlobalStorage()) {
- LV.setGlobalObjCRef(true);
- LV.setThreadLocalRef(VD->getTLSKind() != VarDecl::TLS_None);
- }
- }
- LV.setObjCArray(E->getType()->isArrayType());
- return;
- }
-
- if (const auto *Exp = dyn_cast<UnaryOperator>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
- return;
- }
-
- if (const auto *Exp = dyn_cast<ParenExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
- if (LV.isObjCIvar()) {
- // If cast is to a structure pointer, follow gcc's behavior and make it
- // a non-ivar write-barrier.
- QualType ExpTy = E->getType();
- if (ExpTy->isPointerType())
- ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
- if (ExpTy->isRecordType())
- LV.setObjCIvar(false);
- }
- return;
- }
-
- if (const auto *Exp = dyn_cast<GenericSelectionExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getResultExpr(), LV);
- return;
- }
-
- if (const auto *Exp = dyn_cast<ImplicitCastExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
- return;
- }
-
- if (const auto *Exp = dyn_cast<CStyleCastExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
- return;
- }
-
- if (const auto *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
- return;
- }
-
- if (const auto *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
- if (LV.isObjCIvar() && !LV.isObjCArray())
- // Using array syntax to assigning to what an ivar points to is not
- // same as assigning to the ivar itself. {id *Names;} Names[i] = 0;
- LV.setObjCIvar(false);
- else if (LV.isGlobalObjCRef() && !LV.isObjCArray())
- // Using array syntax to assigning to what global points to is not
- // same as assigning to the global itself. {id *G;} G[i] = 0;
- LV.setGlobalObjCRef(false);
- return;
- }
-
- if (const auto *Exp = dyn_cast<MemberExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getBase(), LV, true);
- // We don't know if member is an 'ivar', but this flag is looked at
- // only in the context of LV.isObjCIvar().
- LV.setObjCArray(E->getType()->isArrayType());
- return;
- }
-}
-
-static llvm::Value *
-EmitBitCastOfLValueToProperType(CodeGenFunction &CGF,
- llvm::Value *V, llvm::Type *IRType,
- StringRef Name = StringRef()) {
- unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
- return CGF.Builder.CreateBitCast(V, IRType->getPointerTo(AS), Name);
-}
-
-static LValue EmitThreadPrivateVarDeclLValue(
- CodeGenFunction &CGF, const VarDecl *VD, QualType T, Address Addr,
- llvm::Type *RealVarTy, SourceLocation Loc) {
- Addr = CGF.CGM.getOpenMPRuntime().getAddrOfThreadPrivate(CGF, VD, Addr, Loc);
- Addr = CGF.Builder.CreateElementBitCast(Addr, RealVarTy);
- return CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
-}
-
-static Address emitDeclTargetLinkVarDeclLValue(CodeGenFunction &CGF,
- const VarDecl *VD, QualType T) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_To)
- return Address::invalid();
- assert(*Res == OMPDeclareTargetDeclAttr::MT_Link && "Expected link clause");
- QualType PtrTy = CGF.getContext().getPointerType(VD->getType());
- Address Addr = CGF.CGM.getOpenMPRuntime().getAddrOfDeclareTargetLink(VD);
- return CGF.EmitLoadOfPointer(Addr, PtrTy->castAs<PointerType>());
-}
-
-Address
-CodeGenFunction::EmitLoadOfReference(LValue RefLVal,
- LValueBaseInfo *PointeeBaseInfo,
- TBAAAccessInfo *PointeeTBAAInfo) {
- llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(),
- RefLVal.isVolatile());
- CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo());
-
- CharUnits Align = getNaturalTypeAlignment(RefLVal.getType()->getPointeeType(),
- PointeeBaseInfo, PointeeTBAAInfo,
- /* forPointeeType= */ true);
- return Address(Load, Align);
-}
-
-LValue CodeGenFunction::EmitLoadOfReferenceLValue(LValue RefLVal) {
- LValueBaseInfo PointeeBaseInfo;
- TBAAAccessInfo PointeeTBAAInfo;
- Address PointeeAddr = EmitLoadOfReference(RefLVal, &PointeeBaseInfo,
- &PointeeTBAAInfo);
- return MakeAddrLValue(PointeeAddr, RefLVal.getType()->getPointeeType(),
- PointeeBaseInfo, PointeeTBAAInfo);
-}
-
-Address CodeGenFunction::EmitLoadOfPointer(Address Ptr,
- const PointerType *PtrTy,
- LValueBaseInfo *BaseInfo,
- TBAAAccessInfo *TBAAInfo) {
- llvm::Value *Addr = Builder.CreateLoad(Ptr);
- return Address(Addr, getNaturalTypeAlignment(PtrTy->getPointeeType(),
- BaseInfo, TBAAInfo,
- /*forPointeeType=*/true));
-}
-
-LValue CodeGenFunction::EmitLoadOfPointerLValue(Address PtrAddr,
- const PointerType *PtrTy) {
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- Address Addr = EmitLoadOfPointer(PtrAddr, PtrTy, &BaseInfo, &TBAAInfo);
- return MakeAddrLValue(Addr, PtrTy->getPointeeType(), BaseInfo, TBAAInfo);
-}
-
-static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
- const Expr *E, const VarDecl *VD) {
- QualType T = E->getType();
-
- // If it's thread_local, emit a call to its wrapper function instead.
- if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
- CGF.CGM.getCXXABI().usesThreadWrapperFunction())
- return CGF.CGM.getCXXABI().EmitThreadLocalVarDeclLValue(CGF, VD, T);
- // Check if the variable is marked as declare target with link clause in
- // device codegen.
- if (CGF.getLangOpts().OpenMPIsDevice) {
- Address Addr = emitDeclTargetLinkVarDeclLValue(CGF, VD, T);
- if (Addr.isValid())
- return CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
- }
-
- llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
- llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
- V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
- CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
- Address Addr(V, Alignment);
- // Emit reference to the private copy of the variable if it is an OpenMP
- // threadprivate variable.
- if (CGF.getLangOpts().OpenMP && !CGF.getLangOpts().OpenMPSimd &&
- VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
- return EmitThreadPrivateVarDeclLValue(CGF, VD, T, Addr, RealVarTy,
- E->getExprLoc());
- }
- LValue LV = VD->getType()->isReferenceType() ?
- CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
- AlignmentSource::Decl) :
- CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
- setObjCGCLValueClass(CGF.getContext(), E, LV);
- return LV;
-}
-
-static llvm::Constant *EmitFunctionDeclPointer(CodeGenModule &CGM,
- const FunctionDecl *FD) {
- if (FD->hasAttr<WeakRefAttr>()) {
- ConstantAddress aliasee = CGM.GetWeakRefReference(FD);
- return aliasee.getPointer();
- }
-
- llvm::Constant *V = CGM.GetAddrOfFunction(FD);
- if (!FD->hasPrototype()) {
- if (const FunctionProtoType *Proto =
- FD->getType()->getAs<FunctionProtoType>()) {
- // Ugly case: for a K&R-style definition, the type of the definition
- // isn't the same as the type of a use. Correct for this with a
- // bitcast.
- QualType NoProtoType =
- CGM.getContext().getFunctionNoProtoType(Proto->getReturnType());
- NoProtoType = CGM.getContext().getPointerType(NoProtoType);
- V = llvm::ConstantExpr::getBitCast(V,
- CGM.getTypes().ConvertType(NoProtoType));
- }
- }
- return V;
-}
-
-static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
- const Expr *E, const FunctionDecl *FD) {
- llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, FD);
- CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
- return CGF.MakeAddrLValue(V, E->getType(), Alignment,
- AlignmentSource::Decl);
-}
-
-static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
- llvm::Value *ThisValue) {
- QualType TagType = CGF.getContext().getTagDeclType(FD->getParent());
- LValue LV = CGF.MakeNaturalAlignAddrLValue(ThisValue, TagType);
- return CGF.EmitLValueForField(LV, FD);
-}
-
-/// Named Registers are named metadata pointing to the register name
-/// which will be read from/written to as an argument to the intrinsic
-/// @llvm.read/write_register.
-/// So far, only the name is being passed down, but other options such as
-/// register type, allocation type or even optimization options could be
-/// passed down via the metadata node.
-static LValue EmitGlobalNamedRegister(const VarDecl *VD, CodeGenModule &CGM) {
- SmallString<64> Name("llvm.named.register.");
- AsmLabelAttr *Asm = VD->getAttr<AsmLabelAttr>();
- assert(Asm->getLabel().size() < 64-Name.size() &&
- "Register name too big");
- Name.append(Asm->getLabel());
- llvm::NamedMDNode *M =
- CGM.getModule().getOrInsertNamedMetadata(Name);
- if (M->getNumOperands() == 0) {
- llvm::MDString *Str = llvm::MDString::get(CGM.getLLVMContext(),
- Asm->getLabel());
- llvm::Metadata *Ops[] = {Str};
- M->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops));
- }
-
- CharUnits Alignment = CGM.getContext().getDeclAlign(VD);
-
- llvm::Value *Ptr =
- llvm::MetadataAsValue::get(CGM.getLLVMContext(), M->getOperand(0));
- return LValue::MakeGlobalReg(Address(Ptr, Alignment), VD->getType());
-}
-
-LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
- const NamedDecl *ND = E->getDecl();
- QualType T = E->getType();
-
- if (const auto *VD = dyn_cast<VarDecl>(ND)) {
- // Global Named registers access via intrinsics only
- if (VD->getStorageClass() == SC_Register &&
- VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())
- return EmitGlobalNamedRegister(VD, CGM);
-
- // A DeclRefExpr for a reference initialized by a constant expression can
- // appear without being odr-used. Directly emit the constant initializer.
- const Expr *Init = VD->getAnyInitializer(VD);
- const auto *BD = dyn_cast_or_null<BlockDecl>(CurCodeDecl);
- if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() &&
- VD->isUsableInConstantExpressions(getContext()) &&
- VD->checkInitIsICE() &&
- // Do not emit if it is private OpenMP variable.
- !(E->refersToEnclosingVariableOrCapture() &&
- ((CapturedStmtInfo &&
- (LocalDeclMap.count(VD->getCanonicalDecl()) ||
- CapturedStmtInfo->lookup(VD->getCanonicalDecl()))) ||
- LambdaCaptureFields.lookup(VD->getCanonicalDecl()) ||
- (BD && BD->capturesVariable(VD))))) {
- llvm::Constant *Val =
- ConstantEmitter(*this).emitAbstract(E->getLocation(),
- *VD->evaluateValue(),
- VD->getType());
- assert(Val && "failed to emit reference constant expression");
- // FIXME: Eventually we will want to emit vector element references.
-
- // Should we be using the alignment of the constant pointer we emitted?
- CharUnits Alignment = getNaturalTypeAlignment(E->getType(),
- /* BaseInfo= */ nullptr,
- /* TBAAInfo= */ nullptr,
- /* forPointeeType= */ true);
- return MakeAddrLValue(Address(Val, Alignment), T, AlignmentSource::Decl);
- }
-
- // Check for captured variables.
- if (E->refersToEnclosingVariableOrCapture()) {
- VD = VD->getCanonicalDecl();
- if (auto *FD = LambdaCaptureFields.lookup(VD))
- return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
- else if (CapturedStmtInfo) {
- auto I = LocalDeclMap.find(VD);
- if (I != LocalDeclMap.end()) {
- if (VD->getType()->isReferenceType())
- return EmitLoadOfReferenceLValue(I->second, VD->getType(),
- AlignmentSource::Decl);
- return MakeAddrLValue(I->second, T);
- }
- LValue CapLVal =
- EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD),
- CapturedStmtInfo->getContextValue());
- return MakeAddrLValue(
- Address(CapLVal.getPointer(), getContext().getDeclAlign(VD)),
- CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl),
- CapLVal.getTBAAInfo());
- }
-
- assert(isa<BlockDecl>(CurCodeDecl));
- Address addr = GetAddrOfBlockDecl(VD);
- return MakeAddrLValue(addr, T, AlignmentSource::Decl);
- }
- }
-
- // FIXME: We should be able to assert this for FunctionDecls as well!
- // FIXME: We should be able to assert this for all DeclRefExprs, not just
- // those with a valid source location.
- assert((ND->isUsed(false) || !isa<VarDecl>(ND) ||
- !E->getLocation().isValid()) &&
- "Should not use decl without marking it used!");
-
- if (ND->hasAttr<WeakRefAttr>()) {
- const auto *VD = cast<ValueDecl>(ND);
- ConstantAddress Aliasee = CGM.GetWeakRefReference(VD);
- return MakeAddrLValue(Aliasee, T, AlignmentSource::Decl);
- }
-
- if (const auto *VD = dyn_cast<VarDecl>(ND)) {
- // Check if this is a global variable.
- if (VD->hasLinkage() || VD->isStaticDataMember())
- return EmitGlobalVarDeclLValue(*this, E, VD);
-
- Address addr = Address::invalid();
-
- // The variable should generally be present in the local decl map.
- auto iter = LocalDeclMap.find(VD);
- if (iter != LocalDeclMap.end()) {
- addr = iter->second;
-
- // Otherwise, it might be static local we haven't emitted yet for
- // some reason; most likely, because it's in an outer function.
- } else if (VD->isStaticLocal()) {
- addr = Address(CGM.getOrCreateStaticVarDecl(
- *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false)),
- getContext().getDeclAlign(VD));
-
- // No other cases for now.
- } else {
- llvm_unreachable("DeclRefExpr for Decl not entered in LocalDeclMap?");
- }
-
-
- // Check for OpenMP threadprivate variables.
- if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd &&
- VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
- return EmitThreadPrivateVarDeclLValue(
- *this, VD, T, addr, getTypes().ConvertTypeForMem(VD->getType()),
- E->getExprLoc());
- }
-
- // Drill into block byref variables.
- bool isBlockByref = VD->isEscapingByref();
- if (isBlockByref) {
- addr = emitBlockByrefAddress(addr, VD);
- }
-
- // Drill into reference types.
- LValue LV = VD->getType()->isReferenceType() ?
- EmitLoadOfReferenceLValue(addr, VD->getType(), AlignmentSource::Decl) :
- MakeAddrLValue(addr, T, AlignmentSource::Decl);
-
- bool isLocalStorage = VD->hasLocalStorage();
-
- bool NonGCable = isLocalStorage &&
- !VD->getType()->isReferenceType() &&
- !isBlockByref;
- if (NonGCable) {
- LV.getQuals().removeObjCGCAttr();
- LV.setNonGC(true);
- }
-
- bool isImpreciseLifetime =
- (isLocalStorage && !VD->hasAttr<ObjCPreciseLifetimeAttr>());
- if (isImpreciseLifetime)
- LV.setARCPreciseLifetime(ARCImpreciseLifetime);
- setObjCGCLValueClass(getContext(), E, LV);
- return LV;
- }
-
- if (const auto *FD = dyn_cast<FunctionDecl>(ND))
- return EmitFunctionDeclLValue(*this, E, FD);
-
- // FIXME: While we're emitting a binding from an enclosing scope, all other
- // DeclRefExprs we see should be implicitly treated as if they also refer to
- // an enclosing scope.
- if (const auto *BD = dyn_cast<BindingDecl>(ND))
- return EmitLValue(BD->getBinding());
-
- llvm_unreachable("Unhandled DeclRefExpr");
-}
-
-LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
- // __extension__ doesn't affect lvalue-ness.
- if (E->getOpcode() == UO_Extension)
- return EmitLValue(E->getSubExpr());
-
- QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType());
- switch (E->getOpcode()) {
- default: llvm_unreachable("Unknown unary operator lvalue!");
- case UO_Deref: {
- QualType T = E->getSubExpr()->getType()->getPointeeType();
- assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
-
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- Address Addr = EmitPointerWithAlignment(E->getSubExpr(), &BaseInfo,
- &TBAAInfo);
- LValue LV = MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo);
- LV.getQuals().setAddressSpace(ExprTy.getAddressSpace());
-
- // We should not generate __weak write barrier on indirect reference
- // of a pointer to object; as in void foo (__weak id *param); *param = 0;
- // But, we continue to generate __strong write barrier on indirect write
- // into a pointer to object.
- if (getLangOpts().ObjC &&
- getLangOpts().getGC() != LangOptions::NonGC &&
- LV.isObjCWeak())
- LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
- return LV;
- }
- case UO_Real:
- case UO_Imag: {
- LValue LV = EmitLValue(E->getSubExpr());
- assert(LV.isSimple() && "real/imag on non-ordinary l-value");
-
- // __real is valid on scalars. This is a faster way of testing that.
- // __imag can only produce an rvalue on scalars.
- if (E->getOpcode() == UO_Real &&
- !LV.getAddress().getElementType()->isStructTy()) {
- assert(E->getSubExpr()->getType()->isArithmeticType());
- return LV;
- }
-
- QualType T = ExprTy->castAs<ComplexType>()->getElementType();
-
- Address Component =
- (E->getOpcode() == UO_Real
- ? emitAddrOfRealComponent(LV.getAddress(), LV.getType())
- : emitAddrOfImagComponent(LV.getAddress(), LV.getType()));
- LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo(),
- CGM.getTBAAInfoForSubobject(LV, T));
- ElemLV.getQuals().addQualifiers(LV.getQuals());
- return ElemLV;
- }
- case UO_PreInc:
- case UO_PreDec: {
- LValue LV = EmitLValue(E->getSubExpr());
- bool isInc = E->getOpcode() == UO_PreInc;
-
- if (E->getType()->isAnyComplexType())
- EmitComplexPrePostIncDec(E, LV, isInc, true/*isPre*/);
- else
- EmitScalarPrePostIncDec(E, LV, isInc, true/*isPre*/);
- return LV;
- }
- }
-}
-
-LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
- return MakeAddrLValue(CGM.GetAddrOfConstantStringFromLiteral(E),
- E->getType(), AlignmentSource::Decl);
-}
-
-LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
- return MakeAddrLValue(CGM.GetAddrOfConstantStringFromObjCEncode(E),
- E->getType(), AlignmentSource::Decl);
-}
-
-LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
- auto SL = E->getFunctionName();
- assert(SL != nullptr && "No StringLiteral name in PredefinedExpr");
- StringRef FnName = CurFn->getName();
- if (FnName.startswith("\01"))
- FnName = FnName.substr(1);
- StringRef NameItems[] = {
- PredefinedExpr::getIdentKindName(E->getIdentKind()), FnName};
- std::string GVName = llvm::join(NameItems, NameItems + 2, ".");
- if (auto *BD = dyn_cast_or_null<BlockDecl>(CurCodeDecl)) {
- std::string Name = SL->getString();
- if (!Name.empty()) {
- unsigned Discriminator =
- CGM.getCXXABI().getMangleContext().getBlockId(BD, true);
- if (Discriminator)
- Name += "_" + Twine(Discriminator + 1).str();
- auto C = CGM.GetAddrOfConstantCString(Name, GVName.c_str());
- return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
- } else {
- auto C = CGM.GetAddrOfConstantCString(FnName, GVName.c_str());
- return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
- }
- }
- auto C = CGM.GetAddrOfConstantStringFromLiteral(SL, GVName);
- return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
-}
-
-/// Emit a type description suitable for use by a runtime sanitizer library. The
-/// format of a type descriptor is
-///
-/// \code
-/// { i16 TypeKind, i16 TypeInfo }
-/// \endcode
-///
-/// followed by an array of i8 containing the type name. TypeKind is 0 for an
-/// integer, 1 for a floating point value, and -1 for anything else.
-llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
- // Only emit each type's descriptor once.
- if (llvm::Constant *C = CGM.getTypeDescriptorFromMap(T))
- return C;
-
- uint16_t TypeKind = -1;
- uint16_t TypeInfo = 0;
-
- if (T->isIntegerType()) {
- TypeKind = 0;
- TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) |
- (T->isSignedIntegerType() ? 1 : 0);
- } else if (T->isFloatingType()) {
- TypeKind = 1;
- TypeInfo = getContext().getTypeSize(T);
- }
-
- // Format the type name as if for a diagnostic, including quotes and
- // optionally an 'aka'.
- SmallString<32> Buffer;
- CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
- (intptr_t)T.getAsOpaquePtr(),
- StringRef(), StringRef(), None, Buffer,
- None);
-
- llvm::Constant *Components[] = {
- Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo),
- llvm::ConstantDataArray::getString(getLLVMContext(), Buffer)
- };
- llvm::Constant *Descriptor = llvm::ConstantStruct::getAnon(Components);
-
- auto *GV = new llvm::GlobalVariable(
- CGM.getModule(), Descriptor->getType(),
- /*isConstant=*/true, llvm::GlobalVariable::PrivateLinkage, Descriptor);
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- CGM.getSanitizerMetadata()->disableSanitizerForGlobal(GV);
-
- // Remember the descriptor for this type.
- CGM.setTypeDescriptorInMap(T, GV);
-
- return GV;
-}
-
-llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
- llvm::Type *TargetTy = IntPtrTy;
-
- if (V->getType() == TargetTy)
- return V;
-
- // Floating-point types which fit into intptr_t are bitcast to integers
- // and then passed directly (after zero-extension, if necessary).
- if (V->getType()->isFloatingPointTy()) {
- unsigned Bits = V->getType()->getPrimitiveSizeInBits();
- if (Bits <= TargetTy->getIntegerBitWidth())
- V = Builder.CreateBitCast(V, llvm::Type::getIntNTy(getLLVMContext(),
- Bits));
- }
-
- // Integers which fit in intptr_t are zero-extended and passed directly.
- if (V->getType()->isIntegerTy() &&
- V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth())
- return Builder.CreateZExt(V, TargetTy);
-
- // Pointers are passed directly, everything else is passed by address.
- if (!V->getType()->isPointerTy()) {
- Address Ptr = CreateDefaultAlignTempAlloca(V->getType());
- Builder.CreateStore(V, Ptr);
- V = Ptr.getPointer();
- }
- return Builder.CreatePtrToInt(V, TargetTy);
-}
-
-/// Emit a representation of a SourceLocation for passing to a handler
-/// in a sanitizer runtime library. The format for this data is:
-/// \code
-/// struct SourceLocation {
-/// const char *Filename;
-/// int32_t Line, Column;
-/// };
-/// \endcode
-/// For an invalid SourceLocation, the Filename pointer is null.
-llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
- llvm::Constant *Filename;
- int Line, Column;
-
- PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc);
- if (PLoc.isValid()) {
- StringRef FilenameString = PLoc.getFilename();
-
- int PathComponentsToStrip =
- CGM.getCodeGenOpts().EmitCheckPathComponentsToStrip;
- if (PathComponentsToStrip < 0) {
- assert(PathComponentsToStrip != INT_MIN);
- int PathComponentsToKeep = -PathComponentsToStrip;
- auto I = llvm::sys::path::rbegin(FilenameString);
- auto E = llvm::sys::path::rend(FilenameString);
- while (I != E && --PathComponentsToKeep)
- ++I;
-
- FilenameString = FilenameString.substr(I - E);
- } else if (PathComponentsToStrip > 0) {
- auto I = llvm::sys::path::begin(FilenameString);
- auto E = llvm::sys::path::end(FilenameString);
- while (I != E && PathComponentsToStrip--)
- ++I;
-
- if (I != E)
- FilenameString =
- FilenameString.substr(I - llvm::sys::path::begin(FilenameString));
- else
- FilenameString = llvm::sys::path::filename(FilenameString);
- }
-
- auto FilenameGV = CGM.GetAddrOfConstantCString(FilenameString, ".src");
- CGM.getSanitizerMetadata()->disableSanitizerForGlobal(
- cast<llvm::GlobalVariable>(FilenameGV.getPointer()));
- Filename = FilenameGV.getPointer();
- Line = PLoc.getLine();
- Column = PLoc.getColumn();
- } else {
- Filename = llvm::Constant::getNullValue(Int8PtrTy);
- Line = Column = 0;
- }
-
- llvm::Constant *Data[] = {Filename, Builder.getInt32(Line),
- Builder.getInt32(Column)};
-
- return llvm::ConstantStruct::getAnon(Data);
-}
-
-namespace {
-/// Specify under what conditions this check can be recovered
-enum class CheckRecoverableKind {
- /// Always terminate program execution if this check fails.
- Unrecoverable,
- /// Check supports recovering, runtime has both fatal (noreturn) and
- /// non-fatal handlers for this check.
- Recoverable,
- /// Runtime conditionally aborts, always need to support recovery.
- AlwaysRecoverable
-};
-}
-
-static CheckRecoverableKind getRecoverableKind(SanitizerMask Kind) {
- assert(llvm::countPopulation(Kind) == 1);
- switch (Kind) {
- case SanitizerKind::Vptr:
- return CheckRecoverableKind::AlwaysRecoverable;
- case SanitizerKind::Return:
- case SanitizerKind::Unreachable:
- return CheckRecoverableKind::Unrecoverable;
- default:
- return CheckRecoverableKind::Recoverable;
- }
-}
-
-namespace {
-struct SanitizerHandlerInfo {
- char const *const Name;
- unsigned Version;
-};
-}
-
-const SanitizerHandlerInfo SanitizerHandlers[] = {
-#define SANITIZER_CHECK(Enum, Name, Version) {#Name, Version},
- LIST_SANITIZER_CHECKS
-#undef SANITIZER_CHECK
-};
-
-static void emitCheckHandlerCall(CodeGenFunction &CGF,
- llvm::FunctionType *FnType,
- ArrayRef<llvm::Value *> FnArgs,
- SanitizerHandler CheckHandler,
- CheckRecoverableKind RecoverKind, bool IsFatal,
- llvm::BasicBlock *ContBB) {
- assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
- Optional<ApplyDebugLocation> DL;
- if (!CGF.Builder.getCurrentDebugLocation()) {
- // Ensure that the call has at least an artificial debug location.
- DL.emplace(CGF, SourceLocation());
- }
- bool NeedsAbortSuffix =
- IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable;
- bool MinimalRuntime = CGF.CGM.getCodeGenOpts().SanitizeMinimalRuntime;
- const SanitizerHandlerInfo &CheckInfo = SanitizerHandlers[CheckHandler];
- const StringRef CheckName = CheckInfo.Name;
- std::string FnName = "__ubsan_handle_" + CheckName.str();
- if (CheckInfo.Version && !MinimalRuntime)
- FnName += "_v" + llvm::utostr(CheckInfo.Version);
- if (MinimalRuntime)
- FnName += "_minimal";
- if (NeedsAbortSuffix)
- FnName += "_abort";
- bool MayReturn =
- !IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable;
-
- llvm::AttrBuilder B;
- if (!MayReturn) {
- B.addAttribute(llvm::Attribute::NoReturn)
- .addAttribute(llvm::Attribute::NoUnwind);
- }
- B.addAttribute(llvm::Attribute::UWTable);
-
- llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(
- FnType, FnName,
- llvm::AttributeList::get(CGF.getLLVMContext(),
- llvm::AttributeList::FunctionIndex, B),
- /*Local=*/true);
- llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs);
- if (!MayReturn) {
- HandlerCall->setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
- } else {
- CGF.Builder.CreateBr(ContBB);
- }
-}
-
-void CodeGenFunction::EmitCheck(
- ArrayRef<std::pair<llvm::Value *, SanitizerMask>> Checked,
- SanitizerHandler CheckHandler, ArrayRef<llvm::Constant *> StaticArgs,
- ArrayRef<llvm::Value *> DynamicArgs) {
- assert(IsSanitizerScope);
- assert(Checked.size() > 0);
- assert(CheckHandler >= 0 &&
- size_t(CheckHandler) < llvm::array_lengthof(SanitizerHandlers));
- const StringRef CheckName = SanitizerHandlers[CheckHandler].Name;
-
- llvm::Value *FatalCond = nullptr;
- llvm::Value *RecoverableCond = nullptr;
- llvm::Value *TrapCond = nullptr;
- for (int i = 0, n = Checked.size(); i < n; ++i) {
- llvm::Value *Check = Checked[i].first;
- // -fsanitize-trap= overrides -fsanitize-recover=.
- llvm::Value *&Cond =
- CGM.getCodeGenOpts().SanitizeTrap.has(Checked[i].second)
- ? TrapCond
- : CGM.getCodeGenOpts().SanitizeRecover.has(Checked[i].second)
- ? RecoverableCond
- : FatalCond;
- Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
- }
-
- if (TrapCond)
- EmitTrapCheck(TrapCond);
- if (!FatalCond && !RecoverableCond)
- return;
-
- llvm::Value *JointCond;
- if (FatalCond && RecoverableCond)
- JointCond = Builder.CreateAnd(FatalCond, RecoverableCond);
- else
- JointCond = FatalCond ? FatalCond : RecoverableCond;
- assert(JointCond);
-
- CheckRecoverableKind RecoverKind = getRecoverableKind(Checked[0].second);
- assert(SanOpts.has(Checked[0].second));
-#ifndef NDEBUG
- for (int i = 1, n = Checked.size(); i < n; ++i) {
- assert(RecoverKind == getRecoverableKind(Checked[i].second) &&
- "All recoverable kinds in a single check must be same!");
- assert(SanOpts.has(Checked[i].second));
- }
-#endif
-
- llvm::BasicBlock *Cont = createBasicBlock("cont");
- llvm::BasicBlock *Handlers = createBasicBlock("handler." + CheckName);
- llvm::Instruction *Branch = Builder.CreateCondBr(JointCond, Cont, Handlers);
- // Give hint that we very much don't expect to execute the handler
- // Value chosen to match UR_NONTAKEN_WEIGHT, see BranchProbabilityInfo.cpp
- llvm::MDBuilder MDHelper(getLLVMContext());
- llvm::MDNode *Node = MDHelper.createBranchWeights((1U << 20) - 1, 1);
- Branch->setMetadata(llvm::LLVMContext::MD_prof, Node);
- EmitBlock(Handlers);
-
- // Handler functions take an i8* pointing to the (handler-specific) static
- // information block, followed by a sequence of intptr_t arguments
- // representing operand values.
- SmallVector<llvm::Value *, 4> Args;
- SmallVector<llvm::Type *, 4> ArgTypes;
- if (!CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
- Args.reserve(DynamicArgs.size() + 1);
- ArgTypes.reserve(DynamicArgs.size() + 1);
-
- // Emit handler arguments and create handler function type.
- if (!StaticArgs.empty()) {
- llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
- auto *InfoPtr =
- new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
- llvm::GlobalVariable::PrivateLinkage, Info);
- InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
- Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy));
- ArgTypes.push_back(Int8PtrTy);
- }
-
- for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) {
- Args.push_back(EmitCheckValue(DynamicArgs[i]));
- ArgTypes.push_back(IntPtrTy);
- }
- }
-
- llvm::FunctionType *FnType =
- llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
-
- if (!FatalCond || !RecoverableCond) {
- // Simple case: we need to generate a single handler call, either
- // fatal, or non-fatal.
- emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind,
- (FatalCond != nullptr), Cont);
- } else {
- // Emit two handler calls: first one for set of unrecoverable checks,
- // another one for recoverable.
- llvm::BasicBlock *NonFatalHandlerBB =
- createBasicBlock("non_fatal." + CheckName);
- llvm::BasicBlock *FatalHandlerBB = createBasicBlock("fatal." + CheckName);
- Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB);
- EmitBlock(FatalHandlerBB);
- emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, true,
- NonFatalHandlerBB);
- EmitBlock(NonFatalHandlerBB);
- emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, false,
- Cont);
- }
-
- EmitBlock(Cont);
-}
-
-void CodeGenFunction::EmitCfiSlowPathCheck(
- SanitizerMask Kind, llvm::Value *Cond, llvm::ConstantInt *TypeId,
- llvm::Value *Ptr, ArrayRef<llvm::Constant *> StaticArgs) {
- llvm::BasicBlock *Cont = createBasicBlock("cfi.cont");
-
- llvm::BasicBlock *CheckBB = createBasicBlock("cfi.slowpath");
- llvm::BranchInst *BI = Builder.CreateCondBr(Cond, Cont, CheckBB);
-
- llvm::MDBuilder MDHelper(getLLVMContext());
- llvm::MDNode *Node = MDHelper.createBranchWeights((1U << 20) - 1, 1);
- BI->setMetadata(llvm::LLVMContext::MD_prof, Node);
-
- EmitBlock(CheckBB);
-
- bool WithDiag = !CGM.getCodeGenOpts().SanitizeTrap.has(Kind);
-
- llvm::CallInst *CheckCall;
- llvm::Constant *SlowPathFn;
- if (WithDiag) {
- llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
- auto *InfoPtr =
- new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
- llvm::GlobalVariable::PrivateLinkage, Info);
- InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
-
- SlowPathFn = CGM.getModule().getOrInsertFunction(
- "__cfi_slowpath_diag",
- llvm::FunctionType::get(VoidTy, {Int64Ty, Int8PtrTy, Int8PtrTy},
- false));
- CheckCall = Builder.CreateCall(
- SlowPathFn, {TypeId, Ptr, Builder.CreateBitCast(InfoPtr, Int8PtrTy)});
- } else {
- SlowPathFn = CGM.getModule().getOrInsertFunction(
- "__cfi_slowpath",
- llvm::FunctionType::get(VoidTy, {Int64Ty, Int8PtrTy}, false));
- CheckCall = Builder.CreateCall(SlowPathFn, {TypeId, Ptr});
- }
-
- CGM.setDSOLocal(cast<llvm::GlobalValue>(SlowPathFn->stripPointerCasts()));
- CheckCall->setDoesNotThrow();
-
- EmitBlock(Cont);
-}
-
-// Emit a stub for __cfi_check function so that the linker knows about this
-// symbol in LTO mode.
-void CodeGenFunction::EmitCfiCheckStub() {
- llvm::Module *M = &CGM.getModule();
- auto &Ctx = M->getContext();
- llvm::Function *F = llvm::Function::Create(
- llvm::FunctionType::get(VoidTy, {Int64Ty, Int8PtrTy, Int8PtrTy}, false),
- llvm::GlobalValue::WeakAnyLinkage, "__cfi_check", M);
- CGM.setDSOLocal(F);
- llvm::BasicBlock *BB = llvm::BasicBlock::Create(Ctx, "entry", F);
- // FIXME: consider emitting an intrinsic call like
- // call void @llvm.cfi_check(i64 %0, i8* %1, i8* %2)
- // which can be lowered in CrossDSOCFI pass to the actual contents of
- // __cfi_check. This would allow inlining of __cfi_check calls.
- llvm::CallInst::Create(
- llvm::Intrinsic::getDeclaration(M, llvm::Intrinsic::trap), "", BB);
- llvm::ReturnInst::Create(Ctx, nullptr, BB);
-}
-
-// This function is basically a switch over the CFI failure kind, which is
-// extracted from CFICheckFailData (1st function argument). Each case is either
-// llvm.trap or a call to one of the two runtime handlers, based on
-// -fsanitize-trap and -fsanitize-recover settings. Default case (invalid
-// failure kind) traps, but this should really never happen. CFICheckFailData
-// can be nullptr if the calling module has -fsanitize-trap behavior for this
-// check kind; in this case __cfi_check_fail traps as well.
-void CodeGenFunction::EmitCfiCheckFail() {
- SanitizerScope SanScope(this);
- FunctionArgList Args;
- ImplicitParamDecl ArgData(getContext(), getContext().VoidPtrTy,
- ImplicitParamDecl::Other);
- ImplicitParamDecl ArgAddr(getContext(), getContext().VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.push_back(&ArgData);
- Args.push_back(&ArgAddr);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(getContext().VoidTy, Args);
-
- llvm::Function *F = llvm::Function::Create(
- llvm::FunctionType::get(VoidTy, {VoidPtrTy, VoidPtrTy}, false),
- llvm::GlobalValue::WeakODRLinkage, "__cfi_check_fail", &CGM.getModule());
- F->setVisibility(llvm::GlobalValue::HiddenVisibility);
-
- StartFunction(GlobalDecl(), CGM.getContext().VoidTy, F, FI, Args,
- SourceLocation());
-
- // This function should not be affected by blacklist. This function does
- // not have a source location, but "src:*" would still apply. Revert any
- // changes to SanOpts made in StartFunction.
- SanOpts = CGM.getLangOpts().Sanitize;
-
- llvm::Value *Data =
- EmitLoadOfScalar(GetAddrOfLocalVar(&ArgData), /*Volatile=*/false,
- CGM.getContext().VoidPtrTy, ArgData.getLocation());
- llvm::Value *Addr =
- EmitLoadOfScalar(GetAddrOfLocalVar(&ArgAddr), /*Volatile=*/false,
- CGM.getContext().VoidPtrTy, ArgAddr.getLocation());
-
- // Data == nullptr means the calling module has trap behaviour for this check.
- llvm::Value *DataIsNotNullPtr =
- Builder.CreateICmpNE(Data, llvm::ConstantPointerNull::get(Int8PtrTy));
- EmitTrapCheck(DataIsNotNullPtr);
-
- llvm::StructType *SourceLocationTy =
- llvm::StructType::get(VoidPtrTy, Int32Ty, Int32Ty);
- llvm::StructType *CfiCheckFailDataTy =
- llvm::StructType::get(Int8Ty, SourceLocationTy, VoidPtrTy);
-
- llvm::Value *V = Builder.CreateConstGEP2_32(
- CfiCheckFailDataTy,
- Builder.CreatePointerCast(Data, CfiCheckFailDataTy->getPointerTo(0)), 0,
- 0);
- Address CheckKindAddr(V, getIntAlign());
- llvm::Value *CheckKind = Builder.CreateLoad(CheckKindAddr);
-
- llvm::Value *AllVtables = llvm::MetadataAsValue::get(
- CGM.getLLVMContext(),
- llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
- llvm::Value *ValidVtable = Builder.CreateZExt(
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
- {Addr, AllVtables}),
- IntPtrTy);
-
- const std::pair<int, SanitizerMask> CheckKinds[] = {
- {CFITCK_VCall, SanitizerKind::CFIVCall},
- {CFITCK_NVCall, SanitizerKind::CFINVCall},
- {CFITCK_DerivedCast, SanitizerKind::CFIDerivedCast},
- {CFITCK_UnrelatedCast, SanitizerKind::CFIUnrelatedCast},
- {CFITCK_ICall, SanitizerKind::CFIICall}};
-
- SmallVector<std::pair<llvm::Value *, SanitizerMask>, 5> Checks;
- for (auto CheckKindMaskPair : CheckKinds) {
- int Kind = CheckKindMaskPair.first;
- SanitizerMask Mask = CheckKindMaskPair.second;
- llvm::Value *Cond =
- Builder.CreateICmpNE(CheckKind, llvm::ConstantInt::get(Int8Ty, Kind));
- if (CGM.getLangOpts().Sanitize.has(Mask))
- EmitCheck(std::make_pair(Cond, Mask), SanitizerHandler::CFICheckFail, {},
- {Data, Addr, ValidVtable});
- else
- EmitTrapCheck(Cond);
- }
-
- FinishFunction();
- // The only reference to this function will be created during LTO link.
- // Make sure it survives until then.
- CGM.addUsedGlobal(F);
-}
-
-void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
- if (SanOpts.has(SanitizerKind::Unreachable)) {
- SanitizerScope SanScope(this);
- EmitCheck(std::make_pair(static_cast<llvm::Value *>(Builder.getFalse()),
- SanitizerKind::Unreachable),
- SanitizerHandler::BuiltinUnreachable,
- EmitCheckSourceLocation(Loc), None);
- }
- Builder.CreateUnreachable();
-}
-
-void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) {
- llvm::BasicBlock *Cont = createBasicBlock("cont");
-
- // If we're optimizing, collapse all calls to trap down to just one per
- // function to save on code size.
- if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB) {
- TrapBB = createBasicBlock("trap");
- Builder.CreateCondBr(Checked, Cont, TrapBB);
- EmitBlock(TrapBB);
- llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
- TrapCall->setDoesNotReturn();
- TrapCall->setDoesNotThrow();
- Builder.CreateUnreachable();
- } else {
- Builder.CreateCondBr(Checked, Cont, TrapBB);
- }
-
- EmitBlock(Cont);
-}
-
-llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) {
- llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(IntrID));
-
- if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
- auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
- CGM.getCodeGenOpts().TrapFuncName);
- TrapCall->addAttribute(llvm::AttributeList::FunctionIndex, A);
- }
-
- return TrapCall;
-}
-
-Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E,
- LValueBaseInfo *BaseInfo,
- TBAAAccessInfo *TBAAInfo) {
- assert(E->getType()->isArrayType() &&
- "Array to pointer decay must have array source type!");
-
- // Expressions of array type can't be bitfields or vector elements.
- LValue LV = EmitLValue(E);
- Address Addr = LV.getAddress();
-
- // If the array type was an incomplete type, we need to make sure
- // the decay ends up being the right type.
- llvm::Type *NewTy = ConvertType(E->getType());
- Addr = Builder.CreateElementBitCast(Addr, NewTy);
-
- // Note that VLA pointers are always decayed, so we don't need to do
- // anything here.
- if (!E->getType()->isVariableArrayType()) {
- assert(isa<llvm::ArrayType>(Addr.getElementType()) &&
- "Expected pointer to array");
- Addr = Builder.CreateStructGEP(Addr, 0, CharUnits::Zero(), "arraydecay");
- }
-
- // The result of this decay conversion points to an array element within the
- // base lvalue. However, since TBAA currently does not support representing
- // accesses to elements of member arrays, we conservatively represent accesses
- // to the pointee object as if it had no any base lvalue specified.
- // TODO: Support TBAA for member arrays.
- QualType EltType = E->getType()->castAsArrayTypeUnsafe()->getElementType();
- if (BaseInfo) *BaseInfo = LV.getBaseInfo();
- if (TBAAInfo) *TBAAInfo = CGM.getTBAAAccessInfo(EltType);
-
- return Builder.CreateElementBitCast(Addr, ConvertTypeForMem(EltType));
-}
-
-/// isSimpleArrayDecayOperand - If the specified expr is a simple decay from an
-/// array to pointer, return the array subexpression.
-static const Expr *isSimpleArrayDecayOperand(const Expr *E) {
- // If this isn't just an array->pointer decay, bail out.
- const auto *CE = dyn_cast<CastExpr>(E);
- if (!CE || CE->getCastKind() != CK_ArrayToPointerDecay)
- return nullptr;
-
- // If this is a decay from variable width array, bail out.
- const Expr *SubExpr = CE->getSubExpr();
- if (SubExpr->getType()->isVariableArrayType())
- return nullptr;
-
- return SubExpr;
-}
-
-static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
- llvm::Value *ptr,
- ArrayRef<llvm::Value*> indices,
- bool inbounds,
- bool signedIndices,
- SourceLocation loc,
- const llvm::Twine &name = "arrayidx") {
- if (inbounds) {
- return CGF.EmitCheckedInBoundsGEP(ptr, indices, signedIndices,
- CodeGenFunction::NotSubtraction, loc,
- name);
- } else {
- return CGF.Builder.CreateGEP(ptr, indices, name);
- }
-}
-
-static CharUnits getArrayElementAlign(CharUnits arrayAlign,
- llvm::Value *idx,
- CharUnits eltSize) {
- // If we have a constant index, we can use the exact offset of the
- // element we're accessing.
- if (auto constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
- CharUnits offset = constantIdx->getZExtValue() * eltSize;
- return arrayAlign.alignmentAtOffset(offset);
-
- // Otherwise, use the worst-case alignment for any element.
- } else {
- return arrayAlign.alignmentOfArrayElement(eltSize);
- }
-}
-
-static QualType getFixedSizeElementType(const ASTContext &ctx,
- const VariableArrayType *vla) {
- QualType eltType;
- do {
- eltType = vla->getElementType();
- } while ((vla = ctx.getAsVariableArrayType(eltType)));
- return eltType;
-}
-
-static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
- ArrayRef<llvm::Value *> indices,
- QualType eltType, bool inbounds,
- bool signedIndices, SourceLocation loc,
- const llvm::Twine &name = "arrayidx") {
- // All the indices except that last must be zero.
-#ifndef NDEBUG
- for (auto idx : indices.drop_back())
- assert(isa<llvm::ConstantInt>(idx) &&
- cast<llvm::ConstantInt>(idx)->isZero());
-#endif
-
- // Determine the element size of the statically-sized base. This is
- // the thing that the indices are expressed in terms of.
- if (auto vla = CGF.getContext().getAsVariableArrayType(eltType)) {
- eltType = getFixedSizeElementType(CGF.getContext(), vla);
- }
-
- // We can use that to compute the best alignment of the element.
- CharUnits eltSize = CGF.getContext().getTypeSizeInChars(eltType);
- CharUnits eltAlign =
- getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
-
- llvm::Value *eltPtr = emitArraySubscriptGEP(
- CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name);
- return Address(eltPtr, eltAlign);
-}
-
-LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
- bool Accessed) {
- // The index must always be an integer, which is not an aggregate. Emit it
- // in lexical order (this complexity is, sadly, required by C++17).
- llvm::Value *IdxPre =
- (E->getLHS() == E->getIdx()) ? EmitScalarExpr(E->getIdx()) : nullptr;
- bool SignedIndices = false;
- auto EmitIdxAfterBase = [&, IdxPre](bool Promote) -> llvm::Value * {
- auto *Idx = IdxPre;
- if (E->getLHS() != E->getIdx()) {
- assert(E->getRHS() == E->getIdx() && "index was neither LHS nor RHS");
- Idx = EmitScalarExpr(E->getIdx());
- }
-
- QualType IdxTy = E->getIdx()->getType();
- bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
- SignedIndices |= IdxSigned;
-
- if (SanOpts.has(SanitizerKind::ArrayBounds))
- EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
-
- // Extend or truncate the index type to 32 or 64-bits.
- if (Promote && Idx->getType() != IntPtrTy)
- Idx = Builder.CreateIntCast(Idx, IntPtrTy, IdxSigned, "idxprom");
-
- return Idx;
- };
- IdxPre = nullptr;
-
- // If the base is a vector type, then we are forming a vector element lvalue
- // with this subscript.
- if (E->getBase()->getType()->isVectorType() &&
- !isa<ExtVectorElementExpr>(E->getBase())) {
- // Emit the vector as an lvalue to get its address.
- LValue LHS = EmitLValue(E->getBase());
- auto *Idx = EmitIdxAfterBase(/*Promote*/false);
- assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
- return LValue::MakeVectorElt(LHS.getAddress(), Idx, E->getBase()->getType(),
- LHS.getBaseInfo(), TBAAAccessInfo());
- }
-
- // All the other cases basically behave like simple offsetting.
-
- // Handle the extvector case we ignored above.
- if (isa<ExtVectorElementExpr>(E->getBase())) {
- LValue LV = EmitLValue(E->getBase());
- auto *Idx = EmitIdxAfterBase(/*Promote*/true);
- Address Addr = EmitExtVectorElementLValue(LV);
-
- QualType EltType = LV.getType()->castAs<VectorType>()->getElementType();
- Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true,
- SignedIndices, E->getExprLoc());
- return MakeAddrLValue(Addr, EltType, LV.getBaseInfo(),
- CGM.getTBAAInfoForSubobject(LV, EltType));
- }
-
- LValueBaseInfo EltBaseInfo;
- TBAAAccessInfo EltTBAAInfo;
- Address Addr = Address::invalid();
- if (const VariableArrayType *vla =
- getContext().getAsVariableArrayType(E->getType())) {
- // The base must be a pointer, which is not an aggregate. Emit
- // it. It needs to be emitted first in case it's what captures
- // the VLA bounds.
- Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
- auto *Idx = EmitIdxAfterBase(/*Promote*/true);
-
- // The element count here is the total number of non-VLA elements.
- llvm::Value *numElements = getVLASize(vla).NumElts;
-
- // Effectively, the multiply by the VLA size is part of the GEP.
- // GEP indexes are signed, and scaling an index isn't permitted to
- // signed-overflow, so we use the same semantics for our explicit
- // multiply. We suppress this if overflow is not undefined behavior.
- if (getLangOpts().isSignedOverflowDefined()) {
- Idx = Builder.CreateMul(Idx, numElements);
- } else {
- Idx = Builder.CreateNSWMul(Idx, numElements);
- }
-
- Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
- !getLangOpts().isSignedOverflowDefined(),
- SignedIndices, E->getExprLoc());
-
- } else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
- // Indexing over an interface, as in "NSString *P; P[4];"
-
- // Emit the base pointer.
- Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
- auto *Idx = EmitIdxAfterBase(/*Promote*/true);
-
- CharUnits InterfaceSize = getContext().getTypeSizeInChars(OIT);
- llvm::Value *InterfaceSizeVal =
- llvm::ConstantInt::get(Idx->getType(), InterfaceSize.getQuantity());
-
- llvm::Value *ScaledIdx = Builder.CreateMul(Idx, InterfaceSizeVal);
-
- // We don't necessarily build correct LLVM struct types for ObjC
- // interfaces, so we can't rely on GEP to do this scaling
- // correctly, so we need to cast to i8*. FIXME: is this actually
- // true? A lot of other things in the fragile ABI would break...
- llvm::Type *OrigBaseTy = Addr.getType();
- Addr = Builder.CreateElementBitCast(Addr, Int8Ty);
-
- // Do the GEP.
- CharUnits EltAlign =
- getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize);
- llvm::Value *EltPtr =
- emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false,
- SignedIndices, E->getExprLoc());
- Addr = Address(EltPtr, EltAlign);
-
- // Cast back.
- Addr = Builder.CreateBitCast(Addr, OrigBaseTy);
- } else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
- // If this is A[i] where A is an array, the frontend will have decayed the
- // base to be a ArrayToPointerDecay implicit cast. While correct, it is
- // inefficient at -O0 to emit a "gep A, 0, 0" when codegen'ing it, then a
- // "gep x, i" here. Emit one "gep A, 0, i".
- assert(Array->getType()->isArrayType() &&
- "Array to pointer decay must have array source type!");
- LValue ArrayLV;
- // For simple multidimensional array indexing, set the 'accessed' flag for
- // better bounds-checking of the base expression.
- if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Array))
- ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true);
- else
- ArrayLV = EmitLValue(Array);
- auto *Idx = EmitIdxAfterBase(/*Promote*/true);
-
- // Propagate the alignment from the array itself to the result.
- Addr = emitArraySubscriptGEP(
- *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
- E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
- E->getExprLoc());
- EltBaseInfo = ArrayLV.getBaseInfo();
- EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
- } else {
- // The base must be a pointer; emit it with an estimate of its alignment.
- Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
- auto *Idx = EmitIdxAfterBase(/*Promote*/true);
- Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
- !getLangOpts().isSignedOverflowDefined(),
- SignedIndices, E->getExprLoc());
- }
-
- LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
-
- if (getLangOpts().ObjC &&
- getLangOpts().getGC() != LangOptions::NonGC) {
- LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
- setObjCGCLValueClass(getContext(), E, LV);
- }
- return LV;
-}
-
-static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
- LValueBaseInfo &BaseInfo,
- TBAAAccessInfo &TBAAInfo,
- QualType BaseTy, QualType ElTy,
- bool IsLowerBound) {
- LValue BaseLVal;
- if (auto *ASE = dyn_cast<OMPArraySectionExpr>(Base->IgnoreParenImpCasts())) {
- BaseLVal = CGF.EmitOMPArraySectionExpr(ASE, IsLowerBound);
- if (BaseTy->isArrayType()) {
- Address Addr = BaseLVal.getAddress();
- BaseInfo = BaseLVal.getBaseInfo();
-
- // If the array type was an incomplete type, we need to make sure
- // the decay ends up being the right type.
- llvm::Type *NewTy = CGF.ConvertType(BaseTy);
- Addr = CGF.Builder.CreateElementBitCast(Addr, NewTy);
-
- // Note that VLA pointers are always decayed, so we don't need to do
- // anything here.
- if (!BaseTy->isVariableArrayType()) {
- assert(isa<llvm::ArrayType>(Addr.getElementType()) &&
- "Expected pointer to array");
- Addr = CGF.Builder.CreateStructGEP(Addr, 0, CharUnits::Zero(),
- "arraydecay");
- }
-
- return CGF.Builder.CreateElementBitCast(Addr,
- CGF.ConvertTypeForMem(ElTy));
- }
- LValueBaseInfo TypeBaseInfo;
- TBAAAccessInfo TypeTBAAInfo;
- CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &TypeBaseInfo,
- &TypeTBAAInfo);
- BaseInfo.mergeForCast(TypeBaseInfo);
- TBAAInfo = CGF.CGM.mergeTBAAInfoForCast(TBAAInfo, TypeTBAAInfo);
- return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress()), Align);
- }
- return CGF.EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo);
-}
-
-LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
- bool IsLowerBound) {
- QualType BaseTy = OMPArraySectionExpr::getBaseOriginalType(E->getBase());
- QualType ResultExprTy;
- if (auto *AT = getContext().getAsArrayType(BaseTy))
- ResultExprTy = AT->getElementType();
- else
- ResultExprTy = BaseTy->getPointeeType();
- llvm::Value *Idx = nullptr;
- if (IsLowerBound || E->getColonLoc().isInvalid()) {
- // Requesting lower bound or upper bound, but without provided length and
- // without ':' symbol for the default length -> length = 1.
- // Idx = LowerBound ?: 0;
- if (auto *LowerBound = E->getLowerBound()) {
- Idx = Builder.CreateIntCast(
- EmitScalarExpr(LowerBound), IntPtrTy,
- LowerBound->getType()->hasSignedIntegerRepresentation());
- } else
- Idx = llvm::ConstantInt::getNullValue(IntPtrTy);
- } else {
- // Try to emit length or lower bound as constant. If this is possible, 1
- // is subtracted from constant length or lower bound. Otherwise, emit LLVM
- // IR (LB + Len) - 1.
- auto &C = CGM.getContext();
- auto *Length = E->getLength();
- llvm::APSInt ConstLength;
- if (Length) {
- // Idx = LowerBound + Length - 1;
- if (Length->isIntegerConstantExpr(ConstLength, C)) {
- ConstLength = ConstLength.zextOrTrunc(PointerWidthInBits);
- Length = nullptr;
- }
- auto *LowerBound = E->getLowerBound();
- llvm::APSInt ConstLowerBound(PointerWidthInBits, /*isUnsigned=*/false);
- if (LowerBound && LowerBound->isIntegerConstantExpr(ConstLowerBound, C)) {
- ConstLowerBound = ConstLowerBound.zextOrTrunc(PointerWidthInBits);
- LowerBound = nullptr;
- }
- if (!Length)
- --ConstLength;
- else if (!LowerBound)
- --ConstLowerBound;
-
- if (Length || LowerBound) {
- auto *LowerBoundVal =
- LowerBound
- ? Builder.CreateIntCast(
- EmitScalarExpr(LowerBound), IntPtrTy,
- LowerBound->getType()->hasSignedIntegerRepresentation())
- : llvm::ConstantInt::get(IntPtrTy, ConstLowerBound);
- auto *LengthVal =
- Length
- ? Builder.CreateIntCast(
- EmitScalarExpr(Length), IntPtrTy,
- Length->getType()->hasSignedIntegerRepresentation())
- : llvm::ConstantInt::get(IntPtrTy, ConstLength);
- Idx = Builder.CreateAdd(LowerBoundVal, LengthVal, "lb_add_len",
- /*HasNUW=*/false,
- !getLangOpts().isSignedOverflowDefined());
- if (Length && LowerBound) {
- Idx = Builder.CreateSub(
- Idx, llvm::ConstantInt::get(IntPtrTy, /*V=*/1), "idx_sub_1",
- /*HasNUW=*/false, !getLangOpts().isSignedOverflowDefined());
- }
- } else
- Idx = llvm::ConstantInt::get(IntPtrTy, ConstLength + ConstLowerBound);
- } else {
- // Idx = ArraySize - 1;
- QualType ArrayTy = BaseTy->isPointerType()
- ? E->getBase()->IgnoreParenImpCasts()->getType()
- : BaseTy;
- if (auto *VAT = C.getAsVariableArrayType(ArrayTy)) {
- Length = VAT->getSizeExpr();
- if (Length->isIntegerConstantExpr(ConstLength, C))
- Length = nullptr;
- } else {
- auto *CAT = C.getAsConstantArrayType(ArrayTy);
- ConstLength = CAT->getSize();
- }
- if (Length) {
- auto *LengthVal = Builder.CreateIntCast(
- EmitScalarExpr(Length), IntPtrTy,
- Length->getType()->hasSignedIntegerRepresentation());
- Idx = Builder.CreateSub(
- LengthVal, llvm::ConstantInt::get(IntPtrTy, /*V=*/1), "len_sub_1",
- /*HasNUW=*/false, !getLangOpts().isSignedOverflowDefined());
- } else {
- ConstLength = ConstLength.zextOrTrunc(PointerWidthInBits);
- --ConstLength;
- Idx = llvm::ConstantInt::get(IntPtrTy, ConstLength);
- }
- }
- }
- assert(Idx);
-
- Address EltPtr = Address::invalid();
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- if (auto *VLA = getContext().getAsVariableArrayType(ResultExprTy)) {
- // The base must be a pointer, which is not an aggregate. Emit
- // it. It needs to be emitted first in case it's what captures
- // the VLA bounds.
- Address Base =
- emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, TBAAInfo,
- BaseTy, VLA->getElementType(), IsLowerBound);
- // The element count here is the total number of non-VLA elements.
- llvm::Value *NumElements = getVLASize(VLA).NumElts;
-
- // Effectively, the multiply by the VLA size is part of the GEP.
- // GEP indexes are signed, and scaling an index isn't permitted to
- // signed-overflow, so we use the same semantics for our explicit
- // multiply. We suppress this if overflow is not undefined behavior.
- if (getLangOpts().isSignedOverflowDefined())
- Idx = Builder.CreateMul(Idx, NumElements);
- else
- Idx = Builder.CreateNSWMul(Idx, NumElements);
- EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),
- !getLangOpts().isSignedOverflowDefined(),
- /*SignedIndices=*/false, E->getExprLoc());
- } else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
- // If this is A[i] where A is an array, the frontend will have decayed the
- // base to be a ArrayToPointerDecay implicit cast. While correct, it is
- // inefficient at -O0 to emit a "gep A, 0, 0" when codegen'ing it, then a
- // "gep x, i" here. Emit one "gep A, 0, i".
- assert(Array->getType()->isArrayType() &&
- "Array to pointer decay must have array source type!");
- LValue ArrayLV;
- // For simple multidimensional array indexing, set the 'accessed' flag for
- // better bounds-checking of the base expression.
- if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Array))
- ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true);
- else
- ArrayLV = EmitLValue(Array);
-
- // Propagate the alignment from the array itself to the result.
- EltPtr = emitArraySubscriptGEP(
- *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
- ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
- /*SignedIndices=*/false, E->getExprLoc());
- BaseInfo = ArrayLV.getBaseInfo();
- TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy);
- } else {
- Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo,
- TBAAInfo, BaseTy, ResultExprTy,
- IsLowerBound);
- EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
- !getLangOpts().isSignedOverflowDefined(),
- /*SignedIndices=*/false, E->getExprLoc());
- }
-
- return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo, TBAAInfo);
-}
-
-LValue CodeGenFunction::
-EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
- // Emit the base vector as an l-value.
- LValue Base;
-
- // ExtVectorElementExpr's base can either be a vector or pointer to vector.
- if (E->isArrow()) {
- // If it is a pointer to a vector, emit the address and form an lvalue with
- // it.
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- Address Ptr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo);
- const PointerType *PT = E->getBase()->getType()->getAs<PointerType>();
- Base = MakeAddrLValue(Ptr, PT->getPointeeType(), BaseInfo, TBAAInfo);
- Base.getQuals().removeObjCGCAttr();
- } else if (E->getBase()->isGLValue()) {
- // Otherwise, if the base is an lvalue ( as in the case of foo.x.x),
- // emit the base as an lvalue.
- assert(E->getBase()->getType()->isVectorType());
- Base = EmitLValue(E->getBase());
- } else {
- // Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such.
- assert(E->getBase()->getType()->isVectorType() &&
- "Result must be a vector");
- llvm::Value *Vec = EmitScalarExpr(E->getBase());
-
- // Store the vector to memory (because LValue wants an address).
- Address VecMem = CreateMemTemp(E->getBase()->getType());
- Builder.CreateStore(Vec, VecMem);
- Base = MakeAddrLValue(VecMem, E->getBase()->getType(),
- AlignmentSource::Decl);
- }
-
- QualType type =
- E->getType().withCVRQualifiers(Base.getQuals().getCVRQualifiers());
-
- // Encode the element access list into a vector of unsigned indices.
- SmallVector<uint32_t, 4> Indices;
- E->getEncodedElementAccess(Indices);
-
- if (Base.isSimple()) {
- llvm::Constant *CV =
- llvm::ConstantDataVector::get(getLLVMContext(), Indices);
- return LValue::MakeExtVectorElt(Base.getAddress(), CV, type,
- Base.getBaseInfo(), TBAAAccessInfo());
- }
- assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
-
- llvm::Constant *BaseElts = Base.getExtVectorElts();
- SmallVector<llvm::Constant *, 4> CElts;
-
- for (unsigned i = 0, e = Indices.size(); i != e; ++i)
- CElts.push_back(BaseElts->getAggregateElement(Indices[i]));
- llvm::Constant *CV = llvm::ConstantVector::get(CElts);
- return LValue::MakeExtVectorElt(Base.getExtVectorAddress(), CV, type,
- Base.getBaseInfo(), TBAAAccessInfo());
-}
-
-LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
- if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, E)) {
- EmitIgnoredExpr(E->getBase());
- return EmitDeclRefLValue(DRE);
- }
-
- Expr *BaseExpr = E->getBase();
- // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
- LValue BaseLV;
- if (E->isArrow()) {
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- Address Addr = EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo);
- QualType PtrTy = BaseExpr->getType()->getPointeeType();
- SanitizerSet SkippedChecks;
- bool IsBaseCXXThis = IsWrappedCXXThis(BaseExpr);
- if (IsBaseCXXThis)
- SkippedChecks.set(SanitizerKind::Alignment, true);
- if (IsBaseCXXThis || isa<DeclRefExpr>(BaseExpr))
- SkippedChecks.set(SanitizerKind::Null, true);
- EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy,
- /*Alignment=*/CharUnits::Zero(), SkippedChecks);
- BaseLV = MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo);
- } else
- BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
-
- NamedDecl *ND = E->getMemberDecl();
- if (auto *Field = dyn_cast<FieldDecl>(ND)) {
- LValue LV = EmitLValueForField(BaseLV, Field);
- setObjCGCLValueClass(getContext(), E, LV);
- return LV;
- }
-
- if (const auto *FD = dyn_cast<FunctionDecl>(ND))
- return EmitFunctionDeclLValue(*this, E, FD);
-
- llvm_unreachable("Unhandled member declaration!");
-}
-
-/// Given that we are currently emitting a lambda, emit an l-value for
-/// one of its members.
-LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) {
- assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent()->isLambda());
- assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent() == Field->getParent());
- QualType LambdaTagType =
- getContext().getTagDeclType(Field->getParent());
- LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, LambdaTagType);
- return EmitLValueForField(LambdaLV, Field);
-}
-
-/// Drill down to the storage of a field without walking into
-/// reference types.
-///
-/// The resulting address doesn't necessarily have the right type.
-static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
- const FieldDecl *field) {
- const RecordDecl *rec = field->getParent();
-
- unsigned idx =
- CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
-
- CharUnits offset;
- // Adjust the alignment down to the given offset.
- // As a special case, if the LLVM field index is 0, we know that this
- // is zero.
- assert((idx != 0 || CGF.getContext().getASTRecordLayout(rec)
- .getFieldOffset(field->getFieldIndex()) == 0) &&
- "LLVM field at index zero had non-zero offset?");
- if (idx != 0) {
- auto &recLayout = CGF.getContext().getASTRecordLayout(rec);
- auto offsetInBits = recLayout.getFieldOffset(field->getFieldIndex());
- offset = CGF.getContext().toCharUnitsFromBits(offsetInBits);
- }
-
- return CGF.Builder.CreateStructGEP(base, idx, offset, field->getName());
-}
-
-static bool hasAnyVptr(const QualType Type, const ASTContext &Context) {
- const auto *RD = Type.getTypePtr()->getAsCXXRecordDecl();
- if (!RD)
- return false;
-
- if (RD->isDynamicClass())
- return true;
-
- for (const auto &Base : RD->bases())
- if (hasAnyVptr(Base.getType(), Context))
- return true;
-
- for (const FieldDecl *Field : RD->fields())
- if (hasAnyVptr(Field->getType(), Context))
- return true;
-
- return false;
-}
-
-LValue CodeGenFunction::EmitLValueForField(LValue base,
- const FieldDecl *field) {
- LValueBaseInfo BaseInfo = base.getBaseInfo();
-
- if (field->isBitField()) {
- const CGRecordLayout &RL =
- CGM.getTypes().getCGRecordLayout(field->getParent());
- const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
- Address Addr = base.getAddress();
- unsigned Idx = RL.getLLVMFieldNo(field);
- if (Idx != 0)
- // For structs, we GEP to the field that the record layout suggests.
- Addr = Builder.CreateStructGEP(Addr, Idx, Info.StorageOffset,
- field->getName());
- // Get the access type.
- llvm::Type *FieldIntTy =
- llvm::Type::getIntNTy(getLLVMContext(), Info.StorageSize);
- if (Addr.getElementType() != FieldIntTy)
- Addr = Builder.CreateElementBitCast(Addr, FieldIntTy);
-
- QualType fieldType =
- field->getType().withCVRQualifiers(base.getVRQualifiers());
- // TODO: Support TBAA for bit fields.
- LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource());
- return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo,
- TBAAAccessInfo());
- }
-
- // Fields of may-alias structures are may-alias themselves.
- // FIXME: this should get propagated down through anonymous structs
- // and unions.
- QualType FieldType = field->getType();
- const RecordDecl *rec = field->getParent();
- AlignmentSource BaseAlignSource = BaseInfo.getAlignmentSource();
- LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(BaseAlignSource));
- TBAAAccessInfo FieldTBAAInfo;
- if (base.getTBAAInfo().isMayAlias() ||
- rec->hasAttr<MayAliasAttr>() || FieldType->isVectorType()) {
- FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
- } else if (rec->isUnion()) {
- // TODO: Support TBAA for unions.
- FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
- } else {
- // If no base type been assigned for the base access, then try to generate
- // one for this base lvalue.
- FieldTBAAInfo = base.getTBAAInfo();
- if (!FieldTBAAInfo.BaseType) {
- FieldTBAAInfo.BaseType = CGM.getTBAABaseTypeInfo(base.getType());
- assert(!FieldTBAAInfo.Offset &&
- "Nonzero offset for an access with no base type!");
- }
-
- // Adjust offset to be relative to the base type.
- const ASTRecordLayout &Layout =
- getContext().getASTRecordLayout(field->getParent());
- unsigned CharWidth = getContext().getCharWidth();
- if (FieldTBAAInfo.BaseType)
- FieldTBAAInfo.Offset +=
- Layout.getFieldOffset(field->getFieldIndex()) / CharWidth;
-
- // Update the final access type and size.
- FieldTBAAInfo.AccessType = CGM.getTBAATypeInfo(FieldType);
- FieldTBAAInfo.Size =
- getContext().getTypeSizeInChars(FieldType).getQuantity();
- }
-
- Address addr = base.getAddress();
- if (auto *ClassDef = dyn_cast<CXXRecordDecl>(rec)) {
- if (CGM.getCodeGenOpts().StrictVTablePointers &&
- ClassDef->isDynamicClass()) {
- // Getting to any field of dynamic object requires stripping dynamic
- // information provided by invariant.group. This is because accessing
- // fields may leak the real address of dynamic object, which could result
- // in miscompilation when leaked pointer would be compared.
- auto *stripped = Builder.CreateStripInvariantGroup(addr.getPointer());
- addr = Address(stripped, addr.getAlignment());
- }
- }
-
- unsigned RecordCVR = base.getVRQualifiers();
- if (rec->isUnion()) {
- // For unions, there is no pointer adjustment.
- assert(!FieldType->isReferenceType() && "union has reference member");
- if (CGM.getCodeGenOpts().StrictVTablePointers &&
- hasAnyVptr(FieldType, getContext()))
- // Because unions can easily skip invariant.barriers, we need to add
- // a barrier every time CXXRecord field with vptr is referenced.
- addr = Address(Builder.CreateLaunderInvariantGroup(addr.getPointer()),
- addr.getAlignment());
- } else {
- // For structs, we GEP to the field that the record layout suggests.
- addr = emitAddrOfFieldStorage(*this, addr, field);
-
- // If this is a reference field, load the reference right now.
- if (FieldType->isReferenceType()) {
- LValue RefLVal = MakeAddrLValue(addr, FieldType, FieldBaseInfo,
- FieldTBAAInfo);
- if (RecordCVR & Qualifiers::Volatile)
- RefLVal.getQuals().addVolatile();
- addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo);
-
- // Qualifiers on the struct don't apply to the referencee.
- RecordCVR = 0;
- FieldType = FieldType->getPointeeType();
- }
- }
-
- // Make sure that the address is pointing to the right type. This is critical
- // for both unions and structs. A union needs a bitcast, a struct element
- // will need a bitcast if the LLVM type laid out doesn't match the desired
- // type.
- addr = Builder.CreateElementBitCast(
- addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName());
-
- if (field->hasAttr<AnnotateAttr>())
- addr = EmitFieldAnnotations(field, addr);
-
- LValue LV = MakeAddrLValue(addr, FieldType, FieldBaseInfo, FieldTBAAInfo);
- LV.getQuals().addCVRQualifiers(RecordCVR);
-
- // __weak attribute on a field is ignored.
- if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak)
- LV.getQuals().removeObjCGCAttr();
-
- return LV;
-}
-
-LValue
-CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
- const FieldDecl *Field) {
- QualType FieldType = Field->getType();
-
- if (!FieldType->isReferenceType())
- return EmitLValueForField(Base, Field);
-
- Address V = emitAddrOfFieldStorage(*this, Base.getAddress(), Field);
-
- // Make sure that the address is pointing to the right type.
- llvm::Type *llvmType = ConvertTypeForMem(FieldType);
- V = Builder.CreateElementBitCast(V, llvmType, Field->getName());
-
- // TODO: Generate TBAA information that describes this access as a structure
- // member access and not just an access to an object of the field's type. This
- // should be similar to what we do in EmitLValueForField().
- LValueBaseInfo BaseInfo = Base.getBaseInfo();
- AlignmentSource FieldAlignSource = BaseInfo.getAlignmentSource();
- LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(FieldAlignSource));
- return MakeAddrLValue(V, FieldType, FieldBaseInfo,
- CGM.getTBAAInfoForSubobject(Base, FieldType));
-}
-
-LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
- if (E->isFileScope()) {
- ConstantAddress GlobalPtr = CGM.GetAddrOfConstantCompoundLiteral(E);
- return MakeAddrLValue(GlobalPtr, E->getType(), AlignmentSource::Decl);
- }
- if (E->getType()->isVariablyModifiedType())
- // make sure to emit the VLA size.
- EmitVariablyModifiedType(E->getType());
-
- Address DeclPtr = CreateMemTemp(E->getType(), ".compoundliteral");
- const Expr *InitExpr = E->getInitializer();
- LValue Result = MakeAddrLValue(DeclPtr, E->getType(), AlignmentSource::Decl);
-
- EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(),
- /*Init*/ true);
-
- return Result;
-}
-
-LValue CodeGenFunction::EmitInitListLValue(const InitListExpr *E) {
- if (!E->isGLValue())
- // Initializing an aggregate temporary in C++11: T{...}.
- return EmitAggExprToLValue(E);
-
- // An lvalue initializer list must be initializing a reference.
- assert(E->isTransparent() && "non-transparent glvalue init list");
- return EmitLValue(E->getInit(0));
-}
-
-/// Emit the operand of a glvalue conditional operator. This is either a glvalue
-/// or a (possibly-parenthesized) throw-expression. If this is a throw, no
-/// LValue is returned and the current block has been terminated.
-static Optional<LValue> EmitLValueOrThrowExpression(CodeGenFunction &CGF,
- const Expr *Operand) {
- if (auto *ThrowExpr = dyn_cast<CXXThrowExpr>(Operand->IgnoreParens())) {
- CGF.EmitCXXThrowExpr(ThrowExpr, /*KeepInsertionPoint*/false);
- return None;
- }
-
- return CGF.EmitLValue(Operand);
-}
-
-LValue CodeGenFunction::
-EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
- if (!expr->isGLValue()) {
- // ?: here should be an aggregate.
- assert(hasAggregateEvaluationKind(expr->getType()) &&
- "Unexpected conditional operator!");
- return EmitAggExprToLValue(expr);
- }
-
- OpaqueValueMapping binding(*this, expr);
-
- const Expr *condExpr = expr->getCond();
- bool CondExprBool;
- if (ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) {
- const Expr *live = expr->getTrueExpr(), *dead = expr->getFalseExpr();
- if (!CondExprBool) std::swap(live, dead);
-
- if (!ContainsLabel(dead)) {
- // If the true case is live, we need to track its region.
- if (CondExprBool)
- incrementProfileCounter(expr);
- return EmitLValue(live);
- }
- }
-
- llvm::BasicBlock *lhsBlock = createBasicBlock("cond.true");
- llvm::BasicBlock *rhsBlock = createBasicBlock("cond.false");
- llvm::BasicBlock *contBlock = createBasicBlock("cond.end");
-
- ConditionalEvaluation eval(*this);
- EmitBranchOnBoolExpr(condExpr, lhsBlock, rhsBlock, getProfileCount(expr));
-
- // Any temporaries created here are conditional.
- EmitBlock(lhsBlock);
- incrementProfileCounter(expr);
- eval.begin(*this);
- Optional<LValue> lhs =
- EmitLValueOrThrowExpression(*this, expr->getTrueExpr());
- eval.end(*this);
-
- if (lhs && !lhs->isSimple())
- return EmitUnsupportedLValue(expr, "conditional operator");
-
- lhsBlock = Builder.GetInsertBlock();
- if (lhs)
- Builder.CreateBr(contBlock);
-
- // Any temporaries created here are conditional.
- EmitBlock(rhsBlock);
- eval.begin(*this);
- Optional<LValue> rhs =
- EmitLValueOrThrowExpression(*this, expr->getFalseExpr());
- eval.end(*this);
- if (rhs && !rhs->isSimple())
- return EmitUnsupportedLValue(expr, "conditional operator");
- rhsBlock = Builder.GetInsertBlock();
-
- EmitBlock(contBlock);
-
- if (lhs && rhs) {
- llvm::PHINode *phi = Builder.CreatePHI(lhs->getPointer()->getType(),
- 2, "cond-lvalue");
- phi->addIncoming(lhs->getPointer(), lhsBlock);
- phi->addIncoming(rhs->getPointer(), rhsBlock);
- Address result(phi, std::min(lhs->getAlignment(), rhs->getAlignment()));
- AlignmentSource alignSource =
- std::max(lhs->getBaseInfo().getAlignmentSource(),
- rhs->getBaseInfo().getAlignmentSource());
- TBAAAccessInfo TBAAInfo = CGM.mergeTBAAInfoForConditionalOperator(
- lhs->getTBAAInfo(), rhs->getTBAAInfo());
- return MakeAddrLValue(result, expr->getType(), LValueBaseInfo(alignSource),
- TBAAInfo);
- } else {
- assert((lhs || rhs) &&
- "both operands of glvalue conditional are throw-expressions?");
- return lhs ? *lhs : *rhs;
- }
-}
-
-/// EmitCastLValue - Casts are never lvalues unless that cast is to a reference
-/// type. If the cast is to a reference, we can have the usual lvalue result,
-/// otherwise if a cast is needed by the code generator in an lvalue context,
-/// then it must mean that we need the address of an aggregate in order to
-/// access one of its members. This can happen for all the reasons that casts
-/// are permitted with aggregate result, including noop aggregate casts, and
-/// cast from scalar to union.
-LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
- switch (E->getCastKind()) {
- case CK_ToVoid:
- case CK_BitCast:
- case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
- case CK_NullToMemberPointer:
- case CK_NullToPointer:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
- case CK_VectorSplat:
- case CK_IntegralCast:
- case CK_BooleanToSignedIntegral:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_DerivedToBaseMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_MemberPointerToBoolean:
- case CK_ReinterpretMemberPointer:
- case CK_AnyPointerToBlockPointerCast:
- case CK_ARCProduceObject:
- case CK_ARCConsumeObject:
- case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject:
- case CK_CopyAndAutoreleaseBlockObject:
- case CK_IntToOCLSampler:
- case CK_FixedPointCast:
- case CK_FixedPointToBoolean:
- return EmitUnsupportedLValue(E, "unexpected cast lvalue");
-
- case CK_Dependent:
- llvm_unreachable("dependent cast kind in IR gen!");
-
- case CK_BuiltinFnToFnPtr:
- llvm_unreachable("builtin functions are handled elsewhere");
-
- // These are never l-values; just use the aggregate emission code.
- case CK_NonAtomicToAtomic:
- case CK_AtomicToNonAtomic:
- return EmitAggExprToLValue(E);
-
- case CK_Dynamic: {
- LValue LV = EmitLValue(E->getSubExpr());
- Address V = LV.getAddress();
- const auto *DCE = cast<CXXDynamicCastExpr>(E);
- return MakeNaturalAlignAddrLValue(EmitDynamicCast(V, DCE), E->getType());
- }
-
- case CK_ConstructorConversion:
- case CK_UserDefinedConversion:
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_NoOp:
- case CK_LValueToRValue:
- return EmitLValue(E->getSubExpr());
-
- case CK_UncheckedDerivedToBase:
- case CK_DerivedToBase: {
- const RecordType *DerivedClassTy =
- E->getSubExpr()->getType()->getAs<RecordType>();
- auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl());
-
- LValue LV = EmitLValue(E->getSubExpr());
- Address This = LV.getAddress();
-
- // Perform the derived-to-base conversion
- Address Base = GetAddressOfBaseClass(
- This, DerivedClassDecl, E->path_begin(), E->path_end(),
- /*NullCheckValue=*/false, E->getExprLoc());
-
- // TODO: Support accesses to members of base classes in TBAA. For now, we
- // conservatively pretend that the complete object is of the base class
- // type.
- return MakeAddrLValue(Base, E->getType(), LV.getBaseInfo(),
- CGM.getTBAAInfoForSubobject(LV, E->getType()));
- }
- case CK_ToUnion:
- return EmitAggExprToLValue(E);
- case CK_BaseToDerived: {
- const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
- auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl());
-
- LValue LV = EmitLValue(E->getSubExpr());
-
- // Perform the base-to-derived conversion
- Address Derived =
- GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
- E->path_begin(), E->path_end(),
- /*NullCheckValue=*/false);
-
- // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
- // performed and the object is not of the derived type.
- if (sanitizePerformTypeCheck())
- EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
- Derived.getPointer(), E->getType());
-
- if (SanOpts.has(SanitizerKind::CFIDerivedCast))
- EmitVTablePtrCheckForCast(E->getType(), Derived.getPointer(),
- /*MayBeNull=*/false, CFITCK_DerivedCast,
- E->getBeginLoc());
-
- return MakeAddrLValue(Derived, E->getType(), LV.getBaseInfo(),
- CGM.getTBAAInfoForSubobject(LV, E->getType()));
- }
- case CK_LValueBitCast: {
- // This must be a reinterpret_cast (or c-style equivalent).
- const auto *CE = cast<ExplicitCastExpr>(E);
-
- CGM.EmitExplicitCastExprType(CE, this);
- LValue LV = EmitLValue(E->getSubExpr());
- Address V = Builder.CreateBitCast(LV.getAddress(),
- ConvertType(CE->getTypeAsWritten()));
-
- if (SanOpts.has(SanitizerKind::CFIUnrelatedCast))
- EmitVTablePtrCheckForCast(E->getType(), V.getPointer(),
- /*MayBeNull=*/false, CFITCK_UnrelatedCast,
- E->getBeginLoc());
-
- return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
- CGM.getTBAAInfoForSubobject(LV, E->getType()));
- }
- case CK_AddressSpaceConversion: {
- LValue LV = EmitLValue(E->getSubExpr());
- QualType DestTy = getContext().getPointerType(E->getType());
- llvm::Value *V = getTargetHooks().performAddrSpaceCast(
- *this, LV.getPointer(), E->getSubExpr()->getType().getAddressSpace(),
- E->getType().getAddressSpace(), ConvertType(DestTy));
- return MakeAddrLValue(Address(V, LV.getAddress().getAlignment()),
- E->getType(), LV.getBaseInfo(), LV.getTBAAInfo());
- }
- case CK_ObjCObjectLValueCast: {
- LValue LV = EmitLValue(E->getSubExpr());
- Address V = Builder.CreateElementBitCast(LV.getAddress(),
- ConvertType(E->getType()));
- return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
- CGM.getTBAAInfoForSubobject(LV, E->getType()));
- }
- case CK_ZeroToOCLOpaqueType:
- llvm_unreachable("NULL to OpenCL opaque type lvalue cast is not valid");
- }
-
- llvm_unreachable("Unhandled lvalue cast kind?");
-}
-
-LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
- assert(OpaqueValueMappingData::shouldBindAsLValue(e));
- return getOrCreateOpaqueLValueMapping(e);
-}
-
-LValue
-CodeGenFunction::getOrCreateOpaqueLValueMapping(const OpaqueValueExpr *e) {
- assert(OpaqueValueMapping::shouldBindAsLValue(e));
-
- llvm::DenseMap<const OpaqueValueExpr*,LValue>::iterator
- it = OpaqueLValues.find(e);
-
- if (it != OpaqueLValues.end())
- return it->second;
-
- assert(e->isUnique() && "LValue for a nonunique OVE hasn't been emitted");
- return EmitLValue(e->getSourceExpr());
-}
-
-RValue
-CodeGenFunction::getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e) {
- assert(!OpaqueValueMapping::shouldBindAsLValue(e));
-
- llvm::DenseMap<const OpaqueValueExpr*,RValue>::iterator
- it = OpaqueRValues.find(e);
-
- if (it != OpaqueRValues.end())
- return it->second;
-
- assert(e->isUnique() && "RValue for a nonunique OVE hasn't been emitted");
- return EmitAnyExpr(e->getSourceExpr());
-}
-
-RValue CodeGenFunction::EmitRValueForField(LValue LV,
- const FieldDecl *FD,
- SourceLocation Loc) {
- QualType FT = FD->getType();
- LValue FieldLV = EmitLValueForField(LV, FD);
- switch (getEvaluationKind(FT)) {
- case TEK_Complex:
- return RValue::getComplex(EmitLoadOfComplex(FieldLV, Loc));
- case TEK_Aggregate:
- return FieldLV.asAggregateRValue();
- case TEK_Scalar:
- // This routine is used to load fields one-by-one to perform a copy, so
- // don't load reference fields.
- if (FD->getType()->isReferenceType())
- return RValue::get(FieldLV.getPointer());
- return EmitLoadOfLValue(FieldLV, Loc);
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-//===--------------------------------------------------------------------===//
-// Expression Emission
-//===--------------------------------------------------------------------===//
-
-RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue) {
- // Builtins never have block type.
- if (E->getCallee()->getType()->isBlockPointerType())
- return EmitBlockCallExpr(E, ReturnValue);
-
- if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
- return EmitCXXMemberCallExpr(CE, ReturnValue);
-
- if (const auto *CE = dyn_cast<CUDAKernelCallExpr>(E))
- return EmitCUDAKernelCallExpr(CE, ReturnValue);
-
- if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(E))
- if (const CXXMethodDecl *MD =
- dyn_cast_or_null<CXXMethodDecl>(CE->getCalleeDecl()))
- return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
-
- CGCallee callee = EmitCallee(E->getCallee());
-
- if (callee.isBuiltin()) {
- return EmitBuiltinExpr(callee.getBuiltinDecl(), callee.getBuiltinID(),
- E, ReturnValue);
- }
-
- if (callee.isPseudoDestructor()) {
- return EmitCXXPseudoDestructorExpr(callee.getPseudoDestructorExpr());
- }
-
- return EmitCall(E->getCallee()->getType(), callee, E, ReturnValue);
-}
-
-/// Emit a CallExpr without considering whether it might be a subclass.
-RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue) {
- CGCallee Callee = EmitCallee(E->getCallee());
- return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue);
-}
-
-static CGCallee EmitDirectCallee(CodeGenFunction &CGF, const FunctionDecl *FD) {
- if (auto builtinID = FD->getBuiltinID()) {
- return CGCallee::forBuiltin(builtinID, FD);
- }
-
- llvm::Constant *calleePtr = EmitFunctionDeclPointer(CGF.CGM, FD);
- return CGCallee::forDirect(calleePtr, GlobalDecl(FD));
-}
-
-CGCallee CodeGenFunction::EmitCallee(const Expr *E) {
- E = E->IgnoreParens();
-
- // Look through function-to-pointer decay.
- if (auto ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getCastKind() == CK_FunctionToPointerDecay ||
- ICE->getCastKind() == CK_BuiltinFnToFnPtr) {
- return EmitCallee(ICE->getSubExpr());
- }
-
- // Resolve direct calls.
- } else if (auto DRE = dyn_cast<DeclRefExpr>(E)) {
- if (auto FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- return EmitDirectCallee(*this, FD);
- }
- } else if (auto ME = dyn_cast<MemberExpr>(E)) {
- if (auto FD = dyn_cast<FunctionDecl>(ME->getMemberDecl())) {
- EmitIgnoredExpr(ME->getBase());
- return EmitDirectCallee(*this, FD);
- }
-
- // Look through template substitutions.
- } else if (auto NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
- return EmitCallee(NTTP->getReplacement());
-
- // Treat pseudo-destructor calls differently.
- } else if (auto PDE = dyn_cast<CXXPseudoDestructorExpr>(E)) {
- return CGCallee::forPseudoDestructor(PDE);
- }
-
- // Otherwise, we have an indirect reference.
- llvm::Value *calleePtr;
- QualType functionType;
- if (auto ptrType = E->getType()->getAs<PointerType>()) {
- calleePtr = EmitScalarExpr(E);
- functionType = ptrType->getPointeeType();
- } else {
- functionType = E->getType();
- calleePtr = EmitLValue(E).getPointer();
- }
- assert(functionType->isFunctionType());
-
- GlobalDecl GD;
- if (const auto *VD =
- dyn_cast_or_null<VarDecl>(E->getReferencedDeclOfCallee()))
- GD = GlobalDecl(VD);
-
- CGCalleeInfo calleeInfo(functionType->getAs<FunctionProtoType>(), GD);
- CGCallee callee(calleeInfo, calleePtr);
- return callee;
-}
-
-LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
- // Comma expressions just emit their LHS then their RHS as an l-value.
- if (E->getOpcode() == BO_Comma) {
- EmitIgnoredExpr(E->getLHS());
- EnsureInsertPoint();
- return EmitLValue(E->getRHS());
- }
-
- if (E->getOpcode() == BO_PtrMemD ||
- E->getOpcode() == BO_PtrMemI)
- return EmitPointerToDataMemberBinaryExpr(E);
-
- assert(E->getOpcode() == BO_Assign && "unexpected binary l-value");
-
- // Note that in all of these cases, __block variables need the RHS
- // evaluated first just in case the variable gets moved by the RHS.
-
- switch (getEvaluationKind(E->getType())) {
- case TEK_Scalar: {
- switch (E->getLHS()->getType().getObjCLifetime()) {
- case Qualifiers::OCL_Strong:
- return EmitARCStoreStrong(E, /*ignored*/ false).first;
-
- case Qualifiers::OCL_Autoreleasing:
- return EmitARCStoreAutoreleasing(E).first;
-
- // No reason to do any of these differently.
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Weak:
- break;
- }
-
- RValue RV = EmitAnyExpr(E->getRHS());
- LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
- if (RV.isScalar())
- EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
- EmitStoreThroughLValue(RV, LV);
- return LV;
- }
-
- case TEK_Complex:
- return EmitComplexAssignmentLValue(E);
-
- case TEK_Aggregate:
- return EmitAggExprToLValue(E);
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
- RValue RV = EmitCallExpr(E);
-
- if (!RV.isScalar())
- return MakeAddrLValue(RV.getAggregateAddress(), E->getType(),
- AlignmentSource::Decl);
-
- assert(E->getCallReturnType(getContext())->isReferenceType() &&
- "Can't have a scalar return unless the return type is a "
- "reference type!");
-
- return MakeNaturalAlignPointeeAddrLValue(RV.getScalarVal(), E->getType());
-}
-
-LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
- // FIXME: This shouldn't require another copy.
- return EmitAggExprToLValue(E);
-}
-
-LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
- assert(E->getType()->getAsCXXRecordDecl()->hasTrivialDestructor()
- && "binding l-value to type which needs a temporary");
- AggValueSlot Slot = CreateAggTemp(E->getType());
- EmitCXXConstructExpr(E, Slot);
- return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl);
-}
-
-LValue
-CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
- return MakeNaturalAlignAddrLValue(EmitCXXTypeidExpr(E), E->getType());
-}
-
-Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
- return Builder.CreateElementBitCast(CGM.GetAddrOfUuidDescriptor(E),
- ConvertType(E->getType()));
-}
-
-LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) {
- return MakeAddrLValue(EmitCXXUuidofExpr(E), E->getType(),
- AlignmentSource::Decl);
-}
-
-LValue
-CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
- AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
- Slot.setExternallyDestructed();
- EmitAggExpr(E->getSubExpr(), Slot);
- EmitCXXTemporary(E->getTemporary(), E->getType(), Slot.getAddress());
- return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl);
-}
-
-LValue
-CodeGenFunction::EmitLambdaLValue(const LambdaExpr *E) {
- AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
- EmitLambdaExpr(E, Slot);
- return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl);
-}
-
-LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
- RValue RV = EmitObjCMessageExpr(E);
-
- if (!RV.isScalar())
- return MakeAddrLValue(RV.getAggregateAddress(), E->getType(),
- AlignmentSource::Decl);
-
- assert(E->getMethodDecl()->getReturnType()->isReferenceType() &&
- "Can't have a scalar return unless the return type is a "
- "reference type!");
-
- return MakeNaturalAlignPointeeAddrLValue(RV.getScalarVal(), E->getType());
-}
-
-LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) {
- Address V =
- CGM.getObjCRuntime().GetAddrOfSelector(*this, E->getSelector());
- return MakeAddrLValue(V, E->getType(), AlignmentSource::Decl);
-}
-
-llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) {
- return CGM.getObjCRuntime().EmitIvarOffset(*this, Interface, Ivar);
-}
-
-LValue CodeGenFunction::EmitLValueForIvar(QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) {
- return CGM.getObjCRuntime().EmitObjCValueForIvar(*this, ObjectTy, BaseValue,
- Ivar, CVRQualifiers);
-}
-
-LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
- // FIXME: A lot of the code below could be shared with EmitMemberExpr.
- llvm::Value *BaseValue = nullptr;
- const Expr *BaseExpr = E->getBase();
- Qualifiers BaseQuals;
- QualType ObjectTy;
- if (E->isArrow()) {
- BaseValue = EmitScalarExpr(BaseExpr);
- ObjectTy = BaseExpr->getType()->getPointeeType();
- BaseQuals = ObjectTy.getQualifiers();
- } else {
- LValue BaseLV = EmitLValue(BaseExpr);
- BaseValue = BaseLV.getPointer();
- ObjectTy = BaseExpr->getType();
- BaseQuals = ObjectTy.getQualifiers();
- }
-
- LValue LV =
- EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(),
- BaseQuals.getCVRQualifiers());
- setObjCGCLValueClass(getContext(), E, LV);
- return LV;
-}
-
-LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
- // Can only get l-value for message expression returning aggregate type
- RValue RV = EmitAnyExprToTemp(E);
- return MakeAddrLValue(RV.getAggregateAddress(), E->getType(),
- AlignmentSource::Decl);
-}
-
-RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee,
- const CallExpr *E, ReturnValueSlot ReturnValue,
- llvm::Value *Chain) {
- // Get the actual function type. The callee type will always be a pointer to
- // function type or a block pointer type.
- assert(CalleeType->isFunctionPointerType() &&
- "Call must have function pointer type!");
-
- const Decl *TargetDecl =
- OrigCallee.getAbstractInfo().getCalleeDecl().getDecl();
-
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
- // We can only guarantee that a function is called from the correct
- // context/function based on the appropriate target attributes,
- // so only check in the case where we have both always_inline and target
- // since otherwise we could be making a conditional call after a check for
- // the proper cpu features (and it won't cause code generation issues due to
- // function based code generation).
- if (TargetDecl->hasAttr<AlwaysInlineAttr>() &&
- TargetDecl->hasAttr<TargetAttr>())
- checkTargetFeatures(E, FD);
-
- CalleeType = getContext().getCanonicalType(CalleeType);
-
- auto PointeeType = cast<PointerType>(CalleeType)->getPointeeType();
-
- CGCallee Callee = OrigCallee;
-
- if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function) &&
- (!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
- if (llvm::Constant *PrefixSig =
- CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
- SanitizerScope SanScope(this);
- // Remove any (C++17) exception specifications, to allow calling e.g. a
- // noexcept function through a non-noexcept pointer.
- auto ProtoTy =
- getContext().getFunctionTypeWithExceptionSpec(PointeeType, EST_None);
- llvm::Constant *FTRTTIConst =
- CGM.GetAddrOfRTTIDescriptor(ProtoTy, /*ForEH=*/true);
- llvm::Type *PrefixStructTyElems[] = {PrefixSig->getType(), Int32Ty};
- llvm::StructType *PrefixStructTy = llvm::StructType::get(
- CGM.getLLVMContext(), PrefixStructTyElems, /*isPacked=*/true);
-
- llvm::Value *CalleePtr = Callee.getFunctionPointer();
-
- llvm::Value *CalleePrefixStruct = Builder.CreateBitCast(
- CalleePtr, llvm::PointerType::getUnqual(PrefixStructTy));
- llvm::Value *CalleeSigPtr =
- Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, 0, 0);
- llvm::Value *CalleeSig =
- Builder.CreateAlignedLoad(CalleeSigPtr, getIntAlign());
- llvm::Value *CalleeSigMatch = Builder.CreateICmpEQ(CalleeSig, PrefixSig);
-
- llvm::BasicBlock *Cont = createBasicBlock("cont");
- llvm::BasicBlock *TypeCheck = createBasicBlock("typecheck");
- Builder.CreateCondBr(CalleeSigMatch, TypeCheck, Cont);
-
- EmitBlock(TypeCheck);
- llvm::Value *CalleeRTTIPtr =
- Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, 0, 1);
- llvm::Value *CalleeRTTIEncoded =
- Builder.CreateAlignedLoad(CalleeRTTIPtr, getPointerAlign());
- llvm::Value *CalleeRTTI =
- DecodeAddrUsedInPrologue(CalleePtr, CalleeRTTIEncoded);
- llvm::Value *CalleeRTTIMatch =
- Builder.CreateICmpEQ(CalleeRTTI, FTRTTIConst);
- llvm::Constant *StaticData[] = {EmitCheckSourceLocation(E->getBeginLoc()),
- EmitCheckTypeDescriptor(CalleeType)};
- EmitCheck(std::make_pair(CalleeRTTIMatch, SanitizerKind::Function),
- SanitizerHandler::FunctionTypeMismatch, StaticData, CalleePtr);
-
- Builder.CreateBr(Cont);
- EmitBlock(Cont);
- }
- }
-
- const auto *FnType = cast<FunctionType>(PointeeType);
-
- // If we are checking indirect calls and this call is indirect, check that the
- // function pointer is a member of the bit set for the function type.
- if (SanOpts.has(SanitizerKind::CFIICall) &&
- (!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
- SanitizerScope SanScope(this);
- EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
-
- llvm::Metadata *MD;
- if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
- MD = CGM.CreateMetadataIdentifierGeneralized(QualType(FnType, 0));
- else
- MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
-
- llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
-
- llvm::Value *CalleePtr = Callee.getFunctionPointer();
- llvm::Value *CastedCallee = Builder.CreateBitCast(CalleePtr, Int8PtrTy);
- llvm::Value *TypeTest = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedCallee, TypeId});
-
- auto CrossDsoTypeId = CGM.CreateCrossDsoCfiTypeId(MD);
- llvm::Constant *StaticData[] = {
- llvm::ConstantInt::get(Int8Ty, CFITCK_ICall),
- EmitCheckSourceLocation(E->getBeginLoc()),
- EmitCheckTypeDescriptor(QualType(FnType, 0)),
- };
- if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) {
- EmitCfiSlowPathCheck(SanitizerKind::CFIICall, TypeTest, CrossDsoTypeId,
- CastedCallee, StaticData);
- } else {
- EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIICall),
- SanitizerHandler::CFICheckFail, StaticData,
- {CastedCallee, llvm::UndefValue::get(IntPtrTy)});
- }
- }
-
- CallArgList Args;
- if (Chain)
- Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)),
- CGM.getContext().VoidPtrTy);
-
- // C++17 requires that we evaluate arguments to a call using assignment syntax
- // right-to-left, and that we evaluate arguments to certain other operators
- // left-to-right. Note that we allow this to override the order dictated by
- // the calling convention on the MS ABI, which means that parameter
- // destruction order is not necessarily reverse construction order.
- // FIXME: Revisit this based on C++ committee response to unimplementability.
- EvaluationOrder Order = EvaluationOrder::Default;
- if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
- if (OCE->isAssignmentOp())
- Order = EvaluationOrder::ForceRightToLeft;
- else {
- switch (OCE->getOperator()) {
- case OO_LessLess:
- case OO_GreaterGreater:
- case OO_AmpAmp:
- case OO_PipePipe:
- case OO_Comma:
- case OO_ArrowStar:
- Order = EvaluationOrder::ForceLeftToRight;
- break;
- default:
- break;
- }
- }
- }
-
- EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), E->arguments(),
- E->getDirectCallee(), /*ParamsToSkip*/ 0, Order);
-
- const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(
- Args, FnType, /*isChainCall=*/Chain);
-
- // C99 6.5.2.2p6:
- // If the expression that denotes the called function has a type
- // that does not include a prototype, [the default argument
- // promotions are performed]. If the number of arguments does not
- // equal the number of parameters, the behavior is undefined. If
- // the function is defined with a type that includes a prototype,
- // and either the prototype ends with an ellipsis (, ...) or the
- // types of the arguments after promotion are not compatible with
- // the types of the parameters, the behavior is undefined. If the
- // function is defined with a type that does not include a
- // prototype, and the types of the arguments after promotion are
- // not compatible with those of the parameters after promotion,
- // the behavior is undefined [except in some trivial cases].
- // That is, in the general case, we should assume that a call
- // through an unprototyped function type works like a *non-variadic*
- // call. The way we make this work is to cast to the exact type
- // of the promoted arguments.
- //
- // Chain calls use this same code path to add the invisible chain parameter
- // to the function type.
- if (isa<FunctionNoProtoType>(FnType) || Chain) {
- llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
- CalleeTy = CalleeTy->getPointerTo();
-
- llvm::Value *CalleePtr = Callee.getFunctionPointer();
- CalleePtr = Builder.CreateBitCast(CalleePtr, CalleeTy, "callee.knr.cast");
- Callee.setFunctionPointer(CalleePtr);
- }
-
- return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr, E->getExprLoc());
-}
-
-LValue CodeGenFunction::
-EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
- Address BaseAddr = Address::invalid();
- if (E->getOpcode() == BO_PtrMemI) {
- BaseAddr = EmitPointerWithAlignment(E->getLHS());
- } else {
- BaseAddr = EmitLValue(E->getLHS()).getAddress();
- }
-
- llvm::Value *OffsetV = EmitScalarExpr(E->getRHS());
-
- const MemberPointerType *MPT
- = E->getRHS()->getType()->getAs<MemberPointerType>();
-
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- Address MemberAddr =
- EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT, &BaseInfo,
- &TBAAInfo);
-
- return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), BaseInfo, TBAAInfo);
-}
-
-/// Given the address of a temporary variable, produce an r-value of
-/// its type.
-RValue CodeGenFunction::convertTempToRValue(Address addr,
- QualType type,
- SourceLocation loc) {
- LValue lvalue = MakeAddrLValue(addr, type, AlignmentSource::Decl);
- switch (getEvaluationKind(type)) {
- case TEK_Complex:
- return RValue::getComplex(EmitLoadOfComplex(lvalue, loc));
- case TEK_Aggregate:
- return lvalue.asAggregateRValue();
- case TEK_Scalar:
- return RValue::get(EmitLoadOfScalar(lvalue, loc));
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, float Accuracy) {
- assert(Val->getType()->isFPOrFPVectorTy());
- if (Accuracy == 0.0 || !isa<llvm::Instruction>(Val))
- return;
-
- llvm::MDBuilder MDHelper(getLLVMContext());
- llvm::MDNode *Node = MDHelper.createFPMath(Accuracy);
-
- cast<llvm::Instruction>(Val)->setMetadata(llvm::LLVMContext::MD_fpmath, Node);
-}
-
-namespace {
- struct LValueOrRValue {
- LValue LV;
- RValue RV;
- };
-}
-
-static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
- const PseudoObjectExpr *E,
- bool forLValue,
- AggValueSlot slot) {
- SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
-
- // Find the result expression, if any.
- const Expr *resultExpr = E->getResultExpr();
- LValueOrRValue result;
-
- for (PseudoObjectExpr::const_semantics_iterator
- i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
- const Expr *semantic = *i;
-
- // If this semantic expression is an opaque value, bind it
- // to the result of its source expression.
- if (const auto *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
- // Skip unique OVEs.
- if (ov->isUnique()) {
- assert(ov != resultExpr &&
- "A unique OVE cannot be used as the result expression");
- continue;
- }
-
- // If this is the result expression, we may need to evaluate
- // directly into the slot.
- typedef CodeGenFunction::OpaqueValueMappingData OVMA;
- OVMA opaqueData;
- if (ov == resultExpr && ov->isRValue() && !forLValue &&
- CodeGenFunction::hasAggregateEvaluationKind(ov->getType())) {
- CGF.EmitAggExpr(ov->getSourceExpr(), slot);
- LValue LV = CGF.MakeAddrLValue(slot.getAddress(), ov->getType(),
- AlignmentSource::Decl);
- opaqueData = OVMA::bind(CGF, ov, LV);
- result.RV = slot.asRValue();
-
- // Otherwise, emit as normal.
- } else {
- opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());
-
- // If this is the result, also evaluate the result now.
- if (ov == resultExpr) {
- if (forLValue)
- result.LV = CGF.EmitLValue(ov);
- else
- result.RV = CGF.EmitAnyExpr(ov, slot);
- }
- }
-
- opaques.push_back(opaqueData);
-
- // Otherwise, if the expression is the result, evaluate it
- // and remember the result.
- } else if (semantic == resultExpr) {
- if (forLValue)
- result.LV = CGF.EmitLValue(semantic);
- else
- result.RV = CGF.EmitAnyExpr(semantic, slot);
-
- // Otherwise, evaluate the expression in an ignored context.
- } else {
- CGF.EmitIgnoredExpr(semantic);
- }
- }
-
- // Unbind all the opaques now.
- for (unsigned i = 0, e = opaques.size(); i != e; ++i)
- opaques[i].unbind(CGF);
-
- return result;
-}
-
-RValue CodeGenFunction::EmitPseudoObjectRValue(const PseudoObjectExpr *E,
- AggValueSlot slot) {
- return emitPseudoObjectExpr(*this, E, false, slot).RV;
-}
-
-LValue CodeGenFunction::EmitPseudoObjectLValue(const PseudoObjectExpr *E) {
- return emitPseudoObjectExpr(*this, E, true, AggValueSlot::ignored()).LV;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp
deleted file mode 100644
index db49b3f28a5..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp
+++ /dev/null
@@ -1,1935 +0,0 @@
-//===--- CGExprAgg.cpp - Emit LLVM Code from Aggregate Expressions --------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Aggregate Expr nodes as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
-#include "CodeGenModule.h"
-#include "ConstantEmitter.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/IntrinsicInst.h"
-using namespace clang;
-using namespace CodeGen;
-
-//===----------------------------------------------------------------------===//
-// Aggregate Expression Emitter
-//===----------------------------------------------------------------------===//
-
-namespace {
-class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
- CodeGenFunction &CGF;
- CGBuilderTy &Builder;
- AggValueSlot Dest;
- bool IsResultUnused;
-
- AggValueSlot EnsureSlot(QualType T) {
- if (!Dest.isIgnored()) return Dest;
- return CGF.CreateAggTemp(T, "agg.tmp.ensured");
- }
- void EnsureDest(QualType T) {
- if (!Dest.isIgnored()) return;
- Dest = CGF.CreateAggTemp(T, "agg.tmp.ensured");
- }
-
- // Calls `Fn` with a valid return value slot, potentially creating a temporary
- // to do so. If a temporary is created, an appropriate copy into `Dest` will
- // be emitted, as will lifetime markers.
- //
- // The given function should take a ReturnValueSlot, and return an RValue that
- // points to said slot.
- void withReturnValueSlot(const Expr *E,
- llvm::function_ref<RValue(ReturnValueSlot)> Fn);
-
-public:
- AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest, bool IsResultUnused)
- : CGF(cgf), Builder(CGF.Builder), Dest(Dest),
- IsResultUnused(IsResultUnused) { }
-
- //===--------------------------------------------------------------------===//
- // Utilities
- //===--------------------------------------------------------------------===//
-
- /// EmitAggLoadOfLValue - Given an expression with aggregate type that
- /// represents a value lvalue, this method emits the address of the lvalue,
- /// then loads the result into DestPtr.
- void EmitAggLoadOfLValue(const Expr *E);
-
- enum ExprValueKind {
- EVK_RValue,
- EVK_NonRValue
- };
-
- /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
- /// SrcIsRValue is true if source comes from an RValue.
- void EmitFinalDestCopy(QualType type, const LValue &src,
- ExprValueKind SrcValueKind = EVK_NonRValue);
- void EmitFinalDestCopy(QualType type, RValue src);
- void EmitCopy(QualType type, const AggValueSlot &dest,
- const AggValueSlot &src);
-
- void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
-
- void EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
- QualType ArrayQTy, InitListExpr *E);
-
- AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
- if (CGF.getLangOpts().getGC() && TypeRequiresGCollection(T))
- return AggValueSlot::NeedsGCBarriers;
- return AggValueSlot::DoesNotNeedGCBarriers;
- }
-
- bool TypeRequiresGCollection(QualType T);
-
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- void Visit(Expr *E) {
- ApplyDebugLocation DL(CGF, E);
- StmtVisitor<AggExprEmitter>::Visit(E);
- }
-
- void VisitStmt(Stmt *S) {
- CGF.ErrorUnsupported(S, "aggregate expression");
- }
- void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
- void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
- Visit(GE->getResultExpr());
- }
- void VisitCoawaitExpr(CoawaitExpr *E) {
- CGF.EmitCoawaitExpr(*E, Dest, IsResultUnused);
- }
- void VisitCoyieldExpr(CoyieldExpr *E) {
- CGF.EmitCoyieldExpr(*E, Dest, IsResultUnused);
- }
- void VisitUnaryCoawait(UnaryOperator *E) { Visit(E->getSubExpr()); }
- void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
- void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
- return Visit(E->getReplacement());
- }
-
- void VisitConstantExpr(ConstantExpr *E) {
- return Visit(E->getSubExpr());
- }
-
- // l-values.
- void VisitDeclRefExpr(DeclRefExpr *E) { EmitAggLoadOfLValue(E); }
- void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
- void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
- void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
- void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
- void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
- EmitAggLoadOfLValue(E);
- }
- void VisitPredefinedExpr(const PredefinedExpr *E) {
- EmitAggLoadOfLValue(E);
- }
-
- // Operators.
- void VisitCastExpr(CastExpr *E);
- void VisitCallExpr(const CallExpr *E);
- void VisitStmtExpr(const StmtExpr *E);
- void VisitBinaryOperator(const BinaryOperator *BO);
- void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO);
- void VisitBinAssign(const BinaryOperator *E);
- void VisitBinComma(const BinaryOperator *E);
- void VisitBinCmp(const BinaryOperator *E);
-
- void VisitObjCMessageExpr(ObjCMessageExpr *E);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
- EmitAggLoadOfLValue(E);
- }
-
- void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E);
- void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
- void VisitChooseExpr(const ChooseExpr *CE);
- void VisitInitListExpr(InitListExpr *E);
- void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
- llvm::Value *outerBegin = nullptr);
- void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
- void VisitNoInitExpr(NoInitExpr *E) { } // Do nothing.
- void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
- Visit(DAE->getExpr());
- }
- void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
- CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
- Visit(DIE->getExpr());
- }
- void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
- void VisitCXXConstructExpr(const CXXConstructExpr *E);
- void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
- void VisitLambdaExpr(LambdaExpr *E);
- void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E);
- void VisitExprWithCleanups(ExprWithCleanups *E);
- void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
- void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
- void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
- void VisitOpaqueValueExpr(OpaqueValueExpr *E);
-
- void VisitPseudoObjectExpr(PseudoObjectExpr *E) {
- if (E->isGLValue()) {
- LValue LV = CGF.EmitPseudoObjectLValue(E);
- return EmitFinalDestCopy(E->getType(), LV);
- }
-
- CGF.EmitPseudoObjectRValue(E, EnsureSlot(E->getType()));
- }
-
- void VisitVAArgExpr(VAArgExpr *E);
-
- void EmitInitializationToLValue(Expr *E, LValue Address);
- void EmitNullInitializationToLValue(LValue Address);
- // case Expr::ChooseExprClass:
- void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
- void VisitAtomicExpr(AtomicExpr *E) {
- RValue Res = CGF.EmitAtomicExpr(E);
- EmitFinalDestCopy(E->getType(), Res);
- }
-};
-} // end anonymous namespace.
-
-//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-/// EmitAggLoadOfLValue - Given an expression with aggregate type that
-/// represents a value lvalue, this method emits the address of the lvalue,
-/// then loads the result into DestPtr.
-void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
- LValue LV = CGF.EmitLValue(E);
-
- // If the type of the l-value is atomic, then do an atomic load.
- if (LV.getType()->isAtomicType() || CGF.LValueIsSuitableForInlineAtomic(LV)) {
- CGF.EmitAtomicLoad(LV, E->getExprLoc(), Dest);
- return;
- }
-
- EmitFinalDestCopy(E->getType(), LV);
-}
-
-/// True if the given aggregate type requires special GC API calls.
-bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
- // Only record types have members that might require garbage collection.
- const RecordType *RecordTy = T->getAs<RecordType>();
- if (!RecordTy) return false;
-
- // Don't mess with non-trivial C++ types.
- RecordDecl *Record = RecordTy->getDecl();
- if (isa<CXXRecordDecl>(Record) &&
- (cast<CXXRecordDecl>(Record)->hasNonTrivialCopyConstructor() ||
- !cast<CXXRecordDecl>(Record)->hasTrivialDestructor()))
- return false;
-
- // Check whether the type has an object member.
- return Record->hasObjectMember();
-}
-
-void AggExprEmitter::withReturnValueSlot(
- const Expr *E, llvm::function_ref<RValue(ReturnValueSlot)> EmitCall) {
- QualType RetTy = E->getType();
- bool RequiresDestruction =
- Dest.isIgnored() &&
- RetTy.isDestructedType() == QualType::DK_nontrivial_c_struct;
-
- // If it makes no observable difference, save a memcpy + temporary.
- //
- // We need to always provide our own temporary if destruction is required.
- // Otherwise, EmitCall will emit its own, notice that it's "unused", and end
- // its lifetime before we have the chance to emit a proper destructor call.
- bool UseTemp = Dest.isPotentiallyAliased() || Dest.requiresGCollection() ||
- (RequiresDestruction && !Dest.getAddress().isValid());
-
- Address RetAddr = Address::invalid();
- Address RetAllocaAddr = Address::invalid();
-
- EHScopeStack::stable_iterator LifetimeEndBlock;
- llvm::Value *LifetimeSizePtr = nullptr;
- llvm::IntrinsicInst *LifetimeStartInst = nullptr;
- if (!UseTemp) {
- RetAddr = Dest.getAddress();
- } else {
- RetAddr = CGF.CreateMemTemp(RetTy, "tmp", &RetAllocaAddr);
- uint64_t Size =
- CGF.CGM.getDataLayout().getTypeAllocSize(CGF.ConvertTypeForMem(RetTy));
- LifetimeSizePtr = CGF.EmitLifetimeStart(Size, RetAllocaAddr.getPointer());
- if (LifetimeSizePtr) {
- LifetimeStartInst =
- cast<llvm::IntrinsicInst>(std::prev(Builder.GetInsertPoint()));
- assert(LifetimeStartInst->getIntrinsicID() ==
- llvm::Intrinsic::lifetime_start &&
- "Last insertion wasn't a lifetime.start?");
-
- CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>(
- NormalEHLifetimeMarker, RetAllocaAddr, LifetimeSizePtr);
- LifetimeEndBlock = CGF.EHStack.stable_begin();
- }
- }
-
- RValue Src =
- EmitCall(ReturnValueSlot(RetAddr, Dest.isVolatile(), IsResultUnused));
-
- if (RequiresDestruction)
- CGF.pushDestroy(RetTy.isDestructedType(), Src.getAggregateAddress(), RetTy);
-
- if (!UseTemp)
- return;
-
- assert(Dest.getPointer() != Src.getAggregatePointer());
- EmitFinalDestCopy(E->getType(), Src);
-
- if (!RequiresDestruction && LifetimeStartInst) {
- // If there's no dtor to run, the copy was the last use of our temporary.
- // Since we're not guaranteed to be in an ExprWithCleanups, clean up
- // eagerly.
- CGF.DeactivateCleanupBlock(LifetimeEndBlock, LifetimeStartInst);
- CGF.EmitLifetimeEnd(LifetimeSizePtr, RetAllocaAddr.getPointer());
- }
-}
-
-/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-void AggExprEmitter::EmitFinalDestCopy(QualType type, RValue src) {
- assert(src.isAggregate() && "value must be aggregate value!");
- LValue srcLV = CGF.MakeAddrLValue(src.getAggregateAddress(), type);
- EmitFinalDestCopy(type, srcLV, EVK_RValue);
-}
-
-/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src,
- ExprValueKind SrcValueKind) {
- // If Dest is ignored, then we're evaluating an aggregate expression
- // in a context that doesn't care about the result. Note that loads
- // from volatile l-values force the existence of a non-ignored
- // destination.
- if (Dest.isIgnored())
- return;
-
- // Copy non-trivial C structs here.
- LValue DstLV = CGF.MakeAddrLValue(
- Dest.getAddress(), Dest.isVolatile() ? type.withVolatile() : type);
-
- if (SrcValueKind == EVK_RValue) {
- if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct) {
- if (Dest.isPotentiallyAliased())
- CGF.callCStructMoveAssignmentOperator(DstLV, src);
- else
- CGF.callCStructMoveConstructor(DstLV, src);
- return;
- }
- } else {
- if (type.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
- if (Dest.isPotentiallyAliased())
- CGF.callCStructCopyAssignmentOperator(DstLV, src);
- else
- CGF.callCStructCopyConstructor(DstLV, src);
- return;
- }
- }
-
- AggValueSlot srcAgg =
- AggValueSlot::forLValue(src, AggValueSlot::IsDestructed,
- needsGC(type), AggValueSlot::IsAliased,
- AggValueSlot::MayOverlap);
- EmitCopy(type, Dest, srcAgg);
-}
-
-/// Perform a copy from the source into the destination.
-///
-/// \param type - the type of the aggregate being copied; qualifiers are
-/// ignored
-void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest,
- const AggValueSlot &src) {
- if (dest.requiresGCollection()) {
- CharUnits sz = dest.getPreferredSize(CGF.getContext(), type);
- llvm::Value *size = llvm::ConstantInt::get(CGF.SizeTy, sz.getQuantity());
- CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
- dest.getAddress(),
- src.getAddress(),
- size);
- return;
- }
-
- // If the result of the assignment is used, copy the LHS there also.
- // It's volatile if either side is. Use the minimum alignment of
- // the two sides.
- LValue DestLV = CGF.MakeAddrLValue(dest.getAddress(), type);
- LValue SrcLV = CGF.MakeAddrLValue(src.getAddress(), type);
- CGF.EmitAggregateCopy(DestLV, SrcLV, type, dest.mayOverlap(),
- dest.isVolatile() || src.isVolatile());
-}
-
-/// Emit the initializer for a std::initializer_list initialized with a
-/// real initializer list.
-void
-AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
- // Emit an array containing the elements. The array is externally destructed
- // if the std::initializer_list object is.
- ASTContext &Ctx = CGF.getContext();
- LValue Array = CGF.EmitLValue(E->getSubExpr());
- assert(Array.isSimple() && "initializer_list array not a simple lvalue");
- Address ArrayPtr = Array.getAddress();
-
- const ConstantArrayType *ArrayType =
- Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
- assert(ArrayType && "std::initializer_list constructed from non-array");
-
- // FIXME: Perform the checks on the field types in SemaInit.
- RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
- RecordDecl::field_iterator Field = Record->field_begin();
- if (Field == Record->field_end()) {
- CGF.ErrorUnsupported(E, "weird std::initializer_list");
- return;
- }
-
- // Start pointer.
- if (!Field->getType()->isPointerType() ||
- !Ctx.hasSameType(Field->getType()->getPointeeType(),
- ArrayType->getElementType())) {
- CGF.ErrorUnsupported(E, "weird std::initializer_list");
- return;
- }
-
- AggValueSlot Dest = EnsureSlot(E->getType());
- LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
- LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
- llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
- llvm::Value *IdxStart[] = { Zero, Zero };
- llvm::Value *ArrayStart =
- Builder.CreateInBoundsGEP(ArrayPtr.getPointer(), IdxStart, "arraystart");
- CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start);
- ++Field;
-
- if (Field == Record->field_end()) {
- CGF.ErrorUnsupported(E, "weird std::initializer_list");
- return;
- }
-
- llvm::Value *Size = Builder.getInt(ArrayType->getSize());
- LValue EndOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
- if (Field->getType()->isPointerType() &&
- Ctx.hasSameType(Field->getType()->getPointeeType(),
- ArrayType->getElementType())) {
- // End pointer.
- llvm::Value *IdxEnd[] = { Zero, Size };
- llvm::Value *ArrayEnd =
- Builder.CreateInBoundsGEP(ArrayPtr.getPointer(), IdxEnd, "arrayend");
- CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength);
- } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
- // Length.
- CGF.EmitStoreThroughLValue(RValue::get(Size), EndOrLength);
- } else {
- CGF.ErrorUnsupported(E, "weird std::initializer_list");
- return;
- }
-}
-
-/// Determine if E is a trivial array filler, that is, one that is
-/// equivalent to zero-initialization.
-static bool isTrivialFiller(Expr *E) {
- if (!E)
- return true;
-
- if (isa<ImplicitValueInitExpr>(E))
- return true;
-
- if (auto *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->getNumInits())
- return false;
- return isTrivialFiller(ILE->getArrayFiller());
- }
-
- if (auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
- return Cons->getConstructor()->isDefaultConstructor() &&
- Cons->getConstructor()->isTrivial();
-
- // FIXME: Are there other cases where we can avoid emitting an initializer?
- return false;
-}
-
-/// Emit initialization of an array from an initializer list.
-void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
- QualType ArrayQTy, InitListExpr *E) {
- uint64_t NumInitElements = E->getNumInits();
-
- uint64_t NumArrayElements = AType->getNumElements();
- assert(NumInitElements <= NumArrayElements);
-
- QualType elementType =
- CGF.getContext().getAsArrayType(ArrayQTy)->getElementType();
-
- // DestPtr is an array*. Construct an elementType* by drilling
- // down a level.
- llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
- llvm::Value *indices[] = { zero, zero };
- llvm::Value *begin =
- Builder.CreateInBoundsGEP(DestPtr.getPointer(), indices, "arrayinit.begin");
-
- CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
- CharUnits elementAlign =
- DestPtr.getAlignment().alignmentOfArrayElement(elementSize);
-
- // Consider initializing the array by copying from a global. For this to be
- // more efficient than per-element initialization, the size of the elements
- // with explicit initializers should be large enough.
- if (NumInitElements * elementSize.getQuantity() > 16 &&
- elementType.isTriviallyCopyableType(CGF.getContext())) {
- CodeGen::CodeGenModule &CGM = CGF.CGM;
- ConstantEmitter Emitter(CGM);
- LangAS AS = ArrayQTy.getAddressSpace();
- if (llvm::Constant *C = Emitter.tryEmitForInitializer(E, AS, ArrayQTy)) {
- auto GV = new llvm::GlobalVariable(
- CGM.getModule(), C->getType(),
- CGM.isTypeConstant(ArrayQTy, /* ExcludeCtorDtor= */ true),
- llvm::GlobalValue::PrivateLinkage, C, "constinit",
- /* InsertBefore= */ nullptr, llvm::GlobalVariable::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(AS));
- Emitter.finalize(GV);
- CharUnits Align = CGM.getContext().getTypeAlignInChars(ArrayQTy);
- GV->setAlignment(Align.getQuantity());
- EmitFinalDestCopy(ArrayQTy, CGF.MakeAddrLValue(GV, ArrayQTy, Align));
- return;
- }
- }
-
- // Exception safety requires us to destroy all the
- // already-constructed members if an initializer throws.
- // For that, we'll need an EH cleanup.
- QualType::DestructionKind dtorKind = elementType.isDestructedType();
- Address endOfInit = Address::invalid();
- EHScopeStack::stable_iterator cleanup;
- llvm::Instruction *cleanupDominator = nullptr;
- if (CGF.needsEHCleanup(dtorKind)) {
- // In principle we could tell the cleanup where we are more
- // directly, but the control flow can get so varied here that it
- // would actually be quite complex. Therefore we go through an
- // alloca.
- endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(),
- "arrayinit.endOfInit");
- cleanupDominator = Builder.CreateStore(begin, endOfInit);
- CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
- elementAlign,
- CGF.getDestroyer(dtorKind));
- cleanup = CGF.EHStack.stable_begin();
-
- // Otherwise, remember that we didn't need a cleanup.
- } else {
- dtorKind = QualType::DK_none;
- }
-
- llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
-
- // The 'current element to initialize'. The invariants on this
- // variable are complicated. Essentially, after each iteration of
- // the loop, it points to the last initialized element, except
- // that it points to the beginning of the array before any
- // elements have been initialized.
- llvm::Value *element = begin;
-
- // Emit the explicit initializers.
- for (uint64_t i = 0; i != NumInitElements; ++i) {
- // Advance to the next element.
- if (i > 0) {
- element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element");
-
- // Tell the cleanup that it needs to destroy up to this
- // element. TODO: some of these stores can be trivially
- // observed to be unnecessary.
- if (endOfInit.isValid()) Builder.CreateStore(element, endOfInit);
- }
-
- LValue elementLV =
- CGF.MakeAddrLValue(Address(element, elementAlign), elementType);
- EmitInitializationToLValue(E->getInit(i), elementLV);
- }
-
- // Check whether there's a non-trivial array-fill expression.
- Expr *filler = E->getArrayFiller();
- bool hasTrivialFiller = isTrivialFiller(filler);
-
- // Any remaining elements need to be zero-initialized, possibly
- // using the filler expression. We can skip this if the we're
- // emitting to zeroed memory.
- if (NumInitElements != NumArrayElements &&
- !(Dest.isZeroed() && hasTrivialFiller &&
- CGF.getTypes().isZeroInitializable(elementType))) {
-
- // Use an actual loop. This is basically
- // do { *array++ = filler; } while (array != end);
-
- // Advance to the start of the rest of the array.
- if (NumInitElements) {
- element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start");
- if (endOfInit.isValid()) Builder.CreateStore(element, endOfInit);
- }
-
- // Compute the end of the array.
- llvm::Value *end = Builder.CreateInBoundsGEP(begin,
- llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements),
- "arrayinit.end");
-
- llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
- llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
-
- // Jump into the body.
- CGF.EmitBlock(bodyBB);
- llvm::PHINode *currentElement =
- Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
- currentElement->addIncoming(element, entryBB);
-
- // Emit the actual filler expression.
- {
- // C++1z [class.temporary]p5:
- // when a default constructor is called to initialize an element of
- // an array with no corresponding initializer [...] the destruction of
- // every temporary created in a default argument is sequenced before
- // the construction of the next array element, if any
- CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
- LValue elementLV =
- CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
- if (filler)
- EmitInitializationToLValue(filler, elementLV);
- else
- EmitNullInitializationToLValue(elementLV);
- }
-
- // Move on to the next element.
- llvm::Value *nextElement =
- Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next");
-
- // Tell the EH cleanup that we finished with the last element.
- if (endOfInit.isValid()) Builder.CreateStore(nextElement, endOfInit);
-
- // Leave the loop if we're done.
- llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
- "arrayinit.done");
- llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
- Builder.CreateCondBr(done, endBB, bodyBB);
- currentElement->addIncoming(nextElement, Builder.GetInsertBlock());
-
- CGF.EmitBlock(endBB);
- }
-
- // Leave the partial-array cleanup if we entered one.
- if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
-}
-
-//===----------------------------------------------------------------------===//
-// Visitor Methods
-//===----------------------------------------------------------------------===//
-
-void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){
- Visit(E->GetTemporaryExpr());
-}
-
-void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
- // If this is a unique OVE, just visit its source expression.
- if (e->isUnique())
- Visit(e->getSourceExpr());
- else
- EmitFinalDestCopy(e->getType(), CGF.getOrCreateOpaqueLValueMapping(e));
-}
-
-void
-AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- if (Dest.isPotentiallyAliased() &&
- E->getType().isPODType(CGF.getContext())) {
- // For a POD type, just emit a load of the lvalue + a copy, because our
- // compound literal might alias the destination.
- EmitAggLoadOfLValue(E);
- return;
- }
-
- AggValueSlot Slot = EnsureSlot(E->getType());
- CGF.EmitAggExpr(E->getInitializer(), Slot);
-}
-
-/// Attempt to look through various unimportant expressions to find a
-/// cast of the given kind.
-static Expr *findPeephole(Expr *op, CastKind kind) {
- while (true) {
- op = op->IgnoreParens();
- if (CastExpr *castE = dyn_cast<CastExpr>(op)) {
- if (castE->getCastKind() == kind)
- return castE->getSubExpr();
- if (castE->getCastKind() == CK_NoOp)
- continue;
- }
- return nullptr;
- }
-}
-
-void AggExprEmitter::VisitCastExpr(CastExpr *E) {
- if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
- CGF.CGM.EmitExplicitCastExprType(ECE, &CGF);
- switch (E->getCastKind()) {
- case CK_Dynamic: {
- // FIXME: Can this actually happen? We have no test coverage for it.
- assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
- LValue LV = CGF.EmitCheckedLValue(E->getSubExpr(),
- CodeGenFunction::TCK_Load);
- // FIXME: Do we also need to handle property references here?
- if (LV.isSimple())
- CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
- else
- CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast");
-
- if (!Dest.isIgnored())
- CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination");
- break;
- }
-
- case CK_ToUnion: {
- // Evaluate even if the destination is ignored.
- if (Dest.isIgnored()) {
- CGF.EmitAnyExpr(E->getSubExpr(), AggValueSlot::ignored(),
- /*ignoreResult=*/true);
- break;
- }
-
- // GCC union extension
- QualType Ty = E->getSubExpr()->getType();
- Address CastPtr =
- Builder.CreateElementBitCast(Dest.getAddress(), CGF.ConvertType(Ty));
- EmitInitializationToLValue(E->getSubExpr(),
- CGF.MakeAddrLValue(CastPtr, Ty));
- break;
- }
-
- case CK_DerivedToBase:
- case CK_BaseToDerived:
- case CK_UncheckedDerivedToBase: {
- llvm_unreachable("cannot perform hierarchy conversion in EmitAggExpr: "
- "should have been unpacked before we got here");
- }
-
- case CK_NonAtomicToAtomic:
- case CK_AtomicToNonAtomic: {
- bool isToAtomic = (E->getCastKind() == CK_NonAtomicToAtomic);
-
- // Determine the atomic and value types.
- QualType atomicType = E->getSubExpr()->getType();
- QualType valueType = E->getType();
- if (isToAtomic) std::swap(atomicType, valueType);
-
- assert(atomicType->isAtomicType());
- assert(CGF.getContext().hasSameUnqualifiedType(valueType,
- atomicType->castAs<AtomicType>()->getValueType()));
-
- // Just recurse normally if we're ignoring the result or the
- // atomic type doesn't change representation.
- if (Dest.isIgnored() || !CGF.CGM.isPaddedAtomicType(atomicType)) {
- return Visit(E->getSubExpr());
- }
-
- CastKind peepholeTarget =
- (isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
-
- // These two cases are reverses of each other; try to peephole them.
- if (Expr *op = findPeephole(E->getSubExpr(), peepholeTarget)) {
- assert(CGF.getContext().hasSameUnqualifiedType(op->getType(),
- E->getType()) &&
- "peephole significantly changed types?");
- return Visit(op);
- }
-
- // If we're converting an r-value of non-atomic type to an r-value
- // of atomic type, just emit directly into the relevant sub-object.
- if (isToAtomic) {
- AggValueSlot valueDest = Dest;
- if (!valueDest.isIgnored() && CGF.CGM.isPaddedAtomicType(atomicType)) {
- // Zero-initialize. (Strictly speaking, we only need to initialize
- // the padding at the end, but this is simpler.)
- if (!Dest.isZeroed())
- CGF.EmitNullInitialization(Dest.getAddress(), atomicType);
-
- // Build a GEP to refer to the subobject.
- Address valueAddr =
- CGF.Builder.CreateStructGEP(valueDest.getAddress(), 0,
- CharUnits());
- valueDest = AggValueSlot::forAddr(valueAddr,
- valueDest.getQualifiers(),
- valueDest.isExternallyDestructed(),
- valueDest.requiresGCollection(),
- valueDest.isPotentiallyAliased(),
- AggValueSlot::DoesNotOverlap,
- AggValueSlot::IsZeroed);
- }
-
- CGF.EmitAggExpr(E->getSubExpr(), valueDest);
- return;
- }
-
- // Otherwise, we're converting an atomic type to a non-atomic type.
- // Make an atomic temporary, emit into that, and then copy the value out.
- AggValueSlot atomicSlot =
- CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
- CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
-
- Address valueAddr =
- Builder.CreateStructGEP(atomicSlot.getAddress(), 0, CharUnits());
- RValue rvalue = RValue::getAggregate(valueAddr, atomicSlot.isVolatile());
- return EmitFinalDestCopy(valueType, rvalue);
- }
-
- case CK_LValueToRValue:
- // If we're loading from a volatile type, force the destination
- // into existence.
- if (E->getSubExpr()->getType().isVolatileQualified()) {
- EnsureDest(E->getType());
- return Visit(E->getSubExpr());
- }
-
- LLVM_FALLTHROUGH;
-
- case CK_NoOp:
- case CK_UserDefinedConversion:
- case CK_ConstructorConversion:
- assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
- E->getType()) &&
- "Implicit cast types must be compatible");
- Visit(E->getSubExpr());
- break;
-
- case CK_LValueBitCast:
- llvm_unreachable("should not be emitting lvalue bitcast as rvalue");
-
- case CK_Dependent:
- case CK_BitCast:
- case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
- case CK_NullToPointer:
- case CK_NullToMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_MemberPointerToBoolean:
- case CK_ReinterpretMemberPointer:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
- case CK_ToVoid:
- case CK_VectorSplat:
- case CK_IntegralCast:
- case CK_BooleanToSignedIntegral:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCObjectLValueCast:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_ARCProduceObject:
- case CK_ARCConsumeObject:
- case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject:
- case CK_CopyAndAutoreleaseBlockObject:
- case CK_BuiltinFnToFnPtr:
- case CK_ZeroToOCLOpaqueType:
- case CK_AddressSpaceConversion:
- case CK_IntToOCLSampler:
- case CK_FixedPointCast:
- case CK_FixedPointToBoolean:
- llvm_unreachable("cast kind invalid for aggregate types");
- }
-}
-
-void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
- if (E->getCallReturnType(CGF.getContext())->isReferenceType()) {
- EmitAggLoadOfLValue(E);
- return;
- }
-
- withReturnValueSlot(E, [&](ReturnValueSlot Slot) {
- return CGF.EmitCallExpr(E, Slot);
- });
-}
-
-void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
- withReturnValueSlot(E, [&](ReturnValueSlot Slot) {
- return CGF.EmitObjCMessageExpr(E, Slot);
- });
-}
-
-void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
- CGF.EmitIgnoredExpr(E->getLHS());
- Visit(E->getRHS());
-}
-
-void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
- CodeGenFunction::StmtExprEvaluation eval(CGF);
- CGF.EmitCompoundStmt(*E->getSubStmt(), true, Dest);
-}
-
-enum CompareKind {
- CK_Less,
- CK_Greater,
- CK_Equal,
-};
-
-static llvm::Value *EmitCompare(CGBuilderTy &Builder, CodeGenFunction &CGF,
- const BinaryOperator *E, llvm::Value *LHS,
- llvm::Value *RHS, CompareKind Kind,
- const char *NameSuffix = "") {
- QualType ArgTy = E->getLHS()->getType();
- if (const ComplexType *CT = ArgTy->getAs<ComplexType>())
- ArgTy = CT->getElementType();
-
- if (const auto *MPT = ArgTy->getAs<MemberPointerType>()) {
- assert(Kind == CK_Equal &&
- "member pointers may only be compared for equality");
- return CGF.CGM.getCXXABI().EmitMemberPointerComparison(
- CGF, LHS, RHS, MPT, /*IsInequality*/ false);
- }
-
- // Compute the comparison instructions for the specified comparison kind.
- struct CmpInstInfo {
- const char *Name;
- llvm::CmpInst::Predicate FCmp;
- llvm::CmpInst::Predicate SCmp;
- llvm::CmpInst::Predicate UCmp;
- };
- CmpInstInfo InstInfo = [&]() -> CmpInstInfo {
- using FI = llvm::FCmpInst;
- using II = llvm::ICmpInst;
- switch (Kind) {
- case CK_Less:
- return {"cmp.lt", FI::FCMP_OLT, II::ICMP_SLT, II::ICMP_ULT};
- case CK_Greater:
- return {"cmp.gt", FI::FCMP_OGT, II::ICMP_SGT, II::ICMP_UGT};
- case CK_Equal:
- return {"cmp.eq", FI::FCMP_OEQ, II::ICMP_EQ, II::ICMP_EQ};
- }
- llvm_unreachable("Unrecognised CompareKind enum");
- }();
-
- if (ArgTy->hasFloatingRepresentation())
- return Builder.CreateFCmp(InstInfo.FCmp, LHS, RHS,
- llvm::Twine(InstInfo.Name) + NameSuffix);
- if (ArgTy->isIntegralOrEnumerationType() || ArgTy->isPointerType()) {
- auto Inst =
- ArgTy->hasSignedIntegerRepresentation() ? InstInfo.SCmp : InstInfo.UCmp;
- return Builder.CreateICmp(Inst, LHS, RHS,
- llvm::Twine(InstInfo.Name) + NameSuffix);
- }
-
- llvm_unreachable("unsupported aggregate binary expression should have "
- "already been handled");
-}
-
-void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
- using llvm::BasicBlock;
- using llvm::PHINode;
- using llvm::Value;
- assert(CGF.getContext().hasSameType(E->getLHS()->getType(),
- E->getRHS()->getType()));
- const ComparisonCategoryInfo &CmpInfo =
- CGF.getContext().CompCategories.getInfoForType(E->getType());
- assert(CmpInfo.Record->isTriviallyCopyable() &&
- "cannot copy non-trivially copyable aggregate");
-
- QualType ArgTy = E->getLHS()->getType();
-
- // TODO: Handle comparing these types.
- if (ArgTy->isVectorType())
- return CGF.ErrorUnsupported(
- E, "aggregate three-way comparison with vector arguments");
- if (!ArgTy->isIntegralOrEnumerationType() && !ArgTy->isRealFloatingType() &&
- !ArgTy->isNullPtrType() && !ArgTy->isPointerType() &&
- !ArgTy->isMemberPointerType() && !ArgTy->isAnyComplexType()) {
- return CGF.ErrorUnsupported(E, "aggregate three-way comparison");
- }
- bool IsComplex = ArgTy->isAnyComplexType();
-
- // Evaluate the operands to the expression and extract their values.
- auto EmitOperand = [&](Expr *E) -> std::pair<Value *, Value *> {
- RValue RV = CGF.EmitAnyExpr(E);
- if (RV.isScalar())
- return {RV.getScalarVal(), nullptr};
- if (RV.isAggregate())
- return {RV.getAggregatePointer(), nullptr};
- assert(RV.isComplex());
- return RV.getComplexVal();
- };
- auto LHSValues = EmitOperand(E->getLHS()),
- RHSValues = EmitOperand(E->getRHS());
-
- auto EmitCmp = [&](CompareKind K) {
- Value *Cmp = EmitCompare(Builder, CGF, E, LHSValues.first, RHSValues.first,
- K, IsComplex ? ".r" : "");
- if (!IsComplex)
- return Cmp;
- assert(K == CompareKind::CK_Equal);
- Value *CmpImag = EmitCompare(Builder, CGF, E, LHSValues.second,
- RHSValues.second, K, ".i");
- return Builder.CreateAnd(Cmp, CmpImag, "and.eq");
- };
- auto EmitCmpRes = [&](const ComparisonCategoryInfo::ValueInfo *VInfo) {
- return Builder.getInt(VInfo->getIntValue());
- };
-
- Value *Select;
- if (ArgTy->isNullPtrType()) {
- Select = EmitCmpRes(CmpInfo.getEqualOrEquiv());
- } else if (CmpInfo.isEquality()) {
- Select = Builder.CreateSelect(
- EmitCmp(CK_Equal), EmitCmpRes(CmpInfo.getEqualOrEquiv()),
- EmitCmpRes(CmpInfo.getNonequalOrNonequiv()), "sel.eq");
- } else if (!CmpInfo.isPartial()) {
- Value *SelectOne =
- Builder.CreateSelect(EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()),
- EmitCmpRes(CmpInfo.getGreater()), "sel.lt");
- Select = Builder.CreateSelect(EmitCmp(CK_Equal),
- EmitCmpRes(CmpInfo.getEqualOrEquiv()),
- SelectOne, "sel.eq");
- } else {
- Value *SelectEq = Builder.CreateSelect(
- EmitCmp(CK_Equal), EmitCmpRes(CmpInfo.getEqualOrEquiv()),
- EmitCmpRes(CmpInfo.getUnordered()), "sel.eq");
- Value *SelectGT = Builder.CreateSelect(EmitCmp(CK_Greater),
- EmitCmpRes(CmpInfo.getGreater()),
- SelectEq, "sel.gt");
- Select = Builder.CreateSelect(
- EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()), SelectGT, "sel.lt");
- }
- // Create the return value in the destination slot.
- EnsureDest(E->getType());
- LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
-
- // Emit the address of the first (and only) field in the comparison category
- // type, and initialize it from the constant integer value selected above.
- LValue FieldLV = CGF.EmitLValueForFieldInitialization(
- DestLV, *CmpInfo.Record->field_begin());
- CGF.EmitStoreThroughLValue(RValue::get(Select), FieldLV, /*IsInit*/ true);
-
- // All done! The result is in the Dest slot.
-}
-
-void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() == BO_PtrMemD || E->getOpcode() == BO_PtrMemI)
- VisitPointerToDataMemberBinaryOperator(E);
- else
- CGF.ErrorUnsupported(E, "aggregate binary expression");
-}
-
-void AggExprEmitter::VisitPointerToDataMemberBinaryOperator(
- const BinaryOperator *E) {
- LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(E);
- EmitFinalDestCopy(E->getType(), LV);
-}
-
-/// Is the value of the given expression possibly a reference to or
-/// into a __block variable?
-static bool isBlockVarRef(const Expr *E) {
- // Make sure we look through parens.
- E = E->IgnoreParens();
-
- // Check for a direct reference to a __block variable.
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- const VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl());
- return (var && var->hasAttr<BlocksAttr>());
- }
-
- // More complicated stuff.
-
- // Binary operators.
- if (const BinaryOperator *op = dyn_cast<BinaryOperator>(E)) {
- // For an assignment or pointer-to-member operation, just care
- // about the LHS.
- if (op->isAssignmentOp() || op->isPtrMemOp())
- return isBlockVarRef(op->getLHS());
-
- // For a comma, just care about the RHS.
- if (op->getOpcode() == BO_Comma)
- return isBlockVarRef(op->getRHS());
-
- // FIXME: pointer arithmetic?
- return false;
-
- // Check both sides of a conditional operator.
- } else if (const AbstractConditionalOperator *op
- = dyn_cast<AbstractConditionalOperator>(E)) {
- return isBlockVarRef(op->getTrueExpr())
- || isBlockVarRef(op->getFalseExpr());
-
- // OVEs are required to support BinaryConditionalOperators.
- } else if (const OpaqueValueExpr *op
- = dyn_cast<OpaqueValueExpr>(E)) {
- if (const Expr *src = op->getSourceExpr())
- return isBlockVarRef(src);
-
- // Casts are necessary to get things like (*(int*)&var) = foo().
- // We don't really care about the kind of cast here, except
- // we don't want to look through l2r casts, because it's okay
- // to get the *value* in a __block variable.
- } else if (const CastExpr *cast = dyn_cast<CastExpr>(E)) {
- if (cast->getCastKind() == CK_LValueToRValue)
- return false;
- return isBlockVarRef(cast->getSubExpr());
-
- // Handle unary operators. Again, just aggressively look through
- // it, ignoring the operation.
- } else if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E)) {
- return isBlockVarRef(uop->getSubExpr());
-
- // Look into the base of a field access.
- } else if (const MemberExpr *mem = dyn_cast<MemberExpr>(E)) {
- return isBlockVarRef(mem->getBase());
-
- // Look into the base of a subscript.
- } else if (const ArraySubscriptExpr *sub = dyn_cast<ArraySubscriptExpr>(E)) {
- return isBlockVarRef(sub->getBase());
- }
-
- return false;
-}
-
-void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
- // For an assignment to work, the value on the right has
- // to be compatible with the value on the left.
- assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
- E->getRHS()->getType())
- && "Invalid assignment");
-
- // If the LHS might be a __block variable, and the RHS can
- // potentially cause a block copy, we need to evaluate the RHS first
- // so that the assignment goes the right place.
- // This is pretty semantically fragile.
- if (isBlockVarRef(E->getLHS()) &&
- E->getRHS()->HasSideEffects(CGF.getContext())) {
- // Ensure that we have a destination, and evaluate the RHS into that.
- EnsureDest(E->getRHS()->getType());
- Visit(E->getRHS());
-
- // Now emit the LHS and copy into it.
- LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
-
- // That copy is an atomic copy if the LHS is atomic.
- if (LHS.getType()->isAtomicType() ||
- CGF.LValueIsSuitableForInlineAtomic(LHS)) {
- CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
- return;
- }
-
- EmitCopy(E->getLHS()->getType(),
- AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
- needsGC(E->getLHS()->getType()),
- AggValueSlot::IsAliased,
- AggValueSlot::MayOverlap),
- Dest);
- return;
- }
-
- LValue LHS = CGF.EmitLValue(E->getLHS());
-
- // If we have an atomic type, evaluate into the destination and then
- // do an atomic copy.
- if (LHS.getType()->isAtomicType() ||
- CGF.LValueIsSuitableForInlineAtomic(LHS)) {
- EnsureDest(E->getRHS()->getType());
- Visit(E->getRHS());
- CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
- return;
- }
-
- // Codegen the RHS so that it stores directly into the LHS.
- AggValueSlot LHSSlot =
- AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
- needsGC(E->getLHS()->getType()),
- AggValueSlot::IsAliased,
- AggValueSlot::MayOverlap);
- // A non-volatile aggregate destination might have volatile member.
- if (!LHSSlot.isVolatile() &&
- CGF.hasVolatileMember(E->getLHS()->getType()))
- LHSSlot.setVolatile(true);
-
- CGF.EmitAggExpr(E->getRHS(), LHSSlot);
-
- // Copy into the destination if the assignment isn't ignored.
- EmitFinalDestCopy(E->getType(), LHS);
-}
-
-void AggExprEmitter::
-VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
- llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
- llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
-
- // Bind the common expression if necessary.
- CodeGenFunction::OpaqueValueMapping binding(CGF, E);
-
- CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock,
- CGF.getProfileCount(E));
-
- // Save whether the destination's lifetime is externally managed.
- bool isExternallyDestructed = Dest.isExternallyDestructed();
-
- eval.begin(CGF);
- CGF.EmitBlock(LHSBlock);
- CGF.incrementProfileCounter(E);
- Visit(E->getTrueExpr());
- eval.end(CGF);
-
- assert(CGF.HaveInsertPoint() && "expression evaluation ended with no IP!");
- CGF.Builder.CreateBr(ContBlock);
-
- // If the result of an agg expression is unused, then the emission
- // of the LHS might need to create a destination slot. That's fine
- // with us, and we can safely emit the RHS into the same slot, but
- // we shouldn't claim that it's already being destructed.
- Dest.setExternallyDestructed(isExternallyDestructed);
-
- eval.begin(CGF);
- CGF.EmitBlock(RHSBlock);
- Visit(E->getFalseExpr());
- eval.end(CGF);
-
- CGF.EmitBlock(ContBlock);
-}
-
-void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
- Visit(CE->getChosenSubExpr());
-}
-
-void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
- Address ArgValue = Address::invalid();
- Address ArgPtr = CGF.EmitVAArg(VE, ArgValue);
-
- // If EmitVAArg fails, emit an error.
- if (!ArgPtr.isValid()) {
- CGF.ErrorUnsupported(VE, "aggregate va_arg expression");
- return;
- }
-
- EmitFinalDestCopy(VE->getType(), CGF.MakeAddrLValue(ArgPtr, VE->getType()));
-}
-
-void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
- // Ensure that we have a slot, but if we already do, remember
- // whether it was externally destructed.
- bool wasExternallyDestructed = Dest.isExternallyDestructed();
- EnsureDest(E->getType());
-
- // We're going to push a destructor if there isn't already one.
- Dest.setExternallyDestructed();
-
- Visit(E->getSubExpr());
-
- // Push that destructor we promised.
- if (!wasExternallyDestructed)
- CGF.EmitCXXTemporary(E->getTemporary(), E->getType(), Dest.getAddress());
-}
-
-void
-AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
- AggValueSlot Slot = EnsureSlot(E->getType());
- CGF.EmitCXXConstructExpr(E, Slot);
-}
-
-void AggExprEmitter::VisitCXXInheritedCtorInitExpr(
- const CXXInheritedCtorInitExpr *E) {
- AggValueSlot Slot = EnsureSlot(E->getType());
- CGF.EmitInheritedCXXConstructorCall(
- E->getConstructor(), E->constructsVBase(), Slot.getAddress(),
- E->inheritedFromVBase(), E);
-}
-
-void
-AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
- AggValueSlot Slot = EnsureSlot(E->getType());
- CGF.EmitLambdaExpr(E, Slot);
-}
-
-void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
- CGF.enterFullExpression(E);
- CodeGenFunction::RunCleanupsScope cleanups(CGF);
- Visit(E->getSubExpr());
-}
-
-void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
- QualType T = E->getType();
- AggValueSlot Slot = EnsureSlot(T);
- EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddress(), T));
-}
-
-void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
- QualType T = E->getType();
- AggValueSlot Slot = EnsureSlot(T);
- EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddress(), T));
-}
-
-/// isSimpleZero - If emitting this value will obviously just cause a store of
-/// zero to memory, return true. This can return false if uncertain, so it just
-/// handles simple cases.
-static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
- E = E->IgnoreParens();
-
- // 0
- if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
- return IL->getValue() == 0;
- // +0.0
- if (const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(E))
- return FL->getValue().isPosZero();
- // int()
- if ((isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) &&
- CGF.getTypes().isZeroInitializable(E->getType()))
- return true;
- // (int*)0 - Null pointer expressions.
- if (const CastExpr *ICE = dyn_cast<CastExpr>(E))
- return ICE->getCastKind() == CK_NullToPointer &&
- CGF.getTypes().isPointerZeroInitializable(E->getType());
- // '\0'
- if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E))
- return CL->getValue() == 0;
-
- // Otherwise, hard case: conservatively return false.
- return false;
-}
-
-
-void
-AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
- QualType type = LV.getType();
- // FIXME: Ignore result?
- // FIXME: Are initializers affected by volatile?
- if (Dest.isZeroed() && isSimpleZero(E, CGF)) {
- // Storing "i32 0" to a zero'd memory location is a noop.
- return;
- } else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
- return EmitNullInitializationToLValue(LV);
- } else if (isa<NoInitExpr>(E)) {
- // Do nothing.
- return;
- } else if (type->isReferenceType()) {
- RValue RV = CGF.EmitReferenceBindingToExpr(E);
- return CGF.EmitStoreThroughLValue(RV, LV);
- }
-
- switch (CGF.getEvaluationKind(type)) {
- case TEK_Complex:
- CGF.EmitComplexExprIntoLValue(E, LV, /*isInit*/ true);
- return;
- case TEK_Aggregate:
- CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::MayOverlap,
- Dest.isZeroed()));
- return;
- case TEK_Scalar:
- if (LV.isSimple()) {
- CGF.EmitScalarInit(E, /*D=*/nullptr, LV, /*Captured=*/false);
- } else {
- CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
- }
- return;
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
- QualType type = lv.getType();
-
- // If the destination slot is already zeroed out before the aggregate is
- // copied into it, we don't have to emit any zeros here.
- if (Dest.isZeroed() && CGF.getTypes().isZeroInitializable(type))
- return;
-
- if (CGF.hasScalarEvaluationKind(type)) {
- // For non-aggregates, we can store the appropriate null constant.
- llvm::Value *null = CGF.CGM.EmitNullConstant(type);
- // Note that the following is not equivalent to
- // EmitStoreThroughBitfieldLValue for ARC types.
- if (lv.isBitField()) {
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(null), lv);
- } else {
- assert(lv.isSimple());
- CGF.EmitStoreOfScalar(null, lv, /* isInitialization */ true);
- }
- } else {
- // There's a potential optimization opportunity in combining
- // memsets; that would be easy for arrays, but relatively
- // difficult for structures with the current code.
- CGF.EmitNullInitialization(lv.getAddress(), lv.getType());
- }
-}
-
-void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
-#if 0
- // FIXME: Assess perf here? Figure out what cases are worth optimizing here
- // (Length of globals? Chunks of zeroed-out space?).
- //
- // If we can, prefer a copy from a global; this is a lot less code for long
- // globals, and it's easier for the current optimizers to analyze.
- if (llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, E->getType(), &CGF)) {
- llvm::GlobalVariable* GV =
- new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true,
- llvm::GlobalValue::InternalLinkage, C, "");
- EmitFinalDestCopy(E->getType(), CGF.MakeAddrLValue(GV, E->getType()));
- return;
- }
-#endif
- if (E->hadArrayRangeDesignator())
- CGF.ErrorUnsupported(E, "GNU array range designator extension");
-
- if (E->isTransparent())
- return Visit(E->getInit(0));
-
- AggValueSlot Dest = EnsureSlot(E->getType());
-
- LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
-
- // Handle initialization of an array.
- if (E->getType()->isArrayType()) {
- auto AType = cast<llvm::ArrayType>(Dest.getAddress().getElementType());
- EmitArrayInit(Dest.getAddress(), AType, E->getType(), E);
- return;
- }
-
- assert(E->getType()->isRecordType() && "Only support structs/unions here!");
-
- // Do struct initialization; this code just sets each individual member
- // to the approprate value. This makes bitfield support automatic;
- // the disadvantage is that the generated code is more difficult for
- // the optimizer, especially with bitfields.
- unsigned NumInitElements = E->getNumInits();
- RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl();
-
- // We'll need to enter cleanup scopes in case any of the element
- // initializers throws an exception.
- SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
- llvm::Instruction *cleanupDominator = nullptr;
-
- unsigned curInitIndex = 0;
-
- // Emit initialization of base classes.
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(record)) {
- assert(E->getNumInits() >= CXXRD->getNumBases() &&
- "missing initializer for base class");
- for (auto &Base : CXXRD->bases()) {
- assert(!Base.isVirtual() && "should not see vbases here");
- auto *BaseRD = Base.getType()->getAsCXXRecordDecl();
- Address V = CGF.GetAddressOfDirectBaseInCompleteClass(
- Dest.getAddress(), CXXRD, BaseRD,
- /*isBaseVirtual*/ false);
- AggValueSlot AggSlot = AggValueSlot::forAddr(
- V, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- CGF.overlapForBaseInit(CXXRD, BaseRD, Base.isVirtual()));
- CGF.EmitAggExpr(E->getInit(curInitIndex++), AggSlot);
-
- if (QualType::DestructionKind dtorKind =
- Base.getType().isDestructedType()) {
- CGF.pushDestroy(dtorKind, V, Base.getType());
- cleanups.push_back(CGF.EHStack.stable_begin());
- }
- }
- }
-
- // Prepare a 'this' for CXXDefaultInitExprs.
- CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddress());
-
- if (record->isUnion()) {
- // Only initialize one field of a union. The field itself is
- // specified by the initializer list.
- if (!E->getInitializedFieldInUnion()) {
- // Empty union; we have nothing to do.
-
-#ifndef NDEBUG
- // Make sure that it's really an empty and not a failure of
- // semantic analysis.
- for (const auto *Field : record->fields())
- assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
-#endif
- return;
- }
-
- // FIXME: volatility
- FieldDecl *Field = E->getInitializedFieldInUnion();
-
- LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestLV, Field);
- if (NumInitElements) {
- // Store the initializer into the field
- EmitInitializationToLValue(E->getInit(0), FieldLoc);
- } else {
- // Default-initialize to null.
- EmitNullInitializationToLValue(FieldLoc);
- }
-
- return;
- }
-
- // Here we iterate over the fields; this makes it simpler to both
- // default-initialize fields and skip over unnamed fields.
- for (const auto *field : record->fields()) {
- // We're done once we hit the flexible array member.
- if (field->getType()->isIncompleteArrayType())
- break;
-
- // Always skip anonymous bitfields.
- if (field->isUnnamedBitfield())
- continue;
-
- // We're done if we reach the end of the explicit initializers, we
- // have a zeroed object, and the rest of the fields are
- // zero-initializable.
- if (curInitIndex == NumInitElements && Dest.isZeroed() &&
- CGF.getTypes().isZeroInitializable(E->getType()))
- break;
-
-
- LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, field);
- // We never generate write-barries for initialized fields.
- LV.setNonGC(true);
-
- if (curInitIndex < NumInitElements) {
- // Store the initializer into the field.
- EmitInitializationToLValue(E->getInit(curInitIndex++), LV);
- } else {
- // We're out of initializers; default-initialize to null
- EmitNullInitializationToLValue(LV);
- }
-
- // Push a destructor if necessary.
- // FIXME: if we have an array of structures, all explicitly
- // initialized, we can end up pushing a linear number of cleanups.
- bool pushedCleanup = false;
- if (QualType::DestructionKind dtorKind
- = field->getType().isDestructedType()) {
- assert(LV.isSimple());
- if (CGF.needsEHCleanup(dtorKind)) {
- if (!cleanupDominator)
- cleanupDominator = CGF.Builder.CreateAlignedLoad(
- CGF.Int8Ty,
- llvm::Constant::getNullValue(CGF.Int8PtrTy),
- CharUnits::One()); // placeholder
-
- CGF.pushDestroy(EHCleanup, LV.getAddress(), field->getType(),
- CGF.getDestroyer(dtorKind), false);
- cleanups.push_back(CGF.EHStack.stable_begin());
- pushedCleanup = true;
- }
- }
-
- // If the GEP didn't get used because of a dead zero init or something
- // else, clean it up for -O0 builds and general tidiness.
- if (!pushedCleanup && LV.isSimple())
- if (llvm::GetElementPtrInst *GEP =
- dyn_cast<llvm::GetElementPtrInst>(LV.getPointer()))
- if (GEP->use_empty())
- GEP->eraseFromParent();
- }
-
- // Deactivate all the partial cleanups in reverse order, which
- // generally means popping them.
- for (unsigned i = cleanups.size(); i != 0; --i)
- CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator);
-
- // Destroy the placeholder if we made one.
- if (cleanupDominator)
- cleanupDominator->eraseFromParent();
-}
-
-void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
- llvm::Value *outerBegin) {
- // Emit the common subexpression.
- CodeGenFunction::OpaqueValueMapping binding(CGF, E->getCommonExpr());
-
- Address destPtr = EnsureSlot(E->getType()).getAddress();
- uint64_t numElements = E->getArraySize().getZExtValue();
-
- if (!numElements)
- return;
-
- // destPtr is an array*. Construct an elementType* by drilling down a level.
- llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
- llvm::Value *indices[] = {zero, zero};
- llvm::Value *begin = Builder.CreateInBoundsGEP(destPtr.getPointer(), indices,
- "arrayinit.begin");
-
- // Prepare to special-case multidimensional array initialization: we avoid
- // emitting multiple destructor loops in that case.
- if (!outerBegin)
- outerBegin = begin;
- ArrayInitLoopExpr *InnerLoop = dyn_cast<ArrayInitLoopExpr>(E->getSubExpr());
-
- QualType elementType =
- CGF.getContext().getAsArrayType(E->getType())->getElementType();
- CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
- CharUnits elementAlign =
- destPtr.getAlignment().alignmentOfArrayElement(elementSize);
-
- llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
- llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
-
- // Jump into the body.
- CGF.EmitBlock(bodyBB);
- llvm::PHINode *index =
- Builder.CreatePHI(zero->getType(), 2, "arrayinit.index");
- index->addIncoming(zero, entryBB);
- llvm::Value *element = Builder.CreateInBoundsGEP(begin, index);
-
- // Prepare for a cleanup.
- QualType::DestructionKind dtorKind = elementType.isDestructedType();
- EHScopeStack::stable_iterator cleanup;
- if (CGF.needsEHCleanup(dtorKind) && !InnerLoop) {
- if (outerBegin->getType() != element->getType())
- outerBegin = Builder.CreateBitCast(outerBegin, element->getType());
- CGF.pushRegularPartialArrayCleanup(outerBegin, element, elementType,
- elementAlign,
- CGF.getDestroyer(dtorKind));
- cleanup = CGF.EHStack.stable_begin();
- } else {
- dtorKind = QualType::DK_none;
- }
-
- // Emit the actual filler expression.
- {
- // Temporaries created in an array initialization loop are destroyed
- // at the end of each iteration.
- CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
- CodeGenFunction::ArrayInitLoopExprScope Scope(CGF, index);
- LValue elementLV =
- CGF.MakeAddrLValue(Address(element, elementAlign), elementType);
-
- if (InnerLoop) {
- // If the subexpression is an ArrayInitLoopExpr, share its cleanup.
- auto elementSlot = AggValueSlot::forLValue(
- elementLV, AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap);
- AggExprEmitter(CGF, elementSlot, false)
- .VisitArrayInitLoopExpr(InnerLoop, outerBegin);
- } else
- EmitInitializationToLValue(E->getSubExpr(), elementLV);
- }
-
- // Move on to the next element.
- llvm::Value *nextIndex = Builder.CreateNUWAdd(
- index, llvm::ConstantInt::get(CGF.SizeTy, 1), "arrayinit.next");
- index->addIncoming(nextIndex, Builder.GetInsertBlock());
-
- // Leave the loop if we're done.
- llvm::Value *done = Builder.CreateICmpEQ(
- nextIndex, llvm::ConstantInt::get(CGF.SizeTy, numElements),
- "arrayinit.done");
- llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
- Builder.CreateCondBr(done, endBB, bodyBB);
-
- CGF.EmitBlock(endBB);
-
- // Leave the partial-array cleanup if we entered one.
- if (dtorKind)
- CGF.DeactivateCleanupBlock(cleanup, index);
-}
-
-void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
- AggValueSlot Dest = EnsureSlot(E->getType());
-
- LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
- EmitInitializationToLValue(E->getBase(), DestLV);
- VisitInitListExpr(E->getUpdater());
-}
-
-//===----------------------------------------------------------------------===//
-// Entry Points into this File
-//===----------------------------------------------------------------------===//
-
-/// GetNumNonZeroBytesInInit - Get an approximate count of the number of
-/// non-zero bytes that will be stored when outputting the initializer for the
-/// specified initializer expression.
-static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
- E = E->IgnoreParens();
-
- // 0 and 0.0 won't require any non-zero stores!
- if (isSimpleZero(E, CGF)) return CharUnits::Zero();
-
- // If this is an initlist expr, sum up the size of sizes of the (present)
- // elements. If this is something weird, assume the whole thing is non-zero.
- const InitListExpr *ILE = dyn_cast<InitListExpr>(E);
- while (ILE && ILE->isTransparent())
- ILE = dyn_cast<InitListExpr>(ILE->getInit(0));
- if (!ILE || !CGF.getTypes().isZeroInitializable(ILE->getType()))
- return CGF.getContext().getTypeSizeInChars(E->getType());
-
- // InitListExprs for structs have to be handled carefully. If there are
- // reference members, we need to consider the size of the reference, not the
- // referencee. InitListExprs for unions and arrays can't have references.
- if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
- if (!RT->isUnionType()) {
- RecordDecl *SD = E->getType()->getAs<RecordType>()->getDecl();
- CharUnits NumNonZeroBytes = CharUnits::Zero();
-
- unsigned ILEElement = 0;
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(SD))
- while (ILEElement != CXXRD->getNumBases())
- NumNonZeroBytes +=
- GetNumNonZeroBytesInInit(ILE->getInit(ILEElement++), CGF);
- for (const auto *Field : SD->fields()) {
- // We're done once we hit the flexible array member or run out of
- // InitListExpr elements.
- if (Field->getType()->isIncompleteArrayType() ||
- ILEElement == ILE->getNumInits())
- break;
- if (Field->isUnnamedBitfield())
- continue;
-
- const Expr *E = ILE->getInit(ILEElement++);
-
- // Reference values are always non-null and have the width of a pointer.
- if (Field->getType()->isReferenceType())
- NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits(
- CGF.getTarget().getPointerWidth(0));
- else
- NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF);
- }
-
- return NumNonZeroBytes;
- }
- }
-
-
- CharUnits NumNonZeroBytes = CharUnits::Zero();
- for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
- NumNonZeroBytes += GetNumNonZeroBytesInInit(ILE->getInit(i), CGF);
- return NumNonZeroBytes;
-}
-
-/// CheckAggExprForMemSetUse - If the initializer is large and has a lot of
-/// zeros in it, emit a memset and avoid storing the individual zeros.
-///
-static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
- CodeGenFunction &CGF) {
- // If the slot is already known to be zeroed, nothing to do. Don't mess with
- // volatile stores.
- if (Slot.isZeroed() || Slot.isVolatile() || !Slot.getAddress().isValid())
- return;
-
- // C++ objects with a user-declared constructor don't need zero'ing.
- if (CGF.getLangOpts().CPlusPlus)
- if (const RecordType *RT = CGF.getContext()
- .getBaseElementType(E->getType())->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasUserDeclaredConstructor())
- return;
- }
-
- // If the type is 16-bytes or smaller, prefer individual stores over memset.
- CharUnits Size = Slot.getPreferredSize(CGF.getContext(), E->getType());
- if (Size <= CharUnits::fromQuantity(16))
- return;
-
- // Check to see if over 3/4 of the initializer are known to be zero. If so,
- // we prefer to emit memset + individual stores for the rest.
- CharUnits NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF);
- if (NumNonZeroBytes*4 > Size)
- return;
-
- // Okay, it seems like a good idea to use an initial memset, emit the call.
- llvm::Constant *SizeVal = CGF.Builder.getInt64(Size.getQuantity());
-
- Address Loc = Slot.getAddress();
- Loc = CGF.Builder.CreateElementBitCast(Loc, CGF.Int8Ty);
- CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, false);
-
- // Tell the AggExprEmitter that the slot is known zero.
- Slot.setZeroed();
-}
-
-
-
-
-/// EmitAggExpr - Emit the computation of the specified expression of aggregate
-/// type. The result is computed into DestPtr. Note that if DestPtr is null,
-/// the value of the aggregate expression is not needed. If VolatileDest is
-/// true, DestPtr cannot be 0.
-void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
- assert(E && hasAggregateEvaluationKind(E->getType()) &&
- "Invalid aggregate expression to emit");
- assert((Slot.getAddress().isValid() || Slot.isIgnored()) &&
- "slot has bits but no address");
-
- // Optimize the slot if possible.
- CheckAggExprForMemSetUse(Slot, E, *this);
-
- AggExprEmitter(*this, Slot, Slot.isIgnored()).Visit(const_cast<Expr*>(E));
-}
-
-LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
- assert(hasAggregateEvaluationKind(E->getType()) && "Invalid argument!");
- Address Temp = CreateMemTemp(E->getType());
- LValue LV = MakeAddrLValue(Temp, E->getType());
- EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
- return LV;
-}
-
-AggValueSlot::Overlap_t CodeGenFunction::overlapForBaseInit(
- const CXXRecordDecl *RD, const CXXRecordDecl *BaseRD, bool IsVirtual) {
- // Virtual bases are initialized first, in address order, so there's never
- // any overlap during their initialization.
- //
- // FIXME: Under P0840, this is no longer true: the tail padding of a vbase
- // of a field could be reused by a vbase of a containing class.
- if (IsVirtual)
- return AggValueSlot::DoesNotOverlap;
-
- // If the base class is laid out entirely within the nvsize of the derived
- // class, its tail padding cannot yet be initialized, so we can issue
- // stores at the full width of the base class.
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
- if (Layout.getBaseClassOffset(BaseRD) +
- getContext().getASTRecordLayout(BaseRD).getSize() <=
- Layout.getNonVirtualSize())
- return AggValueSlot::DoesNotOverlap;
-
- // The tail padding may contain values we need to preserve.
- return AggValueSlot::MayOverlap;
-}
-
-void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
- AggValueSlot::Overlap_t MayOverlap,
- bool isVolatile) {
- assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
-
- Address DestPtr = Dest.getAddress();
- Address SrcPtr = Src.getAddress();
-
- if (getLangOpts().CPlusPlus) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
- assert((Record->hasTrivialCopyConstructor() ||
- Record->hasTrivialCopyAssignment() ||
- Record->hasTrivialMoveConstructor() ||
- Record->hasTrivialMoveAssignment() ||
- Record->isUnion()) &&
- "Trying to aggregate-copy a type without a trivial copy/move "
- "constructor or assignment operator");
- // Ignore empty classes in C++.
- if (Record->isEmpty())
- return;
- }
- }
-
- // Aggregate assignment turns into llvm.memcpy. This is almost valid per
- // C99 6.5.16.1p3, which states "If the value being stored in an object is
- // read from another object that overlaps in anyway the storage of the first
- // object, then the overlap shall be exact and the two objects shall have
- // qualified or unqualified versions of a compatible type."
- //
- // memcpy is not defined if the source and destination pointers are exactly
- // equal, but other compilers do this optimization, and almost every memcpy
- // implementation handles this case safely. If there is a libc that does not
- // safely handle this, we can add a target hook.
-
- // Get data size info for this aggregate. Don't copy the tail padding if this
- // might be a potentially-overlapping subobject, since the tail padding might
- // be occupied by a different object. Otherwise, copying it is fine.
- std::pair<CharUnits, CharUnits> TypeInfo;
- if (MayOverlap)
- TypeInfo = getContext().getTypeInfoDataSizeInChars(Ty);
- else
- TypeInfo = getContext().getTypeInfoInChars(Ty);
-
- llvm::Value *SizeVal = nullptr;
- if (TypeInfo.first.isZero()) {
- // But note that getTypeInfo returns 0 for a VLA.
- if (auto *VAT = dyn_cast_or_null<VariableArrayType>(
- getContext().getAsArrayType(Ty))) {
- QualType BaseEltTy;
- SizeVal = emitArrayLength(VAT, BaseEltTy, DestPtr);
- TypeInfo = getContext().getTypeInfoInChars(BaseEltTy);
- assert(!TypeInfo.first.isZero());
- SizeVal = Builder.CreateNUWMul(
- SizeVal,
- llvm::ConstantInt::get(SizeTy, TypeInfo.first.getQuantity()));
- }
- }
- if (!SizeVal) {
- SizeVal = llvm::ConstantInt::get(SizeTy, TypeInfo.first.getQuantity());
- }
-
- // FIXME: If we have a volatile struct, the optimizer can remove what might
- // appear to be `extra' memory ops:
- //
- // volatile struct { int i; } a, b;
- //
- // int main() {
- // a = b;
- // a = b;
- // }
- //
- // we need to use a different call here. We use isVolatile to indicate when
- // either the source or the destination is volatile.
-
- DestPtr = Builder.CreateElementBitCast(DestPtr, Int8Ty);
- SrcPtr = Builder.CreateElementBitCast(SrcPtr, Int8Ty);
-
- // Don't do any of the memmove_collectable tests if GC isn't set.
- if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
- // fall through
- } else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
- RecordDecl *Record = RecordTy->getDecl();
- if (Record->hasObjectMember()) {
- CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
- SizeVal);
- return;
- }
- } else if (Ty->isArrayType()) {
- QualType BaseType = getContext().getBaseElementType(Ty);
- if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
- if (RecordTy->getDecl()->hasObjectMember()) {
- CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
- SizeVal);
- return;
- }
- }
- }
-
- auto Inst = Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, isVolatile);
-
- // Determine the metadata to describe the position of any padding in this
- // memcpy, as well as the TBAA tags for the members of the struct, in case
- // the optimizer wishes to expand it in to scalar memory operations.
- if (llvm::MDNode *TBAAStructTag = CGM.getTBAAStructInfo(Ty))
- Inst->setMetadata(llvm::LLVMContext::MD_tbaa_struct, TBAAStructTag);
-
- if (CGM.getCodeGenOpts().NewStructPathTBAA) {
- TBAAAccessInfo TBAAInfo = CGM.mergeTBAAInfoForMemoryTransfer(
- Dest.getTBAAInfo(), Src.getTBAAInfo());
- CGM.DecorateInstructionWithTBAA(Inst, TBAAInfo);
- }
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp
deleted file mode 100644
index 884ce96859c..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp
+++ /dev/null
@@ -1,2273 +0,0 @@
-//===--- CGExprCXX.cpp - Emit LLVM Code for C++ expressions ---------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with code generation of C++ expressions
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CGCUDARuntime.h"
-#include "CGCXXABI.h"
-#include "CGDebugInfo.h"
-#include "CGObjCRuntime.h"
-#include "ConstantEmitter.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/Intrinsics.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-struct MemberCallInfo {
- RequiredArgs ReqArgs;
- // Number of prefix arguments for the call. Ignores the `this` pointer.
- unsigned PrefixSize;
-};
-}
-
-static MemberCallInfo
-commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
- llvm::Value *This, llvm::Value *ImplicitParam,
- QualType ImplicitParamTy, const CallExpr *CE,
- CallArgList &Args, CallArgList *RtlArgs) {
- assert(CE == nullptr || isa<CXXMemberCallExpr>(CE) ||
- isa<CXXOperatorCallExpr>(CE));
- assert(MD->isInstance() &&
- "Trying to emit a member or operator call expr on a static method!");
- ASTContext &C = CGF.getContext();
-
- // Push the this ptr.
- const CXXRecordDecl *RD =
- CGF.CGM.getCXXABI().getThisArgumentTypeForMethod(MD);
- Args.add(RValue::get(This),
- RD ? C.getPointerType(C.getTypeDeclType(RD)) : C.VoidPtrTy);
-
- // If there is an implicit parameter (e.g. VTT), emit it.
- if (ImplicitParam) {
- Args.add(RValue::get(ImplicitParam), ImplicitParamTy);
- }
-
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size(), MD);
- unsigned PrefixSize = Args.size() - 1;
-
- // And the rest of the call args.
- if (RtlArgs) {
- // Special case: if the caller emitted the arguments right-to-left already
- // (prior to emitting the *this argument), we're done. This happens for
- // assignment operators.
- Args.addFrom(*RtlArgs);
- } else if (CE) {
- // Special case: skip first argument of CXXOperatorCall (it is "this").
- unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
- CGF.EmitCallArgs(Args, FPT, drop_begin(CE->arguments(), ArgsToSkip),
- CE->getDirectCallee());
- } else {
- assert(
- FPT->getNumParams() == 0 &&
- "No CallExpr specified for function with non-zero number of arguments");
- }
- return {required, PrefixSize};
-}
-
-RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
- const CXXMethodDecl *MD, const CGCallee &Callee,
- ReturnValueSlot ReturnValue,
- llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy,
- const CallExpr *CE, CallArgList *RtlArgs) {
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- CallArgList Args;
- MemberCallInfo CallInfo = commonEmitCXXMemberOrOperatorCall(
- *this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs);
- auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(
- Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize);
- return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr,
- CE ? CE->getExprLoc() : SourceLocation());
-}
-
-RValue CodeGenFunction::EmitCXXDestructorCall(
- const CXXDestructorDecl *DD, const CGCallee &Callee, llvm::Value *This,
- llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *CE,
- StructorType Type) {
- CallArgList Args;
- commonEmitCXXMemberOrOperatorCall(*this, DD, This, ImplicitParam,
- ImplicitParamTy, CE, Args, nullptr);
- return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(DD, Type),
- Callee, ReturnValueSlot(), Args);
-}
-
-RValue CodeGenFunction::EmitCXXPseudoDestructorExpr(
- const CXXPseudoDestructorExpr *E) {
- QualType DestroyedType = E->getDestroyedType();
- if (DestroyedType.hasStrongOrWeakObjCLifetime()) {
- // Automatic Reference Counting:
- // If the pseudo-expression names a retainable object with weak or
- // strong lifetime, the object shall be released.
- Expr *BaseExpr = E->getBase();
- Address BaseValue = Address::invalid();
- Qualifiers BaseQuals;
-
- // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
- if (E->isArrow()) {
- BaseValue = EmitPointerWithAlignment(BaseExpr);
- const PointerType *PTy = BaseExpr->getType()->getAs<PointerType>();
- BaseQuals = PTy->getPointeeType().getQualifiers();
- } else {
- LValue BaseLV = EmitLValue(BaseExpr);
- BaseValue = BaseLV.getAddress();
- QualType BaseTy = BaseExpr->getType();
- BaseQuals = BaseTy.getQualifiers();
- }
-
- switch (DestroyedType.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- break;
-
- case Qualifiers::OCL_Strong:
- EmitARCRelease(Builder.CreateLoad(BaseValue,
- DestroyedType.isVolatileQualified()),
- ARCPreciseLifetime);
- break;
-
- case Qualifiers::OCL_Weak:
- EmitARCDestroyWeak(BaseValue);
- break;
- }
- } else {
- // C++ [expr.pseudo]p1:
- // The result shall only be used as the operand for the function call
- // operator (), and the result of such a call has type void. The only
- // effect is the evaluation of the postfix-expression before the dot or
- // arrow.
- EmitIgnoredExpr(E->getBase());
- }
-
- return RValue::get(nullptr);
-}
-
-static CXXRecordDecl *getCXXRecord(const Expr *E) {
- QualType T = E->getType();
- if (const PointerType *PTy = T->getAs<PointerType>())
- T = PTy->getPointeeType();
- const RecordType *Ty = T->castAs<RecordType>();
- return cast<CXXRecordDecl>(Ty->getDecl());
-}
-
-// Note: This function also emit constructor calls to support a MSVC
-// extensions allowing explicit constructor function call.
-RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
- ReturnValueSlot ReturnValue) {
- const Expr *callee = CE->getCallee()->IgnoreParens();
-
- if (isa<BinaryOperator>(callee))
- return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
-
- const MemberExpr *ME = cast<MemberExpr>(callee);
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
-
- if (MD->isStatic()) {
- // The method is static, emit it as we would a regular call.
- CGCallee callee =
- CGCallee::forDirect(CGM.GetAddrOfFunction(MD), GlobalDecl(MD));
- return EmitCall(getContext().getPointerType(MD->getType()), callee, CE,
- ReturnValue);
- }
-
- bool HasQualifier = ME->hasQualifier();
- NestedNameSpecifier *Qualifier = HasQualifier ? ME->getQualifier() : nullptr;
- bool IsArrow = ME->isArrow();
- const Expr *Base = ME->getBase();
-
- return EmitCXXMemberOrOperatorMemberCallExpr(
- CE, MD, ReturnValue, HasQualifier, Qualifier, IsArrow, Base);
-}
-
-RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
- const CallExpr *CE, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue,
- bool HasQualifier, NestedNameSpecifier *Qualifier, bool IsArrow,
- const Expr *Base) {
- assert(isa<CXXMemberCallExpr>(CE) || isa<CXXOperatorCallExpr>(CE));
-
- // Compute the object pointer.
- bool CanUseVirtualCall = MD->isVirtual() && !HasQualifier;
-
- const CXXMethodDecl *DevirtualizedMethod = nullptr;
- if (CanUseVirtualCall &&
- MD->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) {
- const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
- DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl);
- assert(DevirtualizedMethod);
- const CXXRecordDecl *DevirtualizedClass = DevirtualizedMethod->getParent();
- const Expr *Inner = Base->ignoreParenBaseCasts();
- if (DevirtualizedMethod->getReturnType().getCanonicalType() !=
- MD->getReturnType().getCanonicalType())
- // If the return types are not the same, this might be a case where more
- // code needs to run to compensate for it. For example, the derived
- // method might return a type that inherits form from the return
- // type of MD and has a prefix.
- // For now we just avoid devirtualizing these covariant cases.
- DevirtualizedMethod = nullptr;
- else if (getCXXRecord(Inner) == DevirtualizedClass)
- // If the class of the Inner expression is where the dynamic method
- // is defined, build the this pointer from it.
- Base = Inner;
- else if (getCXXRecord(Base) != DevirtualizedClass) {
- // If the method is defined in a class that is not the best dynamic
- // one or the one of the full expression, we would have to build
- // a derived-to-base cast to compute the correct this pointer, but
- // we don't have support for that yet, so do a virtual call.
- DevirtualizedMethod = nullptr;
- }
- }
-
- // C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
- // operator before the LHS.
- CallArgList RtlArgStorage;
- CallArgList *RtlArgs = nullptr;
- if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
- if (OCE->isAssignmentOp()) {
- RtlArgs = &RtlArgStorage;
- EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
- drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
- /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
- }
- }
-
- LValue This;
- if (IsArrow) {
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- Address ThisValue = EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo);
- This = MakeAddrLValue(ThisValue, Base->getType(), BaseInfo, TBAAInfo);
- } else {
- This = EmitLValue(Base);
- }
-
-
- if (MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion())) {
- if (isa<CXXDestructorDecl>(MD)) return RValue::get(nullptr);
- if (isa<CXXConstructorDecl>(MD) &&
- cast<CXXConstructorDecl>(MD)->isDefaultConstructor())
- return RValue::get(nullptr);
-
- if (!MD->getParent()->mayInsertExtraPadding()) {
- if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
- // We don't like to generate the trivial copy/move assignment operator
- // when it isn't necessary; just produce the proper effect here.
- LValue RHS = isa<CXXOperatorCallExpr>(CE)
- ? MakeNaturalAlignAddrLValue(
- (*RtlArgs)[0].getRValue(*this).getScalarVal(),
- (*(CE->arg_begin() + 1))->getType())
- : EmitLValue(*CE->arg_begin());
- EmitAggregateAssign(This, RHS, CE->getType());
- return RValue::get(This.getPointer());
- }
-
- if (isa<CXXConstructorDecl>(MD) &&
- cast<CXXConstructorDecl>(MD)->isCopyOrMoveConstructor()) {
- // Trivial move and copy ctor are the same.
- assert(CE->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
- const Expr *Arg = *CE->arg_begin();
- LValue RHS = EmitLValue(Arg);
- LValue Dest = MakeAddrLValue(This.getAddress(), Arg->getType());
- // This is the MSVC p->Ctor::Ctor(...) extension. We assume that's
- // constructing a new complete object of type Ctor.
- EmitAggregateCopy(Dest, RHS, Arg->getType(),
- AggValueSlot::DoesNotOverlap);
- return RValue::get(This.getPointer());
- }
- llvm_unreachable("unknown trivial member function");
- }
- }
-
- // Compute the function type we're calling.
- const CXXMethodDecl *CalleeDecl =
- DevirtualizedMethod ? DevirtualizedMethod : MD;
- const CGFunctionInfo *FInfo = nullptr;
- if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl))
- FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
- Dtor, StructorType::Complete);
- else if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl))
- FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
- Ctor, StructorType::Complete);
- else
- FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl);
-
- llvm::FunctionType *Ty = CGM.getTypes().GetFunctionType(*FInfo);
-
- // C++11 [class.mfct.non-static]p2:
- // If a non-static member function of a class X is called for an object that
- // is not of type X, or of a type derived from X, the behavior is undefined.
- SourceLocation CallLoc;
- ASTContext &C = getContext();
- if (CE)
- CallLoc = CE->getExprLoc();
-
- SanitizerSet SkippedChecks;
- if (const auto *CMCE = dyn_cast<CXXMemberCallExpr>(CE)) {
- auto *IOA = CMCE->getImplicitObjectArgument();
- bool IsImplicitObjectCXXThis = IsWrappedCXXThis(IOA);
- if (IsImplicitObjectCXXThis)
- SkippedChecks.set(SanitizerKind::Alignment, true);
- if (IsImplicitObjectCXXThis || isa<DeclRefExpr>(IOA))
- SkippedChecks.set(SanitizerKind::Null, true);
- }
- EmitTypeCheck(
- isa<CXXConstructorDecl>(CalleeDecl) ? CodeGenFunction::TCK_ConstructorCall
- : CodeGenFunction::TCK_MemberCall,
- CallLoc, This.getPointer(), C.getRecordType(CalleeDecl->getParent()),
- /*Alignment=*/CharUnits::Zero(), SkippedChecks);
-
- // FIXME: Uses of 'MD' past this point need to be audited. We may need to use
- // 'CalleeDecl' instead.
-
- // C++ [class.virtual]p12:
- // Explicit qualification with the scope operator (5.1) suppresses the
- // virtual call mechanism.
- //
- // We also don't emit a virtual call if the base expression has a record type
- // because then we know what the type is.
- bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
-
- if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
- assert(CE->arg_begin() == CE->arg_end() &&
- "Destructor shouldn't have explicit parameters");
- assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
- if (UseVirtualCall) {
- CGM.getCXXABI().EmitVirtualDestructorCall(
- *this, Dtor, Dtor_Complete, This.getAddress(),
- cast<CXXMemberCallExpr>(CE));
- } else {
- CGCallee Callee;
- if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
- Callee = BuildAppleKextVirtualCall(MD, Qualifier, Ty);
- else if (!DevirtualizedMethod)
- Callee = CGCallee::forDirect(
- CGM.getAddrOfCXXStructor(Dtor, StructorType::Complete, FInfo, Ty),
- GlobalDecl(Dtor, Dtor_Complete));
- else {
- const CXXDestructorDecl *DDtor =
- cast<CXXDestructorDecl>(DevirtualizedMethod);
- Callee = CGCallee::forDirect(
- CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty),
- GlobalDecl(DDtor, Dtor_Complete));
- }
- EmitCXXMemberOrOperatorCall(
- CalleeDecl, Callee, ReturnValue, This.getPointer(),
- /*ImplicitParam=*/nullptr, QualType(), CE, nullptr);
- }
- return RValue::get(nullptr);
- }
-
- CGCallee Callee;
- if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
- Callee = CGCallee::forDirect(
- CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty),
- GlobalDecl(Ctor, Ctor_Complete));
- } else if (UseVirtualCall) {
- Callee = CGCallee::forVirtual(CE, MD, This.getAddress(), Ty);
- } else {
- if (SanOpts.has(SanitizerKind::CFINVCall) &&
- MD->getParent()->isDynamicClass()) {
- llvm::Value *VTable;
- const CXXRecordDecl *RD;
- std::tie(VTable, RD) =
- CGM.getCXXABI().LoadVTablePtr(*this, This.getAddress(),
- MD->getParent());
- EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getBeginLoc());
- }
-
- if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
- Callee = BuildAppleKextVirtualCall(MD, Qualifier, Ty);
- else if (!DevirtualizedMethod)
- Callee =
- CGCallee::forDirect(CGM.GetAddrOfFunction(MD, Ty), GlobalDecl(MD));
- else {
- Callee =
- CGCallee::forDirect(CGM.GetAddrOfFunction(DevirtualizedMethod, Ty),
- GlobalDecl(DevirtualizedMethod));
- }
- }
-
- if (MD->isVirtual()) {
- Address NewThisAddr =
- CGM.getCXXABI().adjustThisArgumentForVirtualFunctionCall(
- *this, CalleeDecl, This.getAddress(), UseVirtualCall);
- This.setAddress(NewThisAddr);
- }
-
- return EmitCXXMemberOrOperatorCall(
- CalleeDecl, Callee, ReturnValue, This.getPointer(),
- /*ImplicitParam=*/nullptr, QualType(), CE, RtlArgs);
-}
-
-RValue
-CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
- ReturnValueSlot ReturnValue) {
- const BinaryOperator *BO =
- cast<BinaryOperator>(E->getCallee()->IgnoreParens());
- const Expr *BaseExpr = BO->getLHS();
- const Expr *MemFnExpr = BO->getRHS();
-
- const MemberPointerType *MPT =
- MemFnExpr->getType()->castAs<MemberPointerType>();
-
- const FunctionProtoType *FPT =
- MPT->getPointeeType()->castAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
-
- // Emit the 'this' pointer.
- Address This = Address::invalid();
- if (BO->getOpcode() == BO_PtrMemI)
- This = EmitPointerWithAlignment(BaseExpr);
- else
- This = EmitLValue(BaseExpr).getAddress();
-
- EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This.getPointer(),
- QualType(MPT->getClass(), 0));
-
- // Get the member function pointer.
- llvm::Value *MemFnPtr = EmitScalarExpr(MemFnExpr);
-
- // Ask the ABI to load the callee. Note that This is modified.
- llvm::Value *ThisPtrForCall = nullptr;
- CGCallee Callee =
- CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, BO, This,
- ThisPtrForCall, MemFnPtr, MPT);
-
- CallArgList Args;
-
- QualType ThisType =
- getContext().getPointerType(getContext().getTagDeclType(RD));
-
- // Push the this ptr.
- Args.add(RValue::get(ThisPtrForCall), ThisType);
-
- RequiredArgs required =
- RequiredArgs::forPrototypePlus(FPT, 1, /*FD=*/nullptr);
-
- // And the rest of the call args
- EmitCallArgs(Args, FPT, E->arguments());
- return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
- /*PrefixSize=*/0),
- Callee, ReturnValue, Args, nullptr, E->getExprLoc());
-}
-
-RValue
-CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
- const CXXMethodDecl *MD,
- ReturnValueSlot ReturnValue) {
- assert(MD->isInstance() &&
- "Trying to emit a member call expr on a static method!");
- return EmitCXXMemberOrOperatorMemberCallExpr(
- E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr,
- /*IsArrow=*/false, E->getArg(0));
-}
-
-RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
- ReturnValueSlot ReturnValue) {
- return CGM.getCUDARuntime().EmitCUDAKernelCallExpr(*this, E, ReturnValue);
-}
-
-static void EmitNullBaseClassInitialization(CodeGenFunction &CGF,
- Address DestPtr,
- const CXXRecordDecl *Base) {
- if (Base->isEmpty())
- return;
-
- DestPtr = CGF.Builder.CreateElementBitCast(DestPtr, CGF.Int8Ty);
-
- const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(Base);
- CharUnits NVSize = Layout.getNonVirtualSize();
-
- // We cannot simply zero-initialize the entire base sub-object if vbptrs are
- // present, they are initialized by the most derived class before calling the
- // constructor.
- SmallVector<std::pair<CharUnits, CharUnits>, 1> Stores;
- Stores.emplace_back(CharUnits::Zero(), NVSize);
-
- // Each store is split by the existence of a vbptr.
- CharUnits VBPtrWidth = CGF.getPointerSize();
- std::vector<CharUnits> VBPtrOffsets =
- CGF.CGM.getCXXABI().getVBPtrOffsets(Base);
- for (CharUnits VBPtrOffset : VBPtrOffsets) {
- // Stop before we hit any virtual base pointers located in virtual bases.
- if (VBPtrOffset >= NVSize)
- break;
- std::pair<CharUnits, CharUnits> LastStore = Stores.pop_back_val();
- CharUnits LastStoreOffset = LastStore.first;
- CharUnits LastStoreSize = LastStore.second;
-
- CharUnits SplitBeforeOffset = LastStoreOffset;
- CharUnits SplitBeforeSize = VBPtrOffset - SplitBeforeOffset;
- assert(!SplitBeforeSize.isNegative() && "negative store size!");
- if (!SplitBeforeSize.isZero())
- Stores.emplace_back(SplitBeforeOffset, SplitBeforeSize);
-
- CharUnits SplitAfterOffset = VBPtrOffset + VBPtrWidth;
- CharUnits SplitAfterSize = LastStoreSize - SplitAfterOffset;
- assert(!SplitAfterSize.isNegative() && "negative store size!");
- if (!SplitAfterSize.isZero())
- Stores.emplace_back(SplitAfterOffset, SplitAfterSize);
- }
-
- // If the type contains a pointer to data member we can't memset it to zero.
- // Instead, create a null constant and copy it to the destination.
- // TODO: there are other patterns besides zero that we can usefully memset,
- // like -1, which happens to be the pattern used by member-pointers.
- // TODO: isZeroInitializable can be over-conservative in the case where a
- // virtual base contains a member pointer.
- llvm::Constant *NullConstantForBase = CGF.CGM.EmitNullConstantForBase(Base);
- if (!NullConstantForBase->isNullValue()) {
- llvm::GlobalVariable *NullVariable = new llvm::GlobalVariable(
- CGF.CGM.getModule(), NullConstantForBase->getType(),
- /*isConstant=*/true, llvm::GlobalVariable::PrivateLinkage,
- NullConstantForBase, Twine());
-
- CharUnits Align = std::max(Layout.getNonVirtualAlignment(),
- DestPtr.getAlignment());
- NullVariable->setAlignment(Align.getQuantity());
-
- Address SrcPtr = Address(CGF.EmitCastToVoidPtr(NullVariable), Align);
-
- // Get and call the appropriate llvm.memcpy overload.
- for (std::pair<CharUnits, CharUnits> Store : Stores) {
- CharUnits StoreOffset = Store.first;
- CharUnits StoreSize = Store.second;
- llvm::Value *StoreSizeVal = CGF.CGM.getSize(StoreSize);
- CGF.Builder.CreateMemCpy(
- CGF.Builder.CreateConstInBoundsByteGEP(DestPtr, StoreOffset),
- CGF.Builder.CreateConstInBoundsByteGEP(SrcPtr, StoreOffset),
- StoreSizeVal);
- }
-
- // Otherwise, just memset the whole thing to zero. This is legal
- // because in LLVM, all default initializers (other than the ones we just
- // handled above) are guaranteed to have a bit pattern of all zeros.
- } else {
- for (std::pair<CharUnits, CharUnits> Store : Stores) {
- CharUnits StoreOffset = Store.first;
- CharUnits StoreSize = Store.second;
- llvm::Value *StoreSizeVal = CGF.CGM.getSize(StoreSize);
- CGF.Builder.CreateMemSet(
- CGF.Builder.CreateConstInBoundsByteGEP(DestPtr, StoreOffset),
- CGF.Builder.getInt8(0), StoreSizeVal);
- }
- }
-}
-
-void
-CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
- AggValueSlot Dest) {
- assert(!Dest.isIgnored() && "Must have a destination!");
- const CXXConstructorDecl *CD = E->getConstructor();
-
- // If we require zero initialization before (or instead of) calling the
- // constructor, as can be the case with a non-user-provided default
- // constructor, emit the zero initialization now, unless destination is
- // already zeroed.
- if (E->requiresZeroInitialization() && !Dest.isZeroed()) {
- switch (E->getConstructionKind()) {
- case CXXConstructExpr::CK_Delegating:
- case CXXConstructExpr::CK_Complete:
- EmitNullInitialization(Dest.getAddress(), E->getType());
- break;
- case CXXConstructExpr::CK_VirtualBase:
- case CXXConstructExpr::CK_NonVirtualBase:
- EmitNullBaseClassInitialization(*this, Dest.getAddress(),
- CD->getParent());
- break;
- }
- }
-
- // If this is a call to a trivial default constructor, do nothing.
- if (CD->isTrivial() && CD->isDefaultConstructor())
- return;
-
- // Elide the constructor if we're constructing from a temporary.
- // The temporary check is required because Sema sets this on NRVO
- // returns.
- if (getLangOpts().ElideConstructors && E->isElidable()) {
- assert(getContext().hasSameUnqualifiedType(E->getType(),
- E->getArg(0)->getType()));
- if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) {
- EmitAggExpr(E->getArg(0), Dest);
- return;
- }
- }
-
- if (const ArrayType *arrayType
- = getContext().getAsArrayType(E->getType())) {
- EmitCXXAggrConstructorCall(CD, arrayType, Dest.getAddress(), E,
- Dest.isSanitizerChecked());
- } else {
- CXXCtorType Type = Ctor_Complete;
- bool ForVirtualBase = false;
- bool Delegating = false;
-
- switch (E->getConstructionKind()) {
- case CXXConstructExpr::CK_Delegating:
- // We should be emitting a constructor; GlobalDecl will assert this
- Type = CurGD.getCtorType();
- Delegating = true;
- break;
-
- case CXXConstructExpr::CK_Complete:
- Type = Ctor_Complete;
- break;
-
- case CXXConstructExpr::CK_VirtualBase:
- ForVirtualBase = true;
- LLVM_FALLTHROUGH;
-
- case CXXConstructExpr::CK_NonVirtualBase:
- Type = Ctor_Base;
- }
-
- // Call the constructor.
- EmitCXXConstructorCall(CD, Type, ForVirtualBase, Delegating,
- Dest.getAddress(), E, Dest.mayOverlap(),
- Dest.isSanitizerChecked());
- }
-}
-
-void CodeGenFunction::EmitSynthesizedCXXCopyCtor(Address Dest, Address Src,
- const Expr *Exp) {
- if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(Exp))
- Exp = E->getSubExpr();
- assert(isa<CXXConstructExpr>(Exp) &&
- "EmitSynthesizedCXXCopyCtor - unknown copy ctor expr");
- const CXXConstructExpr* E = cast<CXXConstructExpr>(Exp);
- const CXXConstructorDecl *CD = E->getConstructor();
- RunCleanupsScope Scope(*this);
-
- // If we require zero initialization before (or instead of) calling the
- // constructor, as can be the case with a non-user-provided default
- // constructor, emit the zero initialization now.
- // FIXME. Do I still need this for a copy ctor synthesis?
- if (E->requiresZeroInitialization())
- EmitNullInitialization(Dest, E->getType());
-
- assert(!getContext().getAsConstantArrayType(E->getType())
- && "EmitSynthesizedCXXCopyCtor - Copied-in Array");
- EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src, E);
-}
-
-static CharUnits CalculateCookiePadding(CodeGenFunction &CGF,
- const CXXNewExpr *E) {
- if (!E->isArray())
- return CharUnits::Zero();
-
- // No cookie is required if the operator new[] being used is the
- // reserved placement operator new[].
- if (E->getOperatorNew()->isReservedGlobalPlacementOperator())
- return CharUnits::Zero();
-
- return CGF.CGM.getCXXABI().GetArrayCookieSize(E);
-}
-
-static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
- const CXXNewExpr *e,
- unsigned minElements,
- llvm::Value *&numElements,
- llvm::Value *&sizeWithoutCookie) {
- QualType type = e->getAllocatedType();
-
- if (!e->isArray()) {
- CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type);
- sizeWithoutCookie
- = llvm::ConstantInt::get(CGF.SizeTy, typeSize.getQuantity());
- return sizeWithoutCookie;
- }
-
- // The width of size_t.
- unsigned sizeWidth = CGF.SizeTy->getBitWidth();
-
- // Figure out the cookie size.
- llvm::APInt cookieSize(sizeWidth,
- CalculateCookiePadding(CGF, e).getQuantity());
-
- // Emit the array size expression.
- // We multiply the size of all dimensions for NumElements.
- // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
- numElements =
- ConstantEmitter(CGF).tryEmitAbstract(e->getArraySize(), e->getType());
- if (!numElements)
- numElements = CGF.EmitScalarExpr(e->getArraySize());
- assert(isa<llvm::IntegerType>(numElements->getType()));
-
- // The number of elements can be have an arbitrary integer type;
- // essentially, we need to multiply it by a constant factor, add a
- // cookie size, and verify that the result is representable as a
- // size_t. That's just a gloss, though, and it's wrong in one
- // important way: if the count is negative, it's an error even if
- // the cookie size would bring the total size >= 0.
- bool isSigned
- = e->getArraySize()->getType()->isSignedIntegerOrEnumerationType();
- llvm::IntegerType *numElementsType
- = cast<llvm::IntegerType>(numElements->getType());
- unsigned numElementsWidth = numElementsType->getBitWidth();
-
- // Compute the constant factor.
- llvm::APInt arraySizeMultiplier(sizeWidth, 1);
- while (const ConstantArrayType *CAT
- = CGF.getContext().getAsConstantArrayType(type)) {
- type = CAT->getElementType();
- arraySizeMultiplier *= CAT->getSize();
- }
-
- CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type);
- llvm::APInt typeSizeMultiplier(sizeWidth, typeSize.getQuantity());
- typeSizeMultiplier *= arraySizeMultiplier;
-
- // This will be a size_t.
- llvm::Value *size;
-
- // If someone is doing 'new int[42]' there is no need to do a dynamic check.
- // Don't bloat the -O0 code.
- if (llvm::ConstantInt *numElementsC =
- dyn_cast<llvm::ConstantInt>(numElements)) {
- const llvm::APInt &count = numElementsC->getValue();
-
- bool hasAnyOverflow = false;
-
- // If 'count' was a negative number, it's an overflow.
- if (isSigned && count.isNegative())
- hasAnyOverflow = true;
-
- // We want to do all this arithmetic in size_t. If numElements is
- // wider than that, check whether it's already too big, and if so,
- // overflow.
- else if (numElementsWidth > sizeWidth &&
- numElementsWidth - sizeWidth > count.countLeadingZeros())
- hasAnyOverflow = true;
-
- // Okay, compute a count at the right width.
- llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth);
-
- // If there is a brace-initializer, we cannot allocate fewer elements than
- // there are initializers. If we do, that's treated like an overflow.
- if (adjustedCount.ult(minElements))
- hasAnyOverflow = true;
-
- // Scale numElements by that. This might overflow, but we don't
- // care because it only overflows if allocationSize does, too, and
- // if that overflows then we shouldn't use this.
- numElements = llvm::ConstantInt::get(CGF.SizeTy,
- adjustedCount * arraySizeMultiplier);
-
- // Compute the size before cookie, and track whether it overflowed.
- bool overflow;
- llvm::APInt allocationSize
- = adjustedCount.umul_ov(typeSizeMultiplier, overflow);
- hasAnyOverflow |= overflow;
-
- // Add in the cookie, and check whether it's overflowed.
- if (cookieSize != 0) {
- // Save the current size without a cookie. This shouldn't be
- // used if there was overflow.
- sizeWithoutCookie = llvm::ConstantInt::get(CGF.SizeTy, allocationSize);
-
- allocationSize = allocationSize.uadd_ov(cookieSize, overflow);
- hasAnyOverflow |= overflow;
- }
-
- // On overflow, produce a -1 so operator new will fail.
- if (hasAnyOverflow) {
- size = llvm::Constant::getAllOnesValue(CGF.SizeTy);
- } else {
- size = llvm::ConstantInt::get(CGF.SizeTy, allocationSize);
- }
-
- // Otherwise, we might need to use the overflow intrinsics.
- } else {
- // There are up to five conditions we need to test for:
- // 1) if isSigned, we need to check whether numElements is negative;
- // 2) if numElementsWidth > sizeWidth, we need to check whether
- // numElements is larger than something representable in size_t;
- // 3) if minElements > 0, we need to check whether numElements is smaller
- // than that.
- // 4) we need to compute
- // sizeWithoutCookie := numElements * typeSizeMultiplier
- // and check whether it overflows; and
- // 5) if we need a cookie, we need to compute
- // size := sizeWithoutCookie + cookieSize
- // and check whether it overflows.
-
- llvm::Value *hasOverflow = nullptr;
-
- // If numElementsWidth > sizeWidth, then one way or another, we're
- // going to have to do a comparison for (2), and this happens to
- // take care of (1), too.
- if (numElementsWidth > sizeWidth) {
- llvm::APInt threshold(numElementsWidth, 1);
- threshold <<= sizeWidth;
-
- llvm::Value *thresholdV
- = llvm::ConstantInt::get(numElementsType, threshold);
-
- hasOverflow = CGF.Builder.CreateICmpUGE(numElements, thresholdV);
- numElements = CGF.Builder.CreateTrunc(numElements, CGF.SizeTy);
-
- // Otherwise, if we're signed, we want to sext up to size_t.
- } else if (isSigned) {
- if (numElementsWidth < sizeWidth)
- numElements = CGF.Builder.CreateSExt(numElements, CGF.SizeTy);
-
- // If there's a non-1 type size multiplier, then we can do the
- // signedness check at the same time as we do the multiply
- // because a negative number times anything will cause an
- // unsigned overflow. Otherwise, we have to do it here. But at least
- // in this case, we can subsume the >= minElements check.
- if (typeSizeMultiplier == 1)
- hasOverflow = CGF.Builder.CreateICmpSLT(numElements,
- llvm::ConstantInt::get(CGF.SizeTy, minElements));
-
- // Otherwise, zext up to size_t if necessary.
- } else if (numElementsWidth < sizeWidth) {
- numElements = CGF.Builder.CreateZExt(numElements, CGF.SizeTy);
- }
-
- assert(numElements->getType() == CGF.SizeTy);
-
- if (minElements) {
- // Don't allow allocation of fewer elements than we have initializers.
- if (!hasOverflow) {
- hasOverflow = CGF.Builder.CreateICmpULT(numElements,
- llvm::ConstantInt::get(CGF.SizeTy, minElements));
- } else if (numElementsWidth > sizeWidth) {
- // The other existing overflow subsumes this check.
- // We do an unsigned comparison, since any signed value < -1 is
- // taken care of either above or below.
- hasOverflow = CGF.Builder.CreateOr(hasOverflow,
- CGF.Builder.CreateICmpULT(numElements,
- llvm::ConstantInt::get(CGF.SizeTy, minElements)));
- }
- }
-
- size = numElements;
-
- // Multiply by the type size if necessary. This multiplier
- // includes all the factors for nested arrays.
- //
- // This step also causes numElements to be scaled up by the
- // nested-array factor if necessary. Overflow on this computation
- // can be ignored because the result shouldn't be used if
- // allocation fails.
- if (typeSizeMultiplier != 1) {
- llvm::Value *umul_with_overflow
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, CGF.SizeTy);
-
- llvm::Value *tsmV =
- llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier);
- llvm::Value *result =
- CGF.Builder.CreateCall(umul_with_overflow, {size, tsmV});
-
- llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1);
- if (hasOverflow)
- hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed);
- else
- hasOverflow = overflowed;
-
- size = CGF.Builder.CreateExtractValue(result, 0);
-
- // Also scale up numElements by the array size multiplier.
- if (arraySizeMultiplier != 1) {
- // If the base element type size is 1, then we can re-use the
- // multiply we just did.
- if (typeSize.isOne()) {
- assert(arraySizeMultiplier == typeSizeMultiplier);
- numElements = size;
-
- // Otherwise we need a separate multiply.
- } else {
- llvm::Value *asmV =
- llvm::ConstantInt::get(CGF.SizeTy, arraySizeMultiplier);
- numElements = CGF.Builder.CreateMul(numElements, asmV);
- }
- }
- } else {
- // numElements doesn't need to be scaled.
- assert(arraySizeMultiplier == 1);
- }
-
- // Add in the cookie size if necessary.
- if (cookieSize != 0) {
- sizeWithoutCookie = size;
-
- llvm::Value *uadd_with_overflow
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, CGF.SizeTy);
-
- llvm::Value *cookieSizeV = llvm::ConstantInt::get(CGF.SizeTy, cookieSize);
- llvm::Value *result =
- CGF.Builder.CreateCall(uadd_with_overflow, {size, cookieSizeV});
-
- llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1);
- if (hasOverflow)
- hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed);
- else
- hasOverflow = overflowed;
-
- size = CGF.Builder.CreateExtractValue(result, 0);
- }
-
- // If we had any possibility of dynamic overflow, make a select to
- // overwrite 'size' with an all-ones value, which should cause
- // operator new to throw.
- if (hasOverflow)
- size = CGF.Builder.CreateSelect(hasOverflow,
- llvm::Constant::getAllOnesValue(CGF.SizeTy),
- size);
- }
-
- if (cookieSize == 0)
- sizeWithoutCookie = size;
- else
- assert(sizeWithoutCookie && "didn't set sizeWithoutCookie?");
-
- return size;
-}
-
-static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
- QualType AllocType, Address NewPtr,
- AggValueSlot::Overlap_t MayOverlap) {
- // FIXME: Refactor with EmitExprAsInit.
- switch (CGF.getEvaluationKind(AllocType)) {
- case TEK_Scalar:
- CGF.EmitScalarInit(Init, nullptr,
- CGF.MakeAddrLValue(NewPtr, AllocType), false);
- return;
- case TEK_Complex:
- CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType),
- /*isInit*/ true);
- return;
- case TEK_Aggregate: {
- AggValueSlot Slot
- = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- MayOverlap, AggValueSlot::IsNotZeroed,
- AggValueSlot::IsSanitizerChecked);
- CGF.EmitAggExpr(Init, Slot);
- return;
- }
- }
- llvm_unreachable("bad evaluation kind");
-}
-
-void CodeGenFunction::EmitNewArrayInitializer(
- const CXXNewExpr *E, QualType ElementType, llvm::Type *ElementTy,
- Address BeginPtr, llvm::Value *NumElements,
- llvm::Value *AllocSizeWithoutCookie) {
- // If we have a type with trivial initialization and no initializer,
- // there's nothing to do.
- if (!E->hasInitializer())
- return;
-
- Address CurPtr = BeginPtr;
-
- unsigned InitListElements = 0;
-
- const Expr *Init = E->getInitializer();
- Address EndOfInit = Address::invalid();
- QualType::DestructionKind DtorKind = ElementType.isDestructedType();
- EHScopeStack::stable_iterator Cleanup;
- llvm::Instruction *CleanupDominator = nullptr;
-
- CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType);
- CharUnits ElementAlign =
- BeginPtr.getAlignment().alignmentOfArrayElement(ElementSize);
-
- // Attempt to perform zero-initialization using memset.
- auto TryMemsetInitialization = [&]() -> bool {
- // FIXME: If the type is a pointer-to-data-member under the Itanium ABI,
- // we can initialize with a memset to -1.
- if (!CGM.getTypes().isZeroInitializable(ElementType))
- return false;
-
- // Optimization: since zero initialization will just set the memory
- // to all zeroes, generate a single memset to do it in one shot.
-
- // Subtract out the size of any elements we've already initialized.
- auto *RemainingSize = AllocSizeWithoutCookie;
- if (InitListElements) {
- // We know this can't overflow; we check this when doing the allocation.
- auto *InitializedSize = llvm::ConstantInt::get(
- RemainingSize->getType(),
- getContext().getTypeSizeInChars(ElementType).getQuantity() *
- InitListElements);
- RemainingSize = Builder.CreateSub(RemainingSize, InitializedSize);
- }
-
- // Create the memset.
- Builder.CreateMemSet(CurPtr, Builder.getInt8(0), RemainingSize, false);
- return true;
- };
-
- // If the initializer is an initializer list, first do the explicit elements.
- if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- // Initializing from a (braced) string literal is a special case; the init
- // list element does not initialize a (single) array element.
- if (ILE->isStringLiteralInit()) {
- // Initialize the initial portion of length equal to that of the string
- // literal. The allocation must be for at least this much; we emitted a
- // check for that earlier.
- AggValueSlot Slot =
- AggValueSlot::forAddr(CurPtr, ElementType.getQualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap,
- AggValueSlot::IsNotZeroed,
- AggValueSlot::IsSanitizerChecked);
- EmitAggExpr(ILE->getInit(0), Slot);
-
- // Move past these elements.
- InitListElements =
- cast<ConstantArrayType>(ILE->getType()->getAsArrayTypeUnsafe())
- ->getSize().getZExtValue();
- CurPtr =
- Address(Builder.CreateInBoundsGEP(CurPtr.getPointer(),
- Builder.getSize(InitListElements),
- "string.init.end"),
- CurPtr.getAlignment().alignmentAtOffset(InitListElements *
- ElementSize));
-
- // Zero out the rest, if any remain.
- llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
- if (!ConstNum || !ConstNum->equalsInt(InitListElements)) {
- bool OK = TryMemsetInitialization();
- (void)OK;
- assert(OK && "couldn't memset character type?");
- }
- return;
- }
-
- InitListElements = ILE->getNumInits();
-
- // If this is a multi-dimensional array new, we will initialize multiple
- // elements with each init list element.
- QualType AllocType = E->getAllocatedType();
- if (const ConstantArrayType *CAT = dyn_cast_or_null<ConstantArrayType>(
- AllocType->getAsArrayTypeUnsafe())) {
- ElementTy = ConvertTypeForMem(AllocType);
- CurPtr = Builder.CreateElementBitCast(CurPtr, ElementTy);
- InitListElements *= getContext().getConstantArrayElementCount(CAT);
- }
-
- // Enter a partial-destruction Cleanup if necessary.
- if (needsEHCleanup(DtorKind)) {
- // In principle we could tell the Cleanup where we are more
- // directly, but the control flow can get so varied here that it
- // would actually be quite complex. Therefore we go through an
- // alloca.
- EndOfInit = CreateTempAlloca(BeginPtr.getType(), getPointerAlign(),
- "array.init.end");
- CleanupDominator = Builder.CreateStore(BeginPtr.getPointer(), EndOfInit);
- pushIrregularPartialArrayCleanup(BeginPtr.getPointer(), EndOfInit,
- ElementType, ElementAlign,
- getDestroyer(DtorKind));
- Cleanup = EHStack.stable_begin();
- }
-
- CharUnits StartAlign = CurPtr.getAlignment();
- for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) {
- // Tell the cleanup that it needs to destroy up to this
- // element. TODO: some of these stores can be trivially
- // observed to be unnecessary.
- if (EndOfInit.isValid()) {
- auto FinishedPtr =
- Builder.CreateBitCast(CurPtr.getPointer(), BeginPtr.getType());
- Builder.CreateStore(FinishedPtr, EndOfInit);
- }
- // FIXME: If the last initializer is an incomplete initializer list for
- // an array, and we have an array filler, we can fold together the two
- // initialization loops.
- StoreAnyExprIntoOneUnit(*this, ILE->getInit(i),
- ILE->getInit(i)->getType(), CurPtr,
- AggValueSlot::DoesNotOverlap);
- CurPtr = Address(Builder.CreateInBoundsGEP(CurPtr.getPointer(),
- Builder.getSize(1),
- "array.exp.next"),
- StartAlign.alignmentAtOffset((i + 1) * ElementSize));
- }
-
- // The remaining elements are filled with the array filler expression.
- Init = ILE->getArrayFiller();
-
- // Extract the initializer for the individual array elements by pulling
- // out the array filler from all the nested initializer lists. This avoids
- // generating a nested loop for the initialization.
- while (Init && Init->getType()->isConstantArrayType()) {
- auto *SubILE = dyn_cast<InitListExpr>(Init);
- if (!SubILE)
- break;
- assert(SubILE->getNumInits() == 0 && "explicit inits in array filler?");
- Init = SubILE->getArrayFiller();
- }
-
- // Switch back to initializing one base element at a time.
- CurPtr = Builder.CreateBitCast(CurPtr, BeginPtr.getType());
- }
-
- // If all elements have already been initialized, skip any further
- // initialization.
- llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
- if (ConstNum && ConstNum->getZExtValue() <= InitListElements) {
- // If there was a Cleanup, deactivate it.
- if (CleanupDominator)
- DeactivateCleanupBlock(Cleanup, CleanupDominator);
- return;
- }
-
- assert(Init && "have trailing elements to initialize but no initializer");
-
- // If this is a constructor call, try to optimize it out, and failing that
- // emit a single loop to initialize all remaining elements.
- if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
- CXXConstructorDecl *Ctor = CCE->getConstructor();
- if (Ctor->isTrivial()) {
- // If new expression did not specify value-initialization, then there
- // is no initialization.
- if (!CCE->requiresZeroInitialization() || Ctor->getParent()->isEmpty())
- return;
-
- if (TryMemsetInitialization())
- return;
- }
-
- // Store the new Cleanup position for irregular Cleanups.
- //
- // FIXME: Share this cleanup with the constructor call emission rather than
- // having it create a cleanup of its own.
- if (EndOfInit.isValid())
- Builder.CreateStore(CurPtr.getPointer(), EndOfInit);
-
- // Emit a constructor call loop to initialize the remaining elements.
- if (InitListElements)
- NumElements = Builder.CreateSub(
- NumElements,
- llvm::ConstantInt::get(NumElements->getType(), InitListElements));
- EmitCXXAggrConstructorCall(Ctor, NumElements, CurPtr, CCE,
- /*NewPointerIsChecked*/true,
- CCE->requiresZeroInitialization());
- return;
- }
-
- // If this is value-initialization, we can usually use memset.
- ImplicitValueInitExpr IVIE(ElementType);
- if (isa<ImplicitValueInitExpr>(Init)) {
- if (TryMemsetInitialization())
- return;
-
- // Switch to an ImplicitValueInitExpr for the element type. This handles
- // only one case: multidimensional array new of pointers to members. In
- // all other cases, we already have an initializer for the array element.
- Init = &IVIE;
- }
-
- // At this point we should have found an initializer for the individual
- // elements of the array.
- assert(getContext().hasSameUnqualifiedType(ElementType, Init->getType()) &&
- "got wrong type of element to initialize");
-
- // If we have an empty initializer list, we can usually use memset.
- if (auto *ILE = dyn_cast<InitListExpr>(Init))
- if (ILE->getNumInits() == 0 && TryMemsetInitialization())
- return;
-
- // If we have a struct whose every field is value-initialized, we can
- // usually use memset.
- if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
- if (RType->getDecl()->isStruct()) {
- unsigned NumElements = 0;
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RType->getDecl()))
- NumElements = CXXRD->getNumBases();
- for (auto *Field : RType->getDecl()->fields())
- if (!Field->isUnnamedBitfield())
- ++NumElements;
- // FIXME: Recurse into nested InitListExprs.
- if (ILE->getNumInits() == NumElements)
- for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
- if (!isa<ImplicitValueInitExpr>(ILE->getInit(i)))
- --NumElements;
- if (ILE->getNumInits() == NumElements && TryMemsetInitialization())
- return;
- }
- }
- }
-
- // Create the loop blocks.
- llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
- llvm::BasicBlock *LoopBB = createBasicBlock("new.loop");
- llvm::BasicBlock *ContBB = createBasicBlock("new.loop.end");
-
- // Find the end of the array, hoisted out of the loop.
- llvm::Value *EndPtr =
- Builder.CreateInBoundsGEP(BeginPtr.getPointer(), NumElements, "array.end");
-
- // If the number of elements isn't constant, we have to now check if there is
- // anything left to initialize.
- if (!ConstNum) {
- llvm::Value *IsEmpty =
- Builder.CreateICmpEQ(CurPtr.getPointer(), EndPtr, "array.isempty");
- Builder.CreateCondBr(IsEmpty, ContBB, LoopBB);
- }
-
- // Enter the loop.
- EmitBlock(LoopBB);
-
- // Set up the current-element phi.
- llvm::PHINode *CurPtrPhi =
- Builder.CreatePHI(CurPtr.getType(), 2, "array.cur");
- CurPtrPhi->addIncoming(CurPtr.getPointer(), EntryBB);
-
- CurPtr = Address(CurPtrPhi, ElementAlign);
-
- // Store the new Cleanup position for irregular Cleanups.
- if (EndOfInit.isValid())
- Builder.CreateStore(CurPtr.getPointer(), EndOfInit);
-
- // Enter a partial-destruction Cleanup if necessary.
- if (!CleanupDominator && needsEHCleanup(DtorKind)) {
- pushRegularPartialArrayCleanup(BeginPtr.getPointer(), CurPtr.getPointer(),
- ElementType, ElementAlign,
- getDestroyer(DtorKind));
- Cleanup = EHStack.stable_begin();
- CleanupDominator = Builder.CreateUnreachable();
- }
-
- // Emit the initializer into this element.
- StoreAnyExprIntoOneUnit(*this, Init, Init->getType(), CurPtr,
- AggValueSlot::DoesNotOverlap);
-
- // Leave the Cleanup if we entered one.
- if (CleanupDominator) {
- DeactivateCleanupBlock(Cleanup, CleanupDominator);
- CleanupDominator->eraseFromParent();
- }
-
- // Advance to the next element by adjusting the pointer type as necessary.
- llvm::Value *NextPtr =
- Builder.CreateConstInBoundsGEP1_32(ElementTy, CurPtr.getPointer(), 1,
- "array.next");
-
- // Check whether we've gotten to the end of the array and, if so,
- // exit the loop.
- llvm::Value *IsEnd = Builder.CreateICmpEQ(NextPtr, EndPtr, "array.atend");
- Builder.CreateCondBr(IsEnd, ContBB, LoopBB);
- CurPtrPhi->addIncoming(NextPtr, Builder.GetInsertBlock());
-
- EmitBlock(ContBB);
-}
-
-static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
- QualType ElementType, llvm::Type *ElementTy,
- Address NewPtr, llvm::Value *NumElements,
- llvm::Value *AllocSizeWithoutCookie) {
- ApplyDebugLocation DL(CGF, E);
- if (E->isArray())
- CGF.EmitNewArrayInitializer(E, ElementType, ElementTy, NewPtr, NumElements,
- AllocSizeWithoutCookie);
- else if (const Expr *Init = E->getInitializer())
- StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr,
- AggValueSlot::DoesNotOverlap);
-}
-
-/// Emit a call to an operator new or operator delete function, as implicitly
-/// created by new-expressions and delete-expressions.
-static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
- const FunctionDecl *CalleeDecl,
- const FunctionProtoType *CalleeType,
- const CallArgList &Args) {
- llvm::Instruction *CallOrInvoke;
- llvm::Constant *CalleePtr = CGF.CGM.GetAddrOfFunction(CalleeDecl);
- CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(CalleeDecl));
- RValue RV =
- CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(
- Args, CalleeType, /*chainCall=*/false),
- Callee, ReturnValueSlot(), Args, &CallOrInvoke);
-
- /// C++1y [expr.new]p10:
- /// [In a new-expression,] an implementation is allowed to omit a call
- /// to a replaceable global allocation function.
- ///
- /// We model such elidable calls with the 'builtin' attribute.
- llvm::Function *Fn = dyn_cast<llvm::Function>(CalleePtr);
- if (CalleeDecl->isReplaceableGlobalAllocationFunction() &&
- Fn && Fn->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
- // FIXME: Add addAttribute to CallSite.
- if (llvm::CallInst *CI = dyn_cast<llvm::CallInst>(CallOrInvoke))
- CI->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::Builtin);
- else if (llvm::InvokeInst *II = dyn_cast<llvm::InvokeInst>(CallOrInvoke))
- II->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::Builtin);
- else
- llvm_unreachable("unexpected kind of call instruction");
- }
-
- return RV;
-}
-
-RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
- const CallExpr *TheCall,
- bool IsDelete) {
- CallArgList Args;
- EmitCallArgs(Args, Type->getParamTypes(), TheCall->arguments());
- // Find the allocation or deallocation function that we're calling.
- ASTContext &Ctx = getContext();
- DeclarationName Name = Ctx.DeclarationNames
- .getCXXOperatorName(IsDelete ? OO_Delete : OO_New);
-
- for (auto *Decl : Ctx.getTranslationUnitDecl()->lookup(Name))
- if (auto *FD = dyn_cast<FunctionDecl>(Decl))
- if (Ctx.hasSameType(FD->getType(), QualType(Type, 0)))
- return EmitNewDeleteCall(*this, FD, Type, Args);
- llvm_unreachable("predeclared global operator new/delete is missing");
-}
-
-namespace {
-/// The parameters to pass to a usual operator delete.
-struct UsualDeleteParams {
- bool DestroyingDelete = false;
- bool Size = false;
- bool Alignment = false;
-};
-}
-
-static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *FD) {
- UsualDeleteParams Params;
-
- const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
- auto AI = FPT->param_type_begin(), AE = FPT->param_type_end();
-
- // The first argument is always a void*.
- ++AI;
-
- // The next parameter may be a std::destroying_delete_t.
- if (FD->isDestroyingOperatorDelete()) {
- Params.DestroyingDelete = true;
- assert(AI != AE);
- ++AI;
- }
-
- // Figure out what other parameters we should be implicitly passing.
- if (AI != AE && (*AI)->isIntegerType()) {
- Params.Size = true;
- ++AI;
- }
-
- if (AI != AE && (*AI)->isAlignValT()) {
- Params.Alignment = true;
- ++AI;
- }
-
- assert(AI == AE && "unexpected usual deallocation function parameter");
- return Params;
-}
-
-namespace {
- /// A cleanup to call the given 'operator delete' function upon abnormal
- /// exit from a new expression. Templated on a traits type that deals with
- /// ensuring that the arguments dominate the cleanup if necessary.
- template<typename Traits>
- class CallDeleteDuringNew final : public EHScopeStack::Cleanup {
- /// Type used to hold llvm::Value*s.
- typedef typename Traits::ValueTy ValueTy;
- /// Type used to hold RValues.
- typedef typename Traits::RValueTy RValueTy;
- struct PlacementArg {
- RValueTy ArgValue;
- QualType ArgType;
- };
-
- unsigned NumPlacementArgs : 31;
- unsigned PassAlignmentToPlacementDelete : 1;
- const FunctionDecl *OperatorDelete;
- ValueTy Ptr;
- ValueTy AllocSize;
- CharUnits AllocAlign;
-
- PlacementArg *getPlacementArgs() {
- return reinterpret_cast<PlacementArg *>(this + 1);
- }
-
- public:
- static size_t getExtraSize(size_t NumPlacementArgs) {
- return NumPlacementArgs * sizeof(PlacementArg);
- }
-
- CallDeleteDuringNew(size_t NumPlacementArgs,
- const FunctionDecl *OperatorDelete, ValueTy Ptr,
- ValueTy AllocSize, bool PassAlignmentToPlacementDelete,
- CharUnits AllocAlign)
- : NumPlacementArgs(NumPlacementArgs),
- PassAlignmentToPlacementDelete(PassAlignmentToPlacementDelete),
- OperatorDelete(OperatorDelete), Ptr(Ptr), AllocSize(AllocSize),
- AllocAlign(AllocAlign) {}
-
- void setPlacementArg(unsigned I, RValueTy Arg, QualType Type) {
- assert(I < NumPlacementArgs && "index out of range");
- getPlacementArgs()[I] = {Arg, Type};
- }
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- const FunctionProtoType *FPT =
- OperatorDelete->getType()->getAs<FunctionProtoType>();
- CallArgList DeleteArgs;
-
- // The first argument is always a void* (or C* for a destroying operator
- // delete for class type C).
- DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(0));
-
- // Figure out what other parameters we should be implicitly passing.
- UsualDeleteParams Params;
- if (NumPlacementArgs) {
- // A placement deallocation function is implicitly passed an alignment
- // if the placement allocation function was, but is never passed a size.
- Params.Alignment = PassAlignmentToPlacementDelete;
- } else {
- // For a non-placement new-expression, 'operator delete' can take a
- // size and/or an alignment if it has the right parameters.
- Params = getUsualDeleteParams(OperatorDelete);
- }
-
- assert(!Params.DestroyingDelete &&
- "should not call destroying delete in a new-expression");
-
- // The second argument can be a std::size_t (for non-placement delete).
- if (Params.Size)
- DeleteArgs.add(Traits::get(CGF, AllocSize),
- CGF.getContext().getSizeType());
-
- // The next (second or third) argument can be a std::align_val_t, which
- // is an enum whose underlying type is std::size_t.
- // FIXME: Use the right type as the parameter type. Note that in a call
- // to operator delete(size_t, ...), we may not have it available.
- if (Params.Alignment)
- DeleteArgs.add(RValue::get(llvm::ConstantInt::get(
- CGF.SizeTy, AllocAlign.getQuantity())),
- CGF.getContext().getSizeType());
-
- // Pass the rest of the arguments, which must match exactly.
- for (unsigned I = 0; I != NumPlacementArgs; ++I) {
- auto Arg = getPlacementArgs()[I];
- DeleteArgs.add(Traits::get(CGF, Arg.ArgValue), Arg.ArgType);
- }
-
- // Call 'operator delete'.
- EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs);
- }
- };
-}
-
-/// Enter a cleanup to call 'operator delete' if the initializer in a
-/// new-expression throws.
-static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
- const CXXNewExpr *E,
- Address NewPtr,
- llvm::Value *AllocSize,
- CharUnits AllocAlign,
- const CallArgList &NewArgs) {
- unsigned NumNonPlacementArgs = E->passAlignment() ? 2 : 1;
-
- // If we're not inside a conditional branch, then the cleanup will
- // dominate and we can do the easier (and more efficient) thing.
- if (!CGF.isInConditionalBranch()) {
- struct DirectCleanupTraits {
- typedef llvm::Value *ValueTy;
- typedef RValue RValueTy;
- static RValue get(CodeGenFunction &, ValueTy V) { return RValue::get(V); }
- static RValue get(CodeGenFunction &, RValueTy V) { return V; }
- };
-
- typedef CallDeleteDuringNew<DirectCleanupTraits> DirectCleanup;
-
- DirectCleanup *Cleanup = CGF.EHStack
- .pushCleanupWithExtra<DirectCleanup>(EHCleanup,
- E->getNumPlacementArgs(),
- E->getOperatorDelete(),
- NewPtr.getPointer(),
- AllocSize,
- E->passAlignment(),
- AllocAlign);
- for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
- auto &Arg = NewArgs[I + NumNonPlacementArgs];
- Cleanup->setPlacementArg(I, Arg.getRValue(CGF), Arg.Ty);
- }
-
- return;
- }
-
- // Otherwise, we need to save all this stuff.
- DominatingValue<RValue>::saved_type SavedNewPtr =
- DominatingValue<RValue>::save(CGF, RValue::get(NewPtr.getPointer()));
- DominatingValue<RValue>::saved_type SavedAllocSize =
- DominatingValue<RValue>::save(CGF, RValue::get(AllocSize));
-
- struct ConditionalCleanupTraits {
- typedef DominatingValue<RValue>::saved_type ValueTy;
- typedef DominatingValue<RValue>::saved_type RValueTy;
- static RValue get(CodeGenFunction &CGF, ValueTy V) {
- return V.restore(CGF);
- }
- };
- typedef CallDeleteDuringNew<ConditionalCleanupTraits> ConditionalCleanup;
-
- ConditionalCleanup *Cleanup = CGF.EHStack
- .pushCleanupWithExtra<ConditionalCleanup>(EHCleanup,
- E->getNumPlacementArgs(),
- E->getOperatorDelete(),
- SavedNewPtr,
- SavedAllocSize,
- E->passAlignment(),
- AllocAlign);
- for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
- auto &Arg = NewArgs[I + NumNonPlacementArgs];
- Cleanup->setPlacementArg(
- I, DominatingValue<RValue>::save(CGF, Arg.getRValue(CGF)), Arg.Ty);
- }
-
- CGF.initFullExprCleanup();
-}
-
-llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
- // The element type being allocated.
- QualType allocType = getContext().getBaseElementType(E->getAllocatedType());
-
- // 1. Build a call to the allocation function.
- FunctionDecl *allocator = E->getOperatorNew();
-
- // If there is a brace-initializer, cannot allocate fewer elements than inits.
- unsigned minElements = 0;
- if (E->isArray() && E->hasInitializer()) {
- const InitListExpr *ILE = dyn_cast<InitListExpr>(E->getInitializer());
- if (ILE && ILE->isStringLiteralInit())
- minElements =
- cast<ConstantArrayType>(ILE->getType()->getAsArrayTypeUnsafe())
- ->getSize().getZExtValue();
- else if (ILE)
- minElements = ILE->getNumInits();
- }
-
- llvm::Value *numElements = nullptr;
- llvm::Value *allocSizeWithoutCookie = nullptr;
- llvm::Value *allocSize =
- EmitCXXNewAllocSize(*this, E, minElements, numElements,
- allocSizeWithoutCookie);
- CharUnits allocAlign = getContext().getTypeAlignInChars(allocType);
-
- // Emit the allocation call. If the allocator is a global placement
- // operator, just "inline" it directly.
- Address allocation = Address::invalid();
- CallArgList allocatorArgs;
- if (allocator->isReservedGlobalPlacementOperator()) {
- assert(E->getNumPlacementArgs() == 1);
- const Expr *arg = *E->placement_arguments().begin();
-
- LValueBaseInfo BaseInfo;
- allocation = EmitPointerWithAlignment(arg, &BaseInfo);
-
- // The pointer expression will, in many cases, be an opaque void*.
- // In these cases, discard the computed alignment and use the
- // formal alignment of the allocated type.
- if (BaseInfo.getAlignmentSource() != AlignmentSource::Decl)
- allocation = Address(allocation.getPointer(), allocAlign);
-
- // Set up allocatorArgs for the call to operator delete if it's not
- // the reserved global operator.
- if (E->getOperatorDelete() &&
- !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
- allocatorArgs.add(RValue::get(allocSize), getContext().getSizeType());
- allocatorArgs.add(RValue::get(allocation.getPointer()), arg->getType());
- }
-
- } else {
- const FunctionProtoType *allocatorType =
- allocator->getType()->castAs<FunctionProtoType>();
- unsigned ParamsToSkip = 0;
-
- // The allocation size is the first argument.
- QualType sizeType = getContext().getSizeType();
- allocatorArgs.add(RValue::get(allocSize), sizeType);
- ++ParamsToSkip;
-
- if (allocSize != allocSizeWithoutCookie) {
- CharUnits cookieAlign = getSizeAlign(); // FIXME: Ask the ABI.
- allocAlign = std::max(allocAlign, cookieAlign);
- }
-
- // The allocation alignment may be passed as the second argument.
- if (E->passAlignment()) {
- QualType AlignValT = sizeType;
- if (allocatorType->getNumParams() > 1) {
- AlignValT = allocatorType->getParamType(1);
- assert(getContext().hasSameUnqualifiedType(
- AlignValT->castAs<EnumType>()->getDecl()->getIntegerType(),
- sizeType) &&
- "wrong type for alignment parameter");
- ++ParamsToSkip;
- } else {
- // Corner case, passing alignment to 'operator new(size_t, ...)'.
- assert(allocator->isVariadic() && "can't pass alignment to allocator");
- }
- allocatorArgs.add(
- RValue::get(llvm::ConstantInt::get(SizeTy, allocAlign.getQuantity())),
- AlignValT);
- }
-
- // FIXME: Why do we not pass a CalleeDecl here?
- EmitCallArgs(allocatorArgs, allocatorType, E->placement_arguments(),
- /*AC*/AbstractCallee(), /*ParamsToSkip*/ParamsToSkip);
-
- RValue RV =
- EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
-
- // If this was a call to a global replaceable allocation function that does
- // not take an alignment argument, the allocator is known to produce
- // storage that's suitably aligned for any object that fits, up to a known
- // threshold. Otherwise assume it's suitably aligned for the allocated type.
- CharUnits allocationAlign = allocAlign;
- if (!E->passAlignment() &&
- allocator->isReplaceableGlobalAllocationFunction()) {
- unsigned AllocatorAlign = llvm::PowerOf2Floor(std::min<uint64_t>(
- Target.getNewAlign(), getContext().getTypeSize(allocType)));
- allocationAlign = std::max(
- allocationAlign, getContext().toCharUnitsFromBits(AllocatorAlign));
- }
-
- allocation = Address(RV.getScalarVal(), allocationAlign);
- }
-
- // Emit a null check on the allocation result if the allocation
- // function is allowed to return null (because it has a non-throwing
- // exception spec or is the reserved placement new) and we have an
- // interesting initializer will be running sanitizers on the initialization.
- bool nullCheck = E->shouldNullCheckAllocation() &&
- (!allocType.isPODType(getContext()) || E->hasInitializer() ||
- sanitizePerformTypeCheck());
-
- llvm::BasicBlock *nullCheckBB = nullptr;
- llvm::BasicBlock *contBB = nullptr;
-
- // The null-check means that the initializer is conditionally
- // evaluated.
- ConditionalEvaluation conditional(*this);
-
- if (nullCheck) {
- conditional.begin(*this);
-
- nullCheckBB = Builder.GetInsertBlock();
- llvm::BasicBlock *notNullBB = createBasicBlock("new.notnull");
- contBB = createBasicBlock("new.cont");
-
- llvm::Value *isNull =
- Builder.CreateIsNull(allocation.getPointer(), "new.isnull");
- Builder.CreateCondBr(isNull, contBB, notNullBB);
- EmitBlock(notNullBB);
- }
-
- // If there's an operator delete, enter a cleanup to call it if an
- // exception is thrown.
- EHScopeStack::stable_iterator operatorDeleteCleanup;
- llvm::Instruction *cleanupDominator = nullptr;
- if (E->getOperatorDelete() &&
- !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
- EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocAlign,
- allocatorArgs);
- operatorDeleteCleanup = EHStack.stable_begin();
- cleanupDominator = Builder.CreateUnreachable();
- }
-
- assert((allocSize == allocSizeWithoutCookie) ==
- CalculateCookiePadding(*this, E).isZero());
- if (allocSize != allocSizeWithoutCookie) {
- assert(E->isArray());
- allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation,
- numElements,
- E, allocType);
- }
-
- llvm::Type *elementTy = ConvertTypeForMem(allocType);
- Address result = Builder.CreateElementBitCast(allocation, elementTy);
-
- // Passing pointer through launder.invariant.group to avoid propagation of
- // vptrs information which may be included in previous type.
- // To not break LTO with different optimizations levels, we do it regardless
- // of optimization level.
- if (CGM.getCodeGenOpts().StrictVTablePointers &&
- allocator->isReservedGlobalPlacementOperator())
- result = Address(Builder.CreateLaunderInvariantGroup(result.getPointer()),
- result.getAlignment());
-
- // Emit sanitizer checks for pointer value now, so that in the case of an
- // array it was checked only once and not at each constructor call.
- EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall,
- E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
- result.getPointer(), allocType);
-
- EmitNewInitializer(*this, E, allocType, elementTy, result, numElements,
- allocSizeWithoutCookie);
- if (E->isArray()) {
- // NewPtr is a pointer to the base element type. If we're
- // allocating an array of arrays, we'll need to cast back to the
- // array pointer type.
- llvm::Type *resultType = ConvertTypeForMem(E->getType());
- if (result.getType() != resultType)
- result = Builder.CreateBitCast(result, resultType);
- }
-
- // Deactivate the 'operator delete' cleanup if we finished
- // initialization.
- if (operatorDeleteCleanup.isValid()) {
- DeactivateCleanupBlock(operatorDeleteCleanup, cleanupDominator);
- cleanupDominator->eraseFromParent();
- }
-
- llvm::Value *resultPtr = result.getPointer();
- if (nullCheck) {
- conditional.end(*this);
-
- llvm::BasicBlock *notNullBB = Builder.GetInsertBlock();
- EmitBlock(contBB);
-
- llvm::PHINode *PHI = Builder.CreatePHI(resultPtr->getType(), 2);
- PHI->addIncoming(resultPtr, notNullBB);
- PHI->addIncoming(llvm::Constant::getNullValue(resultPtr->getType()),
- nullCheckBB);
-
- resultPtr = PHI;
- }
-
- return resultPtr;
-}
-
-void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
- llvm::Value *Ptr, QualType DeleteTy,
- llvm::Value *NumElements,
- CharUnits CookieSize) {
- assert((!NumElements && CookieSize.isZero()) ||
- DeleteFD->getOverloadedOperator() == OO_Array_Delete);
-
- const FunctionProtoType *DeleteFTy =
- DeleteFD->getType()->getAs<FunctionProtoType>();
-
- CallArgList DeleteArgs;
-
- auto Params = getUsualDeleteParams(DeleteFD);
- auto ParamTypeIt = DeleteFTy->param_type_begin();
-
- // Pass the pointer itself.
- QualType ArgTy = *ParamTypeIt++;
- llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
- DeleteArgs.add(RValue::get(DeletePtr), ArgTy);
-
- // Pass the std::destroying_delete tag if present.
- if (Params.DestroyingDelete) {
- QualType DDTag = *ParamTypeIt++;
- // Just pass an 'undef'. We expect the tag type to be an empty struct.
- auto *V = llvm::UndefValue::get(getTypes().ConvertType(DDTag));
- DeleteArgs.add(RValue::get(V), DDTag);
- }
-
- // Pass the size if the delete function has a size_t parameter.
- if (Params.Size) {
- QualType SizeType = *ParamTypeIt++;
- CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
- llvm::Value *Size = llvm::ConstantInt::get(ConvertType(SizeType),
- DeleteTypeSize.getQuantity());
-
- // For array new, multiply by the number of elements.
- if (NumElements)
- Size = Builder.CreateMul(Size, NumElements);
-
- // If there is a cookie, add the cookie size.
- if (!CookieSize.isZero())
- Size = Builder.CreateAdd(
- Size, llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()));
-
- DeleteArgs.add(RValue::get(Size), SizeType);
- }
-
- // Pass the alignment if the delete function has an align_val_t parameter.
- if (Params.Alignment) {
- QualType AlignValType = *ParamTypeIt++;
- CharUnits DeleteTypeAlign = getContext().toCharUnitsFromBits(
- getContext().getTypeAlignIfKnown(DeleteTy));
- llvm::Value *Align = llvm::ConstantInt::get(ConvertType(AlignValType),
- DeleteTypeAlign.getQuantity());
- DeleteArgs.add(RValue::get(Align), AlignValType);
- }
-
- assert(ParamTypeIt == DeleteFTy->param_type_end() &&
- "unknown parameter to usual delete function");
-
- // Emit the call to delete.
- EmitNewDeleteCall(*this, DeleteFD, DeleteFTy, DeleteArgs);
-}
-
-namespace {
- /// Calls the given 'operator delete' on a single object.
- struct CallObjectDelete final : EHScopeStack::Cleanup {
- llvm::Value *Ptr;
- const FunctionDecl *OperatorDelete;
- QualType ElementType;
-
- CallObjectDelete(llvm::Value *Ptr,
- const FunctionDecl *OperatorDelete,
- QualType ElementType)
- : Ptr(Ptr), OperatorDelete(OperatorDelete), ElementType(ElementType) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType);
- }
- };
-}
-
-void
-CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
- llvm::Value *CompletePtr,
- QualType ElementType) {
- EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup, CompletePtr,
- OperatorDelete, ElementType);
-}
-
-/// Emit the code for deleting a single object with a destroying operator
-/// delete. If the element type has a non-virtual destructor, Ptr has already
-/// been converted to the type of the parameter of 'operator delete'. Otherwise
-/// Ptr points to an object of the static type.
-static void EmitDestroyingObjectDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE, Address Ptr,
- QualType ElementType) {
- auto *Dtor = ElementType->getAsCXXRecordDecl()->getDestructor();
- if (Dtor && Dtor->isVirtual())
- CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType,
- Dtor);
- else
- CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.getPointer(), ElementType);
-}
-
-/// Emit the code for deleting a single object.
-static void EmitObjectDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- Address Ptr,
- QualType ElementType) {
- // C++11 [expr.delete]p3:
- // If the static type of the object to be deleted is different from its
- // dynamic type, the static type shall be a base class of the dynamic type
- // of the object to be deleted and the static type shall have a virtual
- // destructor or the behavior is undefined.
- CGF.EmitTypeCheck(CodeGenFunction::TCK_MemberCall,
- DE->getExprLoc(), Ptr.getPointer(),
- ElementType);
-
- const FunctionDecl *OperatorDelete = DE->getOperatorDelete();
- assert(!OperatorDelete->isDestroyingOperatorDelete());
-
- // Find the destructor for the type, if applicable. If the
- // destructor is virtual, we'll just emit the vcall and return.
- const CXXDestructorDecl *Dtor = nullptr;
- if (const RecordType *RT = ElementType->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasDefinition() && !RD->hasTrivialDestructor()) {
- Dtor = RD->getDestructor();
-
- if (Dtor->isVirtual()) {
- CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType,
- Dtor);
- return;
- }
- }
- }
-
- // Make sure that we call delete even if the dtor throws.
- // This doesn't have to a conditional cleanup because we're going
- // to pop it off in a second.
- CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
- Ptr.getPointer(),
- OperatorDelete, ElementType);
-
- if (Dtor)
- CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false,
- /*Delegating=*/false,
- Ptr);
- else if (auto Lifetime = ElementType.getObjCLifetime()) {
- switch (Lifetime) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- break;
-
- case Qualifiers::OCL_Strong:
- CGF.EmitARCDestroyStrong(Ptr, ARCPreciseLifetime);
- break;
-
- case Qualifiers::OCL_Weak:
- CGF.EmitARCDestroyWeak(Ptr);
- break;
- }
- }
-
- CGF.PopCleanupBlock();
-}
-
-namespace {
- /// Calls the given 'operator delete' on an array of objects.
- struct CallArrayDelete final : EHScopeStack::Cleanup {
- llvm::Value *Ptr;
- const FunctionDecl *OperatorDelete;
- llvm::Value *NumElements;
- QualType ElementType;
- CharUnits CookieSize;
-
- CallArrayDelete(llvm::Value *Ptr,
- const FunctionDecl *OperatorDelete,
- llvm::Value *NumElements,
- QualType ElementType,
- CharUnits CookieSize)
- : Ptr(Ptr), OperatorDelete(OperatorDelete), NumElements(NumElements),
- ElementType(ElementType), CookieSize(CookieSize) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType, NumElements,
- CookieSize);
- }
- };
-}
-
-/// Emit the code for deleting an array of objects.
-static void EmitArrayDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *E,
- Address deletedPtr,
- QualType elementType) {
- llvm::Value *numElements = nullptr;
- llvm::Value *allocatedPtr = nullptr;
- CharUnits cookieSize;
- CGF.CGM.getCXXABI().ReadArrayCookie(CGF, deletedPtr, E, elementType,
- numElements, allocatedPtr, cookieSize);
-
- assert(allocatedPtr && "ReadArrayCookie didn't set allocated pointer");
-
- // Make sure that we call delete even if one of the dtors throws.
- const FunctionDecl *operatorDelete = E->getOperatorDelete();
- CGF.EHStack.pushCleanup<CallArrayDelete>(NormalAndEHCleanup,
- allocatedPtr, operatorDelete,
- numElements, elementType,
- cookieSize);
-
- // Destroy the elements.
- if (QualType::DestructionKind dtorKind = elementType.isDestructedType()) {
- assert(numElements && "no element count for a type with a destructor!");
-
- CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
- CharUnits elementAlign =
- deletedPtr.getAlignment().alignmentOfArrayElement(elementSize);
-
- llvm::Value *arrayBegin = deletedPtr.getPointer();
- llvm::Value *arrayEnd =
- CGF.Builder.CreateInBoundsGEP(arrayBegin, numElements, "delete.end");
-
- // Note that it is legal to allocate a zero-length array, and we
- // can never fold the check away because the length should always
- // come from a cookie.
- CGF.emitArrayDestroy(arrayBegin, arrayEnd, elementType, elementAlign,
- CGF.getDestroyer(dtorKind),
- /*checkZeroLength*/ true,
- CGF.needsEHCleanup(dtorKind));
- }
-
- // Pop the cleanup block.
- CGF.PopCleanupBlock();
-}
-
-void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
- const Expr *Arg = E->getArgument();
- Address Ptr = EmitPointerWithAlignment(Arg);
-
- // Null check the pointer.
- llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull");
- llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end");
-
- llvm::Value *IsNull = Builder.CreateIsNull(Ptr.getPointer(), "isnull");
-
- Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
- EmitBlock(DeleteNotNull);
-
- QualType DeleteTy = E->getDestroyedType();
-
- // A destroying operator delete overrides the entire operation of the
- // delete expression.
- if (E->getOperatorDelete()->isDestroyingOperatorDelete()) {
- EmitDestroyingObjectDelete(*this, E, Ptr, DeleteTy);
- EmitBlock(DeleteEnd);
- return;
- }
-
- // We might be deleting a pointer to array. If so, GEP down to the
- // first non-array element.
- // (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*)
- if (DeleteTy->isConstantArrayType()) {
- llvm::Value *Zero = Builder.getInt32(0);
- SmallVector<llvm::Value*,8> GEP;
-
- GEP.push_back(Zero); // point at the outermost array
-
- // For each layer of array type we're pointing at:
- while (const ConstantArrayType *Arr
- = getContext().getAsConstantArrayType(DeleteTy)) {
- // 1. Unpeel the array type.
- DeleteTy = Arr->getElementType();
-
- // 2. GEP to the first element of the array.
- GEP.push_back(Zero);
- }
-
- Ptr = Address(Builder.CreateInBoundsGEP(Ptr.getPointer(), GEP, "del.first"),
- Ptr.getAlignment());
- }
-
- assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType());
-
- if (E->isArrayForm()) {
- EmitArrayDelete(*this, E, Ptr, DeleteTy);
- } else {
- EmitObjectDelete(*this, E, Ptr, DeleteTy);
- }
-
- EmitBlock(DeleteEnd);
-}
-
-static bool isGLValueFromPointerDeref(const Expr *E) {
- E = E->IgnoreParens();
-
- if (const auto *CE = dyn_cast<CastExpr>(E)) {
- if (!CE->getSubExpr()->isGLValue())
- return false;
- return isGLValueFromPointerDeref(CE->getSubExpr());
- }
-
- if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
- return isGLValueFromPointerDeref(OVE->getSourceExpr());
-
- if (const auto *BO = dyn_cast<BinaryOperator>(E))
- if (BO->getOpcode() == BO_Comma)
- return isGLValueFromPointerDeref(BO->getRHS());
-
- if (const auto *ACO = dyn_cast<AbstractConditionalOperator>(E))
- return isGLValueFromPointerDeref(ACO->getTrueExpr()) ||
- isGLValueFromPointerDeref(ACO->getFalseExpr());
-
- // C++11 [expr.sub]p1:
- // The expression E1[E2] is identical (by definition) to *((E1)+(E2))
- if (isa<ArraySubscriptExpr>(E))
- return true;
-
- if (const auto *UO = dyn_cast<UnaryOperator>(E))
- if (UO->getOpcode() == UO_Deref)
- return true;
-
- return false;
-}
-
-static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E,
- llvm::Type *StdTypeInfoPtrTy) {
- // Get the vtable pointer.
- Address ThisPtr = CGF.EmitLValue(E).getAddress();
-
- QualType SrcRecordTy = E->getType();
-
- // C++ [class.cdtor]p4:
- // If the operand of typeid refers to the object under construction or
- // destruction and the static type of the operand is neither the constructor
- // or destructor’s class nor one of its bases, the behavior is undefined.
- CGF.EmitTypeCheck(CodeGenFunction::TCK_DynamicOperation, E->getExprLoc(),
- ThisPtr.getPointer(), SrcRecordTy);
-
- // C++ [expr.typeid]p2:
- // If the glvalue expression is obtained by applying the unary * operator to
- // a pointer and the pointer is a null pointer value, the typeid expression
- // throws the std::bad_typeid exception.
- //
- // However, this paragraph's intent is not clear. We choose a very generous
- // interpretation which implores us to consider comma operators, conditional
- // operators, parentheses and other such constructs.
- if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(
- isGLValueFromPointerDeref(E), SrcRecordTy)) {
- llvm::BasicBlock *BadTypeidBlock =
- CGF.createBasicBlock("typeid.bad_typeid");
- llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end");
-
- llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr.getPointer());
- CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
-
- CGF.EmitBlock(BadTypeidBlock);
- CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);
- CGF.EmitBlock(EndBlock);
- }
-
- return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,
- StdTypeInfoPtrTy);
-}
-
-llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
- llvm::Type *StdTypeInfoPtrTy =
- ConvertType(E->getType())->getPointerTo();
-
- if (E->isTypeOperand()) {
- llvm::Constant *TypeInfo =
- CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand(getContext()));
- return Builder.CreateBitCast(TypeInfo, StdTypeInfoPtrTy);
- }
-
- // C++ [expr.typeid]p2:
- // When typeid is applied to a glvalue expression whose type is a
- // polymorphic class type, the result refers to a std::type_info object
- // representing the type of the most derived object (that is, the dynamic
- // type) to which the glvalue refers.
- if (E->isPotentiallyEvaluated())
- return EmitTypeidFromVTable(*this, E->getExprOperand(),
- StdTypeInfoPtrTy);
-
- QualType OperandTy = E->getExprOperand()->getType();
- return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(OperandTy),
- StdTypeInfoPtrTy);
-}
-
-static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
- QualType DestTy) {
- llvm::Type *DestLTy = CGF.ConvertType(DestTy);
- if (DestTy->isPointerType())
- return llvm::Constant::getNullValue(DestLTy);
-
- /// C++ [expr.dynamic.cast]p9:
- /// A failed cast to reference type throws std::bad_cast
- if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
- return nullptr;
-
- CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));
- return llvm::UndefValue::get(DestLTy);
-}
-
-llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr,
- const CXXDynamicCastExpr *DCE) {
- CGM.EmitExplicitCastExprType(DCE, this);
- QualType DestTy = DCE->getTypeAsWritten();
-
- QualType SrcTy = DCE->getSubExpr()->getType();
-
- // C++ [expr.dynamic.cast]p7:
- // If T is "pointer to cv void," then the result is a pointer to the most
- // derived object pointed to by v.
- const PointerType *DestPTy = DestTy->getAs<PointerType>();
-
- bool isDynamicCastToVoid;
- QualType SrcRecordTy;
- QualType DestRecordTy;
- if (DestPTy) {
- isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType();
- SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
- DestRecordTy = DestPTy->getPointeeType();
- } else {
- isDynamicCastToVoid = false;
- SrcRecordTy = SrcTy;
- DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
- }
-
- // C++ [class.cdtor]p5:
- // If the operand of the dynamic_cast refers to the object under
- // construction or destruction and the static type of the operand is not a
- // pointer to or object of the constructor or destructor’s own class or one
- // of its bases, the dynamic_cast results in undefined behavior.
- EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr.getPointer(),
- SrcRecordTy);
-
- if (DCE->isAlwaysNull())
- if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
- return T;
-
- assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
-
- // C++ [expr.dynamic.cast]p4:
- // If the value of v is a null pointer value in the pointer case, the result
- // is the null pointer value of type T.
- bool ShouldNullCheckSrcValue =
- CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
- SrcRecordTy);
-
- llvm::BasicBlock *CastNull = nullptr;
- llvm::BasicBlock *CastNotNull = nullptr;
- llvm::BasicBlock *CastEnd = createBasicBlock("dynamic_cast.end");
-
- if (ShouldNullCheckSrcValue) {
- CastNull = createBasicBlock("dynamic_cast.null");
- CastNotNull = createBasicBlock("dynamic_cast.notnull");
-
- llvm::Value *IsNull = Builder.CreateIsNull(ThisAddr.getPointer());
- Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
- EmitBlock(CastNotNull);
- }
-
- llvm::Value *Value;
- if (isDynamicCastToVoid) {
- Value = CGM.getCXXABI().EmitDynamicCastToVoid(*this, ThisAddr, SrcRecordTy,
- DestTy);
- } else {
- assert(DestRecordTy->isRecordType() &&
- "destination type must be a record type!");
- Value = CGM.getCXXABI().EmitDynamicCastCall(*this, ThisAddr, SrcRecordTy,
- DestTy, DestRecordTy, CastEnd);
- CastNotNull = Builder.GetInsertBlock();
- }
-
- if (ShouldNullCheckSrcValue) {
- EmitBranch(CastEnd);
-
- EmitBlock(CastNull);
- EmitBranch(CastEnd);
- }
-
- EmitBlock(CastEnd);
-
- if (ShouldNullCheckSrcValue) {
- llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2);
- PHI->addIncoming(Value, CastNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull);
-
- Value = PHI;
- }
-
- return Value;
-}
-
-void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) {
- LValue SlotLV = MakeAddrLValue(Slot.getAddress(), E->getType());
-
- CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
- for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(),
- e = E->capture_init_end();
- i != e; ++i, ++CurField) {
- // Emit initialization
- LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
- if (CurField->hasCapturedVLAType()) {
- auto VAT = CurField->getCapturedVLAType();
- EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV);
- } else {
- EmitInitializerForField(*CurField, LV, *i);
- }
- }
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
deleted file mode 100644
index 2db693b44c9..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
+++ /dev/null
@@ -1,1158 +0,0 @@
-//===--- CGExprComplex.cpp - Emit LLVM Code for Complex Exprs -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Expr nodes with complex types as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "clang/AST/StmtVisitor.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/IR/Metadata.h"
-#include <algorithm>
-using namespace clang;
-using namespace CodeGen;
-
-//===----------------------------------------------------------------------===//
-// Complex Expression Emitter
-//===----------------------------------------------------------------------===//
-
-typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
-
-/// Return the complex type that we are meant to emit.
-static const ComplexType *getComplexType(QualType type) {
- type = type.getCanonicalType();
- if (const ComplexType *comp = dyn_cast<ComplexType>(type)) {
- return comp;
- } else {
- return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
- }
-}
-
-namespace {
-class ComplexExprEmitter
- : public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
- CodeGenFunction &CGF;
- CGBuilderTy &Builder;
- bool IgnoreReal;
- bool IgnoreImag;
-public:
- ComplexExprEmitter(CodeGenFunction &cgf, bool ir=false, bool ii=false)
- : CGF(cgf), Builder(CGF.Builder), IgnoreReal(ir), IgnoreImag(ii) {
- }
-
-
- //===--------------------------------------------------------------------===//
- // Utilities
- //===--------------------------------------------------------------------===//
-
- bool TestAndClearIgnoreReal() {
- bool I = IgnoreReal;
- IgnoreReal = false;
- return I;
- }
- bool TestAndClearIgnoreImag() {
- bool I = IgnoreImag;
- IgnoreImag = false;
- return I;
- }
-
- /// EmitLoadOfLValue - Given an expression with complex type that represents a
- /// value l-value, this method emits the address of the l-value, then loads
- /// and returns the result.
- ComplexPairTy EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc());
- }
-
- ComplexPairTy EmitLoadOfLValue(LValue LV, SourceLocation Loc);
-
- /// EmitStoreOfComplex - Store the specified real/imag parts into the
- /// specified value pointer.
- void EmitStoreOfComplex(ComplexPairTy Val, LValue LV, bool isInit);
-
- /// Emit a cast from complex value Val to DestType.
- ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
- QualType DestType, SourceLocation Loc);
- /// Emit a cast from scalar value Val to DestType.
- ComplexPairTy EmitScalarToComplexCast(llvm::Value *Val, QualType SrcType,
- QualType DestType, SourceLocation Loc);
-
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- ComplexPairTy Visit(Expr *E) {
- ApplyDebugLocation DL(CGF, E);
- return StmtVisitor<ComplexExprEmitter, ComplexPairTy>::Visit(E);
- }
-
- ComplexPairTy VisitStmt(Stmt *S) {
- S->dump(CGF.getContext().getSourceManager());
- llvm_unreachable("Stmt can't have complex result type!");
- }
- ComplexPairTy VisitExpr(Expr *S);
- ComplexPairTy VisitConstantExpr(ConstantExpr *E) {
- return Visit(E->getSubExpr());
- }
- ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
- ComplexPairTy VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
- return Visit(GE->getResultExpr());
- }
- ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
- ComplexPairTy
- VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) {
- return Visit(PE->getReplacement());
- }
- ComplexPairTy VisitCoawaitExpr(CoawaitExpr *S) {
- return CGF.EmitCoawaitExpr(*S).getComplexVal();
- }
- ComplexPairTy VisitCoyieldExpr(CoyieldExpr *S) {
- return CGF.EmitCoyieldExpr(*S).getComplexVal();
- }
- ComplexPairTy VisitUnaryCoawait(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
-
- ComplexPairTy emitConstant(const CodeGenFunction::ConstantEmission &Constant,
- Expr *E) {
- assert(Constant && "not a constant");
- if (Constant.isReference())
- return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E),
- E->getExprLoc());
-
- llvm::Constant *pair = Constant.getValue();
- return ComplexPairTy(pair->getAggregateElement(0U),
- pair->getAggregateElement(1U));
- }
-
- // l-values.
- ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) {
- if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E))
- return emitConstant(Constant, E);
- return EmitLoadOfLValue(E);
- }
- ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
- return EmitLoadOfLValue(E);
- }
- ComplexPairTy VisitObjCMessageExpr(ObjCMessageExpr *E) {
- return CGF.EmitObjCMessageExpr(E).getComplexVal();
- }
- ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitMemberExpr(MemberExpr *ME) {
- if (CodeGenFunction::ConstantEmission Constant =
- CGF.tryEmitAsConstant(ME)) {
- CGF.EmitIgnoredExpr(ME->getBase());
- return emitConstant(Constant, ME);
- }
- return EmitLoadOfLValue(ME);
- }
- ComplexPairTy VisitOpaqueValueExpr(OpaqueValueExpr *E) {
- if (E->isGLValue())
- return EmitLoadOfLValue(CGF.getOrCreateOpaqueLValueMapping(E),
- E->getExprLoc());
- return CGF.getOrCreateOpaqueRValueMapping(E).getComplexVal();
- }
-
- ComplexPairTy VisitPseudoObjectExpr(PseudoObjectExpr *E) {
- return CGF.EmitPseudoObjectRValue(E).getComplexVal();
- }
-
- // FIXME: CompoundLiteralExpr
-
- ComplexPairTy EmitCast(CastKind CK, Expr *Op, QualType DestTy);
- ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) {
- // Unlike for scalars, we don't have to worry about function->ptr demotion
- // here.
- return EmitCast(E->getCastKind(), E->getSubExpr(), E->getType());
- }
- ComplexPairTy VisitCastExpr(CastExpr *E) {
- if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
- CGF.CGM.EmitExplicitCastExprType(ECE, &CGF);
- return EmitCast(E->getCastKind(), E->getSubExpr(), E->getType());
- }
- ComplexPairTy VisitCallExpr(const CallExpr *E);
- ComplexPairTy VisitStmtExpr(const StmtExpr *E);
-
- // Operators.
- ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E,
- bool isInc, bool isPre) {
- LValue LV = CGF.EmitLValue(E->getSubExpr());
- return CGF.EmitComplexPrePostIncDec(E, LV, isInc, isPre);
- }
- ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) {
- return VisitPrePostIncDec(E, false, false);
- }
- ComplexPairTy VisitUnaryPostInc(const UnaryOperator *E) {
- return VisitPrePostIncDec(E, true, false);
- }
- ComplexPairTy VisitUnaryPreDec(const UnaryOperator *E) {
- return VisitPrePostIncDec(E, false, true);
- }
- ComplexPairTy VisitUnaryPreInc(const UnaryOperator *E) {
- return VisitPrePostIncDec(E, true, true);
- }
- ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- return Visit(E->getSubExpr());
- }
- ComplexPairTy VisitUnaryMinus (const UnaryOperator *E);
- ComplexPairTy VisitUnaryNot (const UnaryOperator *E);
- // LNot,Real,Imag never return complex.
- ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
- ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
- return Visit(DAE->getExpr());
- }
- ComplexPairTy VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
- CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
- return Visit(DIE->getExpr());
- }
- ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) {
- CGF.enterFullExpression(E);
- CodeGenFunction::RunCleanupsScope Scope(CGF);
- ComplexPairTy Vals = Visit(E->getSubExpr());
- // Defend against dominance problems caused by jumps out of expression
- // evaluation through the shared cleanup block.
- Scope.ForceCleanup({&Vals.first, &Vals.second});
- return Vals;
- }
- ComplexPairTy VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
- assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
- llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
- return ComplexPairTy(Null, Null);
- }
- ComplexPairTy VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
- assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
- llvm::Constant *Null =
- llvm::Constant::getNullValue(CGF.ConvertType(Elem));
- return ComplexPairTy(Null, Null);
- }
-
- struct BinOpInfo {
- ComplexPairTy LHS;
- ComplexPairTy RHS;
- QualType Ty; // Computation Type.
- };
-
- BinOpInfo EmitBinOps(const BinaryOperator *E);
- LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
- ComplexPairTy (ComplexExprEmitter::*Func)
- (const BinOpInfo &),
- RValue &Val);
- ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
- ComplexPairTy (ComplexExprEmitter::*Func)
- (const BinOpInfo &));
-
- ComplexPairTy EmitBinAdd(const BinOpInfo &Op);
- ComplexPairTy EmitBinSub(const BinOpInfo &Op);
- ComplexPairTy EmitBinMul(const BinOpInfo &Op);
- ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
-
- ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
- const BinOpInfo &Op);
-
- ComplexPairTy VisitBinAdd(const BinaryOperator *E) {
- return EmitBinAdd(EmitBinOps(E));
- }
- ComplexPairTy VisitBinSub(const BinaryOperator *E) {
- return EmitBinSub(EmitBinOps(E));
- }
- ComplexPairTy VisitBinMul(const BinaryOperator *E) {
- return EmitBinMul(EmitBinOps(E));
- }
- ComplexPairTy VisitBinDiv(const BinaryOperator *E) {
- return EmitBinDiv(EmitBinOps(E));
- }
-
- // Compound assignments.
- ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
- return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
- }
- ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) {
- return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub);
- }
- ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) {
- return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul);
- }
- ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) {
- return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv);
- }
-
- // GCC rejects rem/and/or/xor for integer complex.
- // Logical and/or always return int, never complex.
-
- // No comparisons produce a complex result.
-
- LValue EmitBinAssignLValue(const BinaryOperator *E,
- ComplexPairTy &Val);
- ComplexPairTy VisitBinAssign (const BinaryOperator *E);
- ComplexPairTy VisitBinComma (const BinaryOperator *E);
-
-
- ComplexPairTy
- VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
- ComplexPairTy VisitChooseExpr(ChooseExpr *CE);
-
- ComplexPairTy VisitInitListExpr(InitListExpr *E);
-
- ComplexPairTy VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- return EmitLoadOfLValue(E);
- }
-
- ComplexPairTy VisitVAArgExpr(VAArgExpr *E);
-
- ComplexPairTy VisitAtomicExpr(AtomicExpr *E) {
- return CGF.EmitAtomicExpr(E).getComplexVal();
- }
-};
-} // end anonymous namespace.
-
-//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-Address CodeGenFunction::emitAddrOfRealComponent(Address addr,
- QualType complexType) {
- CharUnits offset = CharUnits::Zero();
- return Builder.CreateStructGEP(addr, 0, offset, addr.getName() + ".realp");
-}
-
-Address CodeGenFunction::emitAddrOfImagComponent(Address addr,
- QualType complexType) {
- QualType eltType = complexType->castAs<ComplexType>()->getElementType();
- CharUnits offset = getContext().getTypeSizeInChars(eltType);
- return Builder.CreateStructGEP(addr, 1, offset, addr.getName() + ".imagp");
-}
-
-/// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to
-/// load the real and imaginary pieces, returning them as Real/Imag.
-ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue,
- SourceLocation loc) {
- assert(lvalue.isSimple() && "non-simple complex l-value?");
- if (lvalue.getType()->isAtomicType())
- return CGF.EmitAtomicLoad(lvalue, loc).getComplexVal();
-
- Address SrcPtr = lvalue.getAddress();
- bool isVolatile = lvalue.isVolatileQualified();
-
- llvm::Value *Real = nullptr, *Imag = nullptr;
-
- if (!IgnoreReal || isVolatile) {
- Address RealP = CGF.emitAddrOfRealComponent(SrcPtr, lvalue.getType());
- Real = Builder.CreateLoad(RealP, isVolatile, SrcPtr.getName() + ".real");
- }
-
- if (!IgnoreImag || isVolatile) {
- Address ImagP = CGF.emitAddrOfImagComponent(SrcPtr, lvalue.getType());
- Imag = Builder.CreateLoad(ImagP, isVolatile, SrcPtr.getName() + ".imag");
- }
-
- return ComplexPairTy(Real, Imag);
-}
-
-/// EmitStoreOfComplex - Store the specified real/imag parts into the
-/// specified value pointer.
-void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue,
- bool isInit) {
- if (lvalue.getType()->isAtomicType() ||
- (!isInit && CGF.LValueIsSuitableForInlineAtomic(lvalue)))
- return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
-
- Address Ptr = lvalue.getAddress();
- Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType());
- Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType());
-
- Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
- Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
-}
-
-
-
-//===----------------------------------------------------------------------===//
-// Visitor Methods
-//===----------------------------------------------------------------------===//
-
-ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
- CGF.ErrorUnsupported(E, "complex expression");
- llvm::Type *EltTy =
- CGF.ConvertType(getComplexType(E->getType())->getElementType());
- llvm::Value *U = llvm::UndefValue::get(EltTy);
- return ComplexPairTy(U, U);
-}
-
-ComplexPairTy ComplexExprEmitter::
-VisitImaginaryLiteral(const ImaginaryLiteral *IL) {
- llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr());
- return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag);
-}
-
-
-ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) {
- if (E->getCallReturnType(CGF.getContext())->isReferenceType())
- return EmitLoadOfLValue(E);
-
- return CGF.EmitCallExpr(E).getComplexVal();
-}
-
-ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) {
- CodeGenFunction::StmtExprEvaluation eval(CGF);
- Address RetAlloca = CGF.EmitCompoundStmt(*E->getSubStmt(), true);
- assert(RetAlloca.isValid() && "Expected complex return value");
- return EmitLoadOfLValue(CGF.MakeAddrLValue(RetAlloca, E->getType()),
- E->getExprLoc());
-}
-
-/// Emit a cast from complex value Val to DestType.
-ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
- QualType SrcType,
- QualType DestType,
- SourceLocation Loc) {
- // Get the src/dest element type.
- SrcType = SrcType->castAs<ComplexType>()->getElementType();
- DestType = DestType->castAs<ComplexType>()->getElementType();
-
- // C99 6.3.1.6: When a value of complex type is converted to another
- // complex type, both the real and imaginary parts follow the conversion
- // rules for the corresponding real types.
- Val.first = CGF.EmitScalarConversion(Val.first, SrcType, DestType, Loc);
- Val.second = CGF.EmitScalarConversion(Val.second, SrcType, DestType, Loc);
- return Val;
-}
-
-ComplexPairTy ComplexExprEmitter::EmitScalarToComplexCast(llvm::Value *Val,
- QualType SrcType,
- QualType DestType,
- SourceLocation Loc) {
- // Convert the input element to the element type of the complex.
- DestType = DestType->castAs<ComplexType>()->getElementType();
- Val = CGF.EmitScalarConversion(Val, SrcType, DestType, Loc);
-
- // Return (realval, 0).
- return ComplexPairTy(Val, llvm::Constant::getNullValue(Val->getType()));
-}
-
-ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
- QualType DestTy) {
- switch (CK) {
- case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
-
- // Atomic to non-atomic casts may be more than a no-op for some platforms and
- // for some types.
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
- case CK_NoOp:
- case CK_LValueToRValue:
- case CK_UserDefinedConversion:
- return Visit(Op);
-
- case CK_LValueBitCast: {
- LValue origLV = CGF.EmitLValue(Op);
- Address V = origLV.getAddress();
- V = Builder.CreateElementBitCast(V, CGF.ConvertType(DestTy));
- return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy), Op->getExprLoc());
- }
-
- case CK_BitCast:
- case CK_BaseToDerived:
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase:
- case CK_Dynamic:
- case CK_ToUnion:
- case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
- case CK_NullToPointer:
- case CK_NullToMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_MemberPointerToBoolean:
- case CK_ReinterpretMemberPointer:
- case CK_ConstructorConversion:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
- case CK_ToVoid:
- case CK_VectorSplat:
- case CK_IntegralCast:
- case CK_BooleanToSignedIntegral:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCObjectLValueCast:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_ARCProduceObject:
- case CK_ARCConsumeObject:
- case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject:
- case CK_CopyAndAutoreleaseBlockObject:
- case CK_BuiltinFnToFnPtr:
- case CK_ZeroToOCLOpaqueType:
- case CK_AddressSpaceConversion:
- case CK_IntToOCLSampler:
- case CK_FixedPointCast:
- case CK_FixedPointToBoolean:
- llvm_unreachable("invalid cast kind for complex value");
-
- case CK_FloatingRealToComplex:
- case CK_IntegralRealToComplex:
- return EmitScalarToComplexCast(CGF.EmitScalarExpr(Op), Op->getType(),
- DestTy, Op->getExprLoc());
-
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy,
- Op->getExprLoc());
- }
-
- llvm_unreachable("unknown cast resulting in complex value");
-}
-
-ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- ComplexPairTy Op = Visit(E->getSubExpr());
-
- llvm::Value *ResR, *ResI;
- if (Op.first->getType()->isFloatingPointTy()) {
- ResR = Builder.CreateFNeg(Op.first, "neg.r");
- ResI = Builder.CreateFNeg(Op.second, "neg.i");
- } else {
- ResR = Builder.CreateNeg(Op.first, "neg.r");
- ResI = Builder.CreateNeg(Op.second, "neg.i");
- }
- return ComplexPairTy(ResR, ResI);
-}
-
-ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- // ~(a+ib) = a + i*-b
- ComplexPairTy Op = Visit(E->getSubExpr());
- llvm::Value *ResI;
- if (Op.second->getType()->isFloatingPointTy())
- ResI = Builder.CreateFNeg(Op.second, "conj.i");
- else
- ResI = Builder.CreateNeg(Op.second, "conj.i");
-
- return ComplexPairTy(Op.first, ResI);
-}
-
-ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
- llvm::Value *ResR, *ResI;
-
- if (Op.LHS.first->getType()->isFloatingPointTy()) {
- ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r");
- if (Op.LHS.second && Op.RHS.second)
- ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i");
- else
- ResI = Op.LHS.second ? Op.LHS.second : Op.RHS.second;
- assert(ResI && "Only one operand may be real!");
- } else {
- ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r");
- assert(Op.LHS.second && Op.RHS.second &&
- "Both operands of integer complex operators must be complex!");
- ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i");
- }
- return ComplexPairTy(ResR, ResI);
-}
-
-ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
- llvm::Value *ResR, *ResI;
- if (Op.LHS.first->getType()->isFloatingPointTy()) {
- ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r");
- if (Op.LHS.second && Op.RHS.second)
- ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i");
- else
- ResI = Op.LHS.second ? Op.LHS.second
- : Builder.CreateFNeg(Op.RHS.second, "sub.i");
- assert(ResI && "Only one operand may be real!");
- } else {
- ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r");
- assert(Op.LHS.second && Op.RHS.second &&
- "Both operands of integer complex operators must be complex!");
- ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i");
- }
- return ComplexPairTy(ResR, ResI);
-}
-
-/// Emit a libcall for a binary operation on complex types.
-ComplexPairTy ComplexExprEmitter::EmitComplexBinOpLibCall(StringRef LibCallName,
- const BinOpInfo &Op) {
- CallArgList Args;
- Args.add(RValue::get(Op.LHS.first),
- Op.Ty->castAs<ComplexType>()->getElementType());
- Args.add(RValue::get(Op.LHS.second),
- Op.Ty->castAs<ComplexType>()->getElementType());
- Args.add(RValue::get(Op.RHS.first),
- Op.Ty->castAs<ComplexType>()->getElementType());
- Args.add(RValue::get(Op.RHS.second),
- Op.Ty->castAs<ComplexType>()->getElementType());
-
- // We *must* use the full CG function call building logic here because the
- // complex type has special ABI handling. We also should not forget about
- // special calling convention which may be used for compiler builtins.
-
- // We create a function qualified type to state that this call does not have
- // any exceptions.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI = EPI.withExceptionSpec(
- FunctionProtoType::ExceptionSpecInfo(EST_BasicNoexcept));
- SmallVector<QualType, 4> ArgsQTys(
- 4, Op.Ty->castAs<ComplexType>()->getElementType());
- QualType FQTy = CGF.getContext().getFunctionType(Op.Ty, ArgsQTys, EPI);
- const CGFunctionInfo &FuncInfo = CGF.CGM.getTypes().arrangeFreeFunctionCall(
- Args, cast<FunctionType>(FQTy.getTypePtr()), false);
-
- llvm::FunctionType *FTy = CGF.CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName);
- CGCallee Callee = CGCallee::forDirect(Func, FQTy->getAs<FunctionProtoType>());
-
- llvm::Instruction *Call;
- RValue Res = CGF.EmitCall(FuncInfo, Callee, ReturnValueSlot(), Args, &Call);
- cast<llvm::CallInst>(Call)->setCallingConv(CGF.CGM.getRuntimeCC());
- return Res.getComplexVal();
-}
-
-/// Lookup the libcall name for a given floating point type complex
-/// multiply.
-static StringRef getComplexMultiplyLibCallName(llvm::Type *Ty) {
- switch (Ty->getTypeID()) {
- default:
- llvm_unreachable("Unsupported floating point type!");
- case llvm::Type::HalfTyID:
- return "__mulhc3";
- case llvm::Type::FloatTyID:
- return "__mulsc3";
- case llvm::Type::DoubleTyID:
- return "__muldc3";
- case llvm::Type::PPC_FP128TyID:
- return "__multc3";
- case llvm::Type::X86_FP80TyID:
- return "__mulxc3";
- case llvm::Type::FP128TyID:
- return "__multc3";
- }
-}
-
-// See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
-// typed values.
-ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
- using llvm::Value;
- Value *ResR, *ResI;
- llvm::MDBuilder MDHelper(CGF.getLLVMContext());
-
- if (Op.LHS.first->getType()->isFloatingPointTy()) {
- // The general formulation is:
- // (a + ib) * (c + id) = (a * c - b * d) + i(a * d + b * c)
- //
- // But we can fold away components which would be zero due to a real
- // operand according to C11 Annex G.5.1p2.
- // FIXME: C11 also provides for imaginary types which would allow folding
- // still more of this within the type system.
-
- if (Op.LHS.second && Op.RHS.second) {
- // If both operands are complex, emit the core math directly, and then
- // test for NaNs. If we find NaNs in the result, we delegate to a libcall
- // to carefully re-compute the correct infinity representation if
- // possible. The expectation is that the presence of NaNs here is
- // *extremely* rare, and so the cost of the libcall is almost irrelevant.
- // This is good, because the libcall re-computes the core multiplication
- // exactly the same as we do here and re-tests for NaNs in order to be
- // a generic complex*complex libcall.
-
- // First compute the four products.
- Value *AC = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul_ac");
- Value *BD = Builder.CreateFMul(Op.LHS.second, Op.RHS.second, "mul_bd");
- Value *AD = Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul_ad");
- Value *BC = Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul_bc");
-
- // The real part is the difference of the first two, the imaginary part is
- // the sum of the second.
- ResR = Builder.CreateFSub(AC, BD, "mul_r");
- ResI = Builder.CreateFAdd(AD, BC, "mul_i");
-
- // Emit the test for the real part becoming NaN and create a branch to
- // handle it. We test for NaN by comparing the number to itself.
- Value *IsRNaN = Builder.CreateFCmpUNO(ResR, ResR, "isnan_cmp");
- llvm::BasicBlock *ContBB = CGF.createBasicBlock("complex_mul_cont");
- llvm::BasicBlock *INaNBB = CGF.createBasicBlock("complex_mul_imag_nan");
- llvm::Instruction *Branch = Builder.CreateCondBr(IsRNaN, INaNBB, ContBB);
- llvm::BasicBlock *OrigBB = Branch->getParent();
-
- // Give hint that we very much don't expect to see NaNs.
- // Value chosen to match UR_NONTAKEN_WEIGHT, see BranchProbabilityInfo.cpp
- llvm::MDNode *BrWeight = MDHelper.createBranchWeights(1, (1U << 20) - 1);
- Branch->setMetadata(llvm::LLVMContext::MD_prof, BrWeight);
-
- // Now test the imaginary part and create its branch.
- CGF.EmitBlock(INaNBB);
- Value *IsINaN = Builder.CreateFCmpUNO(ResI, ResI, "isnan_cmp");
- llvm::BasicBlock *LibCallBB = CGF.createBasicBlock("complex_mul_libcall");
- Branch = Builder.CreateCondBr(IsINaN, LibCallBB, ContBB);
- Branch->setMetadata(llvm::LLVMContext::MD_prof, BrWeight);
-
- // Now emit the libcall on this slowest of the slow paths.
- CGF.EmitBlock(LibCallBB);
- Value *LibCallR, *LibCallI;
- std::tie(LibCallR, LibCallI) = EmitComplexBinOpLibCall(
- getComplexMultiplyLibCallName(Op.LHS.first->getType()), Op);
- Builder.CreateBr(ContBB);
-
- // Finally continue execution by phi-ing together the different
- // computation paths.
- CGF.EmitBlock(ContBB);
- llvm::PHINode *RealPHI = Builder.CreatePHI(ResR->getType(), 3, "real_mul_phi");
- RealPHI->addIncoming(ResR, OrigBB);
- RealPHI->addIncoming(ResR, INaNBB);
- RealPHI->addIncoming(LibCallR, LibCallBB);
- llvm::PHINode *ImagPHI = Builder.CreatePHI(ResI->getType(), 3, "imag_mul_phi");
- ImagPHI->addIncoming(ResI, OrigBB);
- ImagPHI->addIncoming(ResI, INaNBB);
- ImagPHI->addIncoming(LibCallI, LibCallBB);
- return ComplexPairTy(RealPHI, ImagPHI);
- }
- assert((Op.LHS.second || Op.RHS.second) &&
- "At least one operand must be complex!");
-
- // If either of the operands is a real rather than a complex, the
- // imaginary component is ignored when computing the real component of the
- // result.
- ResR = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl");
-
- ResI = Op.LHS.second
- ? Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul.il")
- : Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul.ir");
- } else {
- assert(Op.LHS.second && Op.RHS.second &&
- "Both operands of integer complex operators must be complex!");
- Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl");
- Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second, "mul.rr");
- ResR = Builder.CreateSub(ResRl, ResRr, "mul.r");
-
- Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il");
- Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir");
- ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i");
- }
- return ComplexPairTy(ResR, ResI);
-}
-
-// See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
-// typed values.
-ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
- llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
- llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
-
- llvm::Value *DSTr, *DSTi;
- if (LHSr->getType()->isFloatingPointTy()) {
- // If we have a complex operand on the RHS and FastMath is not allowed, we
- // delegate to a libcall to handle all of the complexities and minimize
- // underflow/overflow cases. When FastMath is allowed we construct the
- // divide inline using the same algorithm as for integer operands.
- //
- // FIXME: We would be able to avoid the libcall in many places if we
- // supported imaginary types in addition to complex types.
- if (RHSi && !CGF.getLangOpts().FastMath) {
- BinOpInfo LibCallOp = Op;
- // If LHS was a real, supply a null imaginary part.
- if (!LHSi)
- LibCallOp.LHS.second = llvm::Constant::getNullValue(LHSr->getType());
-
- switch (LHSr->getType()->getTypeID()) {
- default:
- llvm_unreachable("Unsupported floating point type!");
- case llvm::Type::HalfTyID:
- return EmitComplexBinOpLibCall("__divhc3", LibCallOp);
- case llvm::Type::FloatTyID:
- return EmitComplexBinOpLibCall("__divsc3", LibCallOp);
- case llvm::Type::DoubleTyID:
- return EmitComplexBinOpLibCall("__divdc3", LibCallOp);
- case llvm::Type::PPC_FP128TyID:
- return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
- case llvm::Type::X86_FP80TyID:
- return EmitComplexBinOpLibCall("__divxc3", LibCallOp);
- case llvm::Type::FP128TyID:
- return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
- }
- } else if (RHSi) {
- if (!LHSi)
- LHSi = llvm::Constant::getNullValue(RHSi->getType());
-
- // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
- llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
- llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
- llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
-
- llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
- llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
- llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
-
- llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
- llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
- llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
-
- DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
- DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
- } else {
- assert(LHSi && "Can have at most one non-complex operand!");
-
- DSTr = Builder.CreateFDiv(LHSr, RHSr);
- DSTi = Builder.CreateFDiv(LHSi, RHSr);
- }
- } else {
- assert(Op.LHS.second && Op.RHS.second &&
- "Both operands of integer complex operators must be complex!");
- // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
- llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr); // a*c
- llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi); // b*d
- llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2); // ac+bd
-
- llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr); // c*c
- llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi); // d*d
- llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5); // cc+dd
-
- llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr); // b*c
- llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi); // a*d
- llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8); // bc-ad
-
- if (Op.Ty->castAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
- DSTr = Builder.CreateUDiv(Tmp3, Tmp6);
- DSTi = Builder.CreateUDiv(Tmp9, Tmp6);
- } else {
- DSTr = Builder.CreateSDiv(Tmp3, Tmp6);
- DSTi = Builder.CreateSDiv(Tmp9, Tmp6);
- }
- }
-
- return ComplexPairTy(DSTr, DSTi);
-}
-
-ComplexExprEmitter::BinOpInfo
-ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- BinOpInfo Ops;
- if (E->getLHS()->getType()->isRealFloatingType())
- Ops.LHS = ComplexPairTy(CGF.EmitScalarExpr(E->getLHS()), nullptr);
- else
- Ops.LHS = Visit(E->getLHS());
- if (E->getRHS()->getType()->isRealFloatingType())
- Ops.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
- else
- Ops.RHS = Visit(E->getRHS());
-
- Ops.Ty = E->getType();
- return Ops;
-}
-
-
-LValue ComplexExprEmitter::
-EmitCompoundAssignLValue(const CompoundAssignOperator *E,
- ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&),
- RValue &Val) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- QualType LHSTy = E->getLHS()->getType();
- if (const AtomicType *AT = LHSTy->getAs<AtomicType>())
- LHSTy = AT->getValueType();
-
- BinOpInfo OpInfo;
-
- // Load the RHS and LHS operands.
- // __block variables need to have the rhs evaluated first, plus this should
- // improve codegen a little.
- OpInfo.Ty = E->getComputationResultType();
- QualType ComplexElementTy = cast<ComplexType>(OpInfo.Ty)->getElementType();
-
- // The RHS should have been converted to the computation type.
- if (E->getRHS()->getType()->isRealFloatingType()) {
- assert(
- CGF.getContext()
- .hasSameUnqualifiedType(ComplexElementTy, E->getRHS()->getType()));
- OpInfo.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
- } else {
- assert(CGF.getContext()
- .hasSameUnqualifiedType(OpInfo.Ty, E->getRHS()->getType()));
- OpInfo.RHS = Visit(E->getRHS());
- }
-
- LValue LHS = CGF.EmitLValue(E->getLHS());
-
- // Load from the l-value and convert it.
- SourceLocation Loc = E->getExprLoc();
- if (LHSTy->isAnyComplexType()) {
- ComplexPairTy LHSVal = EmitLoadOfLValue(LHS, Loc);
- OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty, Loc);
- } else {
- llvm::Value *LHSVal = CGF.EmitLoadOfScalar(LHS, Loc);
- // For floating point real operands we can directly pass the scalar form
- // to the binary operator emission and potentially get more efficient code.
- if (LHSTy->isRealFloatingType()) {
- if (!CGF.getContext().hasSameUnqualifiedType(ComplexElementTy, LHSTy))
- LHSVal = CGF.EmitScalarConversion(LHSVal, LHSTy, ComplexElementTy, Loc);
- OpInfo.LHS = ComplexPairTy(LHSVal, nullptr);
- } else {
- OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty, Loc);
- }
- }
-
- // Expand the binary operator.
- ComplexPairTy Result = (this->*Func)(OpInfo);
-
- // Truncate the result and store it into the LHS lvalue.
- if (LHSTy->isAnyComplexType()) {
- ComplexPairTy ResVal =
- EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy, Loc);
- EmitStoreOfComplex(ResVal, LHS, /*isInit*/ false);
- Val = RValue::getComplex(ResVal);
- } else {
- llvm::Value *ResVal =
- CGF.EmitComplexToScalarConversion(Result, OpInfo.Ty, LHSTy, Loc);
- CGF.EmitStoreOfScalar(ResVal, LHS, /*isInit*/ false);
- Val = RValue::get(ResVal);
- }
-
- return LHS;
-}
-
-// Compound assignments.
-ComplexPairTy ComplexExprEmitter::
-EmitCompoundAssign(const CompoundAssignOperator *E,
- ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
- RValue Val;
- LValue LV = EmitCompoundAssignLValue(E, Func, Val);
-
- // The result of an assignment in C is the assigned r-value.
- if (!CGF.getLangOpts().CPlusPlus)
- return Val.getComplexVal();
-
- // If the lvalue is non-volatile, return the computed value of the assignment.
- if (!LV.isVolatileQualified())
- return Val.getComplexVal();
-
- return EmitLoadOfLValue(LV, E->getExprLoc());
-}
-
-LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
- ComplexPairTy &Val) {
- assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
- E->getRHS()->getType()) &&
- "Invalid assignment");
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
-
- // Emit the RHS. __block variables need the RHS evaluated first.
- Val = Visit(E->getRHS());
-
- // Compute the address to store into.
- LValue LHS = CGF.EmitLValue(E->getLHS());
-
- // Store the result value into the LHS lvalue.
- EmitStoreOfComplex(Val, LHS, /*isInit*/ false);
-
- return LHS;
-}
-
-ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
- ComplexPairTy Val;
- LValue LV = EmitBinAssignLValue(E, Val);
-
- // The result of an assignment in C is the assigned r-value.
- if (!CGF.getLangOpts().CPlusPlus)
- return Val;
-
- // If the lvalue is non-volatile, return the computed value of the assignment.
- if (!LV.isVolatileQualified())
- return Val;
-
- return EmitLoadOfLValue(LV, E->getExprLoc());
-}
-
-ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
- CGF.EmitIgnoredExpr(E->getLHS());
- return Visit(E->getRHS());
-}
-
-ComplexPairTy ComplexExprEmitter::
-VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
- llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
-
- // Bind the common expression if necessary.
- CodeGenFunction::OpaqueValueMapping binding(CGF, E);
-
-
- CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock,
- CGF.getProfileCount(E));
-
- eval.begin(CGF);
- CGF.EmitBlock(LHSBlock);
- CGF.incrementProfileCounter(E);
- ComplexPairTy LHS = Visit(E->getTrueExpr());
- LHSBlock = Builder.GetInsertBlock();
- CGF.EmitBranch(ContBlock);
- eval.end(CGF);
-
- eval.begin(CGF);
- CGF.EmitBlock(RHSBlock);
- ComplexPairTy RHS = Visit(E->getFalseExpr());
- RHSBlock = Builder.GetInsertBlock();
- CGF.EmitBlock(ContBlock);
- eval.end(CGF);
-
- // Create a PHI node for the real part.
- llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), 2, "cond.r");
- RealPN->addIncoming(LHS.first, LHSBlock);
- RealPN->addIncoming(RHS.first, RHSBlock);
-
- // Create a PHI node for the imaginary part.
- llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), 2, "cond.i");
- ImagPN->addIncoming(LHS.second, LHSBlock);
- ImagPN->addIncoming(RHS.second, RHSBlock);
-
- return ComplexPairTy(RealPN, ImagPN);
-}
-
-ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) {
- return Visit(E->getChosenSubExpr());
-}
-
-ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
- bool Ignore = TestAndClearIgnoreReal();
- (void)Ignore;
- assert (Ignore == false && "init list ignored");
- Ignore = TestAndClearIgnoreImag();
- (void)Ignore;
- assert (Ignore == false && "init list ignored");
-
- if (E->getNumInits() == 2) {
- llvm::Value *Real = CGF.EmitScalarExpr(E->getInit(0));
- llvm::Value *Imag = CGF.EmitScalarExpr(E->getInit(1));
- return ComplexPairTy(Real, Imag);
- } else if (E->getNumInits() == 1) {
- return Visit(E->getInit(0));
- }
-
- // Empty init list initializes to null
- assert(E->getNumInits() == 0 && "Unexpected number of inits");
- QualType Ty = E->getType()->castAs<ComplexType>()->getElementType();
- llvm::Type* LTy = CGF.ConvertType(Ty);
- llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);
- return ComplexPairTy(zeroConstant, zeroConstant);
-}
-
-ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
- Address ArgValue = Address::invalid();
- Address ArgPtr = CGF.EmitVAArg(E, ArgValue);
-
- if (!ArgPtr.isValid()) {
- CGF.ErrorUnsupported(E, "complex va_arg expression");
- llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->castAs<ComplexType>()->getElementType());
- llvm::Value *U = llvm::UndefValue::get(EltTy);
- return ComplexPairTy(U, U);
- }
-
- return EmitLoadOfLValue(CGF.MakeAddrLValue(ArgPtr, E->getType()),
- E->getExprLoc());
-}
-
-//===----------------------------------------------------------------------===//
-// Entry Point into this File
-//===----------------------------------------------------------------------===//
-
-/// EmitComplexExpr - Emit the computation of the specified expression of
-/// complex type, ignoring the result.
-ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
- bool IgnoreImag) {
- assert(E && getComplexType(E->getType()) &&
- "Invalid complex expression to emit");
-
- return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag)
- .Visit(const_cast<Expr *>(E));
-}
-
-void CodeGenFunction::EmitComplexExprIntoLValue(const Expr *E, LValue dest,
- bool isInit) {
- assert(E && getComplexType(E->getType()) &&
- "Invalid complex expression to emit");
- ComplexExprEmitter Emitter(*this);
- ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
- Emitter.EmitStoreOfComplex(Val, dest, isInit);
-}
-
-/// EmitStoreOfComplex - Store a complex number into the specified l-value.
-void CodeGenFunction::EmitStoreOfComplex(ComplexPairTy V, LValue dest,
- bool isInit) {
- ComplexExprEmitter(*this).EmitStoreOfComplex(V, dest, isInit);
-}
-
-/// EmitLoadOfComplex - Load a complex number from the specified address.
-ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src,
- SourceLocation loc) {
- return ComplexExprEmitter(*this).EmitLoadOfLValue(src, loc);
-}
-
-LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
- assert(E->getOpcode() == BO_Assign);
- ComplexPairTy Val; // ignored
- return ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val);
-}
-
-typedef ComplexPairTy (ComplexExprEmitter::*CompoundFunc)(
- const ComplexExprEmitter::BinOpInfo &);
-
-static CompoundFunc getComplexOp(BinaryOperatorKind Op) {
- switch (Op) {
- case BO_MulAssign: return &ComplexExprEmitter::EmitBinMul;
- case BO_DivAssign: return &ComplexExprEmitter::EmitBinDiv;
- case BO_SubAssign: return &ComplexExprEmitter::EmitBinSub;
- case BO_AddAssign: return &ComplexExprEmitter::EmitBinAdd;
- default:
- llvm_unreachable("unexpected complex compound assignment");
- }
-}
-
-LValue CodeGenFunction::
-EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
- CompoundFunc Op = getComplexOp(E->getOpcode());
- RValue Val;
- return ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
-}
-
-LValue CodeGenFunction::
-EmitScalarCompoundAssignWithComplex(const CompoundAssignOperator *E,
- llvm::Value *&Result) {
- CompoundFunc Op = getComplexOp(E->getOpcode());
- RValue Val;
- LValue Ret = ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
- Result = Val.getScalarVal();
- return Ret;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp
deleted file mode 100644
index c9475840aee..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp
+++ /dev/null
@@ -1,2176 +0,0 @@
-//===--- CGExprConstant.cpp - Emit LLVM Code from Constant Expressions ----===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Constant Expr nodes as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
-#include "CGRecordLayout.h"
-#include "CodeGenModule.h"
-#include "ConstantEmitter.h"
-#include "TargetInfo.h"
-#include "clang/AST/APValue.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/Builtins.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalVariable.h"
-using namespace clang;
-using namespace CodeGen;
-
-//===----------------------------------------------------------------------===//
-// ConstStructBuilder
-//===----------------------------------------------------------------------===//
-
-namespace {
-class ConstExprEmitter;
-class ConstStructBuilder {
- CodeGenModule &CGM;
- ConstantEmitter &Emitter;
-
- bool Packed;
- CharUnits NextFieldOffsetInChars;
- CharUnits LLVMStructAlignment;
- SmallVector<llvm::Constant *, 32> Elements;
-public:
- static llvm::Constant *BuildStruct(ConstantEmitter &Emitter,
- ConstExprEmitter *ExprEmitter,
- llvm::Constant *Base,
- InitListExpr *Updater,
- QualType ValTy);
- static llvm::Constant *BuildStruct(ConstantEmitter &Emitter,
- InitListExpr *ILE, QualType StructTy);
- static llvm::Constant *BuildStruct(ConstantEmitter &Emitter,
- const APValue &Value, QualType ValTy);
-
-private:
- ConstStructBuilder(ConstantEmitter &emitter)
- : CGM(emitter.CGM), Emitter(emitter), Packed(false),
- NextFieldOffsetInChars(CharUnits::Zero()),
- LLVMStructAlignment(CharUnits::One()) { }
-
- void AppendField(const FieldDecl *Field, uint64_t FieldOffset,
- llvm::Constant *InitExpr);
-
- void AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst);
-
- void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
- llvm::ConstantInt *InitExpr);
-
- void AppendPadding(CharUnits PadSize);
-
- void AppendTailPadding(CharUnits RecordSize);
-
- void ConvertStructToPacked();
-
- bool Build(InitListExpr *ILE);
- bool Build(ConstExprEmitter *Emitter, llvm::Constant *Base,
- InitListExpr *Updater);
- bool Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
- const CXXRecordDecl *VTableClass, CharUnits BaseOffset);
- llvm::Constant *Finalize(QualType Ty);
-
- CharUnits getAlignment(const llvm::Constant *C) const {
- if (Packed) return CharUnits::One();
- return CharUnits::fromQuantity(
- CGM.getDataLayout().getABITypeAlignment(C->getType()));
- }
-
- CharUnits getSizeInChars(const llvm::Constant *C) const {
- return CharUnits::fromQuantity(
- CGM.getDataLayout().getTypeAllocSize(C->getType()));
- }
-};
-
-void ConstStructBuilder::
-AppendField(const FieldDecl *Field, uint64_t FieldOffset,
- llvm::Constant *InitCst) {
- const ASTContext &Context = CGM.getContext();
-
- CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset);
-
- AppendBytes(FieldOffsetInChars, InitCst);
-}
-
-void ConstStructBuilder::
-AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst) {
-
- assert(NextFieldOffsetInChars <= FieldOffsetInChars
- && "Field offset mismatch!");
-
- CharUnits FieldAlignment = getAlignment(InitCst);
-
- // Round up the field offset to the alignment of the field type.
- CharUnits AlignedNextFieldOffsetInChars =
- NextFieldOffsetInChars.alignTo(FieldAlignment);
-
- if (AlignedNextFieldOffsetInChars < FieldOffsetInChars) {
- // We need to append padding.
- AppendPadding(FieldOffsetInChars - NextFieldOffsetInChars);
-
- assert(NextFieldOffsetInChars == FieldOffsetInChars &&
- "Did not add enough padding!");
-
- AlignedNextFieldOffsetInChars =
- NextFieldOffsetInChars.alignTo(FieldAlignment);
- }
-
- if (AlignedNextFieldOffsetInChars > FieldOffsetInChars) {
- assert(!Packed && "Alignment is wrong even with a packed struct!");
-
- // Convert the struct to a packed struct.
- ConvertStructToPacked();
-
- // After we pack the struct, we may need to insert padding.
- if (NextFieldOffsetInChars < FieldOffsetInChars) {
- // We need to append padding.
- AppendPadding(FieldOffsetInChars - NextFieldOffsetInChars);
-
- assert(NextFieldOffsetInChars == FieldOffsetInChars &&
- "Did not add enough padding!");
- }
- AlignedNextFieldOffsetInChars = NextFieldOffsetInChars;
- }
-
- // Add the field.
- Elements.push_back(InitCst);
- NextFieldOffsetInChars = AlignedNextFieldOffsetInChars +
- getSizeInChars(InitCst);
-
- if (Packed)
- assert(LLVMStructAlignment == CharUnits::One() &&
- "Packed struct not byte-aligned!");
- else
- LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
-}
-
-void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
- uint64_t FieldOffset,
- llvm::ConstantInt *CI) {
- const ASTContext &Context = CGM.getContext();
- const uint64_t CharWidth = Context.getCharWidth();
- uint64_t NextFieldOffsetInBits = Context.toBits(NextFieldOffsetInChars);
- if (FieldOffset > NextFieldOffsetInBits) {
- // We need to add padding.
- CharUnits PadSize = Context.toCharUnitsFromBits(
- llvm::alignTo(FieldOffset - NextFieldOffsetInBits,
- Context.getTargetInfo().getCharAlign()));
-
- AppendPadding(PadSize);
- }
-
- uint64_t FieldSize = Field->getBitWidthValue(Context);
-
- llvm::APInt FieldValue = CI->getValue();
-
- // Promote the size of FieldValue if necessary
- // FIXME: This should never occur, but currently it can because initializer
- // constants are cast to bool, and because clang is not enforcing bitfield
- // width limits.
- if (FieldSize > FieldValue.getBitWidth())
- FieldValue = FieldValue.zext(FieldSize);
-
- // Truncate the size of FieldValue to the bit field size.
- if (FieldSize < FieldValue.getBitWidth())
- FieldValue = FieldValue.trunc(FieldSize);
-
- NextFieldOffsetInBits = Context.toBits(NextFieldOffsetInChars);
- if (FieldOffset < NextFieldOffsetInBits) {
- // Either part of the field or the entire field can go into the previous
- // byte.
- assert(!Elements.empty() && "Elements can't be empty!");
-
- unsigned BitsInPreviousByte = NextFieldOffsetInBits - FieldOffset;
-
- bool FitsCompletelyInPreviousByte =
- BitsInPreviousByte >= FieldValue.getBitWidth();
-
- llvm::APInt Tmp = FieldValue;
-
- if (!FitsCompletelyInPreviousByte) {
- unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
-
- if (CGM.getDataLayout().isBigEndian()) {
- Tmp.lshrInPlace(NewFieldWidth);
- Tmp = Tmp.trunc(BitsInPreviousByte);
-
- // We want the remaining high bits.
- FieldValue = FieldValue.trunc(NewFieldWidth);
- } else {
- Tmp = Tmp.trunc(BitsInPreviousByte);
-
- // We want the remaining low bits.
- FieldValue.lshrInPlace(BitsInPreviousByte);
- FieldValue = FieldValue.trunc(NewFieldWidth);
- }
- }
-
- Tmp = Tmp.zext(CharWidth);
- if (CGM.getDataLayout().isBigEndian()) {
- if (FitsCompletelyInPreviousByte)
- Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
- } else {
- Tmp = Tmp.shl(CharWidth - BitsInPreviousByte);
- }
-
- // 'or' in the bits that go into the previous byte.
- llvm::Value *LastElt = Elements.back();
- if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(LastElt))
- Tmp |= Val->getValue();
- else {
- assert(isa<llvm::UndefValue>(LastElt));
- // If there is an undef field that we're adding to, it can either be a
- // scalar undef (in which case, we just replace it with our field) or it
- // is an array. If it is an array, we have to pull one byte off the
- // array so that the other undef bytes stay around.
- if (!isa<llvm::IntegerType>(LastElt->getType())) {
- // The undef padding will be a multibyte array, create a new smaller
- // padding and then an hole for our i8 to get plopped into.
- assert(isa<llvm::ArrayType>(LastElt->getType()) &&
- "Expected array padding of undefs");
- llvm::ArrayType *AT = cast<llvm::ArrayType>(LastElt->getType());
- assert(AT->getElementType()->isIntegerTy(CharWidth) &&
- AT->getNumElements() != 0 &&
- "Expected non-empty array padding of undefs");
-
- // Remove the padding array.
- NextFieldOffsetInChars -= CharUnits::fromQuantity(AT->getNumElements());
- Elements.pop_back();
-
- // Add the padding back in two chunks.
- AppendPadding(CharUnits::fromQuantity(AT->getNumElements()-1));
- AppendPadding(CharUnits::One());
- assert(isa<llvm::UndefValue>(Elements.back()) &&
- Elements.back()->getType()->isIntegerTy(CharWidth) &&
- "Padding addition didn't work right");
- }
- }
-
- Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
-
- if (FitsCompletelyInPreviousByte)
- return;
- }
-
- while (FieldValue.getBitWidth() > CharWidth) {
- llvm::APInt Tmp;
-
- if (CGM.getDataLayout().isBigEndian()) {
- // We want the high bits.
- Tmp =
- FieldValue.lshr(FieldValue.getBitWidth() - CharWidth).trunc(CharWidth);
- } else {
- // We want the low bits.
- Tmp = FieldValue.trunc(CharWidth);
-
- FieldValue.lshrInPlace(CharWidth);
- }
-
- Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
- ++NextFieldOffsetInChars;
-
- FieldValue = FieldValue.trunc(FieldValue.getBitWidth() - CharWidth);
- }
-
- assert(FieldValue.getBitWidth() > 0 &&
- "Should have at least one bit left!");
- assert(FieldValue.getBitWidth() <= CharWidth &&
- "Should not have more than a byte left!");
-
- if (FieldValue.getBitWidth() < CharWidth) {
- if (CGM.getDataLayout().isBigEndian()) {
- unsigned BitWidth = FieldValue.getBitWidth();
-
- FieldValue = FieldValue.zext(CharWidth) << (CharWidth - BitWidth);
- } else
- FieldValue = FieldValue.zext(CharWidth);
- }
-
- // Append the last element.
- Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(),
- FieldValue));
- ++NextFieldOffsetInChars;
-}
-
-void ConstStructBuilder::AppendPadding(CharUnits PadSize) {
- if (PadSize.isZero())
- return;
-
- llvm::Type *Ty = CGM.Int8Ty;
- if (PadSize > CharUnits::One())
- Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity());
-
- llvm::Constant *C = llvm::UndefValue::get(Ty);
- Elements.push_back(C);
- assert(getAlignment(C) == CharUnits::One() &&
- "Padding must have 1 byte alignment!");
-
- NextFieldOffsetInChars += getSizeInChars(C);
-}
-
-void ConstStructBuilder::AppendTailPadding(CharUnits RecordSize) {
- assert(NextFieldOffsetInChars <= RecordSize &&
- "Size mismatch!");
-
- AppendPadding(RecordSize - NextFieldOffsetInChars);
-}
-
-void ConstStructBuilder::ConvertStructToPacked() {
- SmallVector<llvm::Constant *, 16> PackedElements;
- CharUnits ElementOffsetInChars = CharUnits::Zero();
-
- for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
- llvm::Constant *C = Elements[i];
-
- CharUnits ElementAlign = CharUnits::fromQuantity(
- CGM.getDataLayout().getABITypeAlignment(C->getType()));
- CharUnits AlignedElementOffsetInChars =
- ElementOffsetInChars.alignTo(ElementAlign);
-
- if (AlignedElementOffsetInChars > ElementOffsetInChars) {
- // We need some padding.
- CharUnits NumChars =
- AlignedElementOffsetInChars - ElementOffsetInChars;
-
- llvm::Type *Ty = CGM.Int8Ty;
- if (NumChars > CharUnits::One())
- Ty = llvm::ArrayType::get(Ty, NumChars.getQuantity());
-
- llvm::Constant *Padding = llvm::UndefValue::get(Ty);
- PackedElements.push_back(Padding);
- ElementOffsetInChars += getSizeInChars(Padding);
- }
-
- PackedElements.push_back(C);
- ElementOffsetInChars += getSizeInChars(C);
- }
-
- assert(ElementOffsetInChars == NextFieldOffsetInChars &&
- "Packing the struct changed its size!");
-
- Elements.swap(PackedElements);
- LLVMStructAlignment = CharUnits::One();
- Packed = true;
-}
-
-bool ConstStructBuilder::Build(InitListExpr *ILE) {
- RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
- unsigned FieldNo = 0;
- unsigned ElementNo = 0;
-
- // Bail out if we have base classes. We could support these, but they only
- // arise in C++1z where we will have already constant folded most interesting
- // cases. FIXME: There are still a few more cases we can handle this way.
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- if (CXXRD->getNumBases())
- return false;
-
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
- // If this is a union, skip all the fields that aren't being initialized.
- if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
- continue;
-
- // Don't emit anonymous bitfields, they just affect layout.
- if (Field->isUnnamedBitfield())
- continue;
-
- // Get the initializer. A struct can include fields without initializers,
- // we just use explicit null values for them.
- llvm::Constant *EltInit;
- if (ElementNo < ILE->getNumInits())
- EltInit = Emitter.tryEmitPrivateForMemory(ILE->getInit(ElementNo++),
- Field->getType());
- else
- EltInit = Emitter.emitNullForMemory(Field->getType());
-
- if (!EltInit)
- return false;
-
- if (!Field->isBitField()) {
- // Handle non-bitfield members.
- AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit);
- } else {
- // Otherwise we have a bitfield.
- if (auto *CI = dyn_cast<llvm::ConstantInt>(EltInit)) {
- AppendBitField(*Field, Layout.getFieldOffset(FieldNo), CI);
- } else {
- // We are trying to initialize a bitfield with a non-trivial constant,
- // this must require run-time code.
- return false;
- }
- }
- }
-
- return true;
-}
-
-namespace {
-struct BaseInfo {
- BaseInfo(const CXXRecordDecl *Decl, CharUnits Offset, unsigned Index)
- : Decl(Decl), Offset(Offset), Index(Index) {
- }
-
- const CXXRecordDecl *Decl;
- CharUnits Offset;
- unsigned Index;
-
- bool operator<(const BaseInfo &O) const { return Offset < O.Offset; }
-};
-}
-
-bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
- bool IsPrimaryBase,
- const CXXRecordDecl *VTableClass,
- CharUnits Offset) {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
- if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
- // Add a vtable pointer, if we need one and it hasn't already been added.
- if (CD->isDynamicClass() && !IsPrimaryBase) {
- llvm::Constant *VTableAddressPoint =
- CGM.getCXXABI().getVTableAddressPointForConstExpr(
- BaseSubobject(CD, Offset), VTableClass);
- AppendBytes(Offset, VTableAddressPoint);
- }
-
- // Accumulate and sort bases, in order to visit them in address order, which
- // may not be the same as declaration order.
- SmallVector<BaseInfo, 8> Bases;
- Bases.reserve(CD->getNumBases());
- unsigned BaseNo = 0;
- for (CXXRecordDecl::base_class_const_iterator Base = CD->bases_begin(),
- BaseEnd = CD->bases_end(); Base != BaseEnd; ++Base, ++BaseNo) {
- assert(!Base->isVirtual() && "should not have virtual bases here");
- const CXXRecordDecl *BD = Base->getType()->getAsCXXRecordDecl();
- CharUnits BaseOffset = Layout.getBaseClassOffset(BD);
- Bases.push_back(BaseInfo(BD, BaseOffset, BaseNo));
- }
- std::stable_sort(Bases.begin(), Bases.end());
-
- for (unsigned I = 0, N = Bases.size(); I != N; ++I) {
- BaseInfo &Base = Bases[I];
-
- bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl;
- Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase,
- VTableClass, Offset + Base.Offset);
- }
- }
-
- unsigned FieldNo = 0;
- uint64_t OffsetBits = CGM.getContext().toBits(Offset);
-
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
- // If this is a union, skip all the fields that aren't being initialized.
- if (RD->isUnion() && Val.getUnionField() != *Field)
- continue;
-
- // Don't emit anonymous bitfields, they just affect layout.
- if (Field->isUnnamedBitfield())
- continue;
-
- // Emit the value of the initializer.
- const APValue &FieldValue =
- RD->isUnion() ? Val.getUnionValue() : Val.getStructField(FieldNo);
- llvm::Constant *EltInit =
- Emitter.tryEmitPrivateForMemory(FieldValue, Field->getType());
- if (!EltInit)
- return false;
-
- if (!Field->isBitField()) {
- // Handle non-bitfield members.
- AppendField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits, EltInit);
- } else {
- // Otherwise we have a bitfield.
- AppendBitField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits,
- cast<llvm::ConstantInt>(EltInit));
- }
- }
-
- return true;
-}
-
-llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) {
- RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
- CharUnits LayoutSizeInChars = Layout.getSize();
-
- if (NextFieldOffsetInChars > LayoutSizeInChars) {
- // If the struct is bigger than the size of the record type,
- // we must have a flexible array member at the end.
- assert(RD->hasFlexibleArrayMember() &&
- "Must have flexible array member if struct is bigger than type!");
-
- // No tail padding is necessary.
- } else {
- // Append tail padding if necessary.
- CharUnits LLVMSizeInChars =
- NextFieldOffsetInChars.alignTo(LLVMStructAlignment);
-
- if (LLVMSizeInChars != LayoutSizeInChars)
- AppendTailPadding(LayoutSizeInChars);
-
- LLVMSizeInChars = NextFieldOffsetInChars.alignTo(LLVMStructAlignment);
-
- // Check if we need to convert the struct to a packed struct.
- if (NextFieldOffsetInChars <= LayoutSizeInChars &&
- LLVMSizeInChars > LayoutSizeInChars) {
- assert(!Packed && "Size mismatch!");
-
- ConvertStructToPacked();
- assert(NextFieldOffsetInChars <= LayoutSizeInChars &&
- "Converting to packed did not help!");
- }
-
- LLVMSizeInChars = NextFieldOffsetInChars.alignTo(LLVMStructAlignment);
-
- assert(LayoutSizeInChars == LLVMSizeInChars &&
- "Tail padding mismatch!");
- }
-
- // Pick the type to use. If the type is layout identical to the ConvertType
- // type then use it, otherwise use whatever the builder produced for us.
- llvm::StructType *STy =
- llvm::ConstantStruct::getTypeForElements(CGM.getLLVMContext(),
- Elements, Packed);
- llvm::Type *ValTy = CGM.getTypes().ConvertType(Ty);
- if (llvm::StructType *ValSTy = dyn_cast<llvm::StructType>(ValTy)) {
- if (ValSTy->isLayoutIdentical(STy))
- STy = ValSTy;
- }
-
- llvm::Constant *Result = llvm::ConstantStruct::get(STy, Elements);
-
- assert(NextFieldOffsetInChars.alignTo(getAlignment(Result)) ==
- getSizeInChars(Result) &&
- "Size mismatch!");
-
- return Result;
-}
-
-llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter,
- ConstExprEmitter *ExprEmitter,
- llvm::Constant *Base,
- InitListExpr *Updater,
- QualType ValTy) {
- ConstStructBuilder Builder(Emitter);
- if (!Builder.Build(ExprEmitter, Base, Updater))
- return nullptr;
- return Builder.Finalize(ValTy);
-}
-
-llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter,
- InitListExpr *ILE,
- QualType ValTy) {
- ConstStructBuilder Builder(Emitter);
-
- if (!Builder.Build(ILE))
- return nullptr;
-
- return Builder.Finalize(ValTy);
-}
-
-llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter,
- const APValue &Val,
- QualType ValTy) {
- ConstStructBuilder Builder(Emitter);
-
- const RecordDecl *RD = ValTy->castAs<RecordType>()->getDecl();
- const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
- if (!Builder.Build(Val, RD, false, CD, CharUnits::Zero()))
- return nullptr;
-
- return Builder.Finalize(ValTy);
-}
-
-
-//===----------------------------------------------------------------------===//
-// ConstExprEmitter
-//===----------------------------------------------------------------------===//
-
-static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM,
- CodeGenFunction *CGF,
- const CompoundLiteralExpr *E) {
- CharUnits Align = CGM.getContext().getTypeAlignInChars(E->getType());
- if (llvm::GlobalVariable *Addr =
- CGM.getAddrOfConstantCompoundLiteralIfEmitted(E))
- return ConstantAddress(Addr, Align);
-
- LangAS addressSpace = E->getType().getAddressSpace();
-
- ConstantEmitter emitter(CGM, CGF);
- llvm::Constant *C = emitter.tryEmitForInitializer(E->getInitializer(),
- addressSpace, E->getType());
- if (!C) {
- assert(!E->isFileScope() &&
- "file-scope compound literal did not have constant initializer!");
- return ConstantAddress::invalid();
- }
-
- auto GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
- CGM.isTypeConstant(E->getType(), true),
- llvm::GlobalValue::InternalLinkage,
- C, ".compoundliteral", nullptr,
- llvm::GlobalVariable::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(addressSpace));
- emitter.finalize(GV);
- GV->setAlignment(Align.getQuantity());
- CGM.setAddrOfConstantCompoundLiteral(E, GV);
- return ConstantAddress(GV, Align);
-}
-
-static llvm::Constant *
-EmitArrayConstant(CodeGenModule &CGM, const ConstantArrayType *DestType,
- llvm::Type *CommonElementType, unsigned ArrayBound,
- SmallVectorImpl<llvm::Constant *> &Elements,
- llvm::Constant *Filler) {
- // Figure out how long the initial prefix of non-zero elements is.
- unsigned NonzeroLength = ArrayBound;
- if (Elements.size() < NonzeroLength && Filler->isNullValue())
- NonzeroLength = Elements.size();
- if (NonzeroLength == Elements.size()) {
- while (NonzeroLength > 0 && Elements[NonzeroLength - 1]->isNullValue())
- --NonzeroLength;
- }
-
- if (NonzeroLength == 0) {
- return llvm::ConstantAggregateZero::get(
- CGM.getTypes().ConvertType(QualType(DestType, 0)));
- }
-
- // Add a zeroinitializer array filler if we have lots of trailing zeroes.
- unsigned TrailingZeroes = ArrayBound - NonzeroLength;
- if (TrailingZeroes >= 8) {
- assert(Elements.size() >= NonzeroLength &&
- "missing initializer for non-zero element");
-
- // If all the elements had the same type up to the trailing zeroes, emit a
- // struct of two arrays (the nonzero data and the zeroinitializer).
- if (CommonElementType && NonzeroLength >= 8) {
- llvm::Constant *Initial = llvm::ConstantArray::get(
- llvm::ArrayType::get(CommonElementType, NonzeroLength),
- makeArrayRef(Elements).take_front(NonzeroLength));
- Elements.resize(2);
- Elements[0] = Initial;
- } else {
- Elements.resize(NonzeroLength + 1);
- }
-
- auto *FillerType =
- CommonElementType
- ? CommonElementType
- : CGM.getTypes().ConvertType(DestType->getElementType());
- FillerType = llvm::ArrayType::get(FillerType, TrailingZeroes);
- Elements.back() = llvm::ConstantAggregateZero::get(FillerType);
- CommonElementType = nullptr;
- } else if (Elements.size() != ArrayBound) {
- // Otherwise pad to the right size with the filler if necessary.
- Elements.resize(ArrayBound, Filler);
- if (Filler->getType() != CommonElementType)
- CommonElementType = nullptr;
- }
-
- // If all elements have the same type, just emit an array constant.
- if (CommonElementType)
- return llvm::ConstantArray::get(
- llvm::ArrayType::get(CommonElementType, ArrayBound), Elements);
-
- // We have mixed types. Use a packed struct.
- llvm::SmallVector<llvm::Type *, 16> Types;
- Types.reserve(Elements.size());
- for (llvm::Constant *Elt : Elements)
- Types.push_back(Elt->getType());
- llvm::StructType *SType =
- llvm::StructType::get(CGM.getLLVMContext(), Types, true);
- return llvm::ConstantStruct::get(SType, Elements);
-}
-
-/// This class only needs to handle two cases:
-/// 1) Literals (this is used by APValue emission to emit literals).
-/// 2) Arrays, structs and unions (outside C++11 mode, we don't currently
-/// constant fold these types).
-class ConstExprEmitter :
- public StmtVisitor<ConstExprEmitter, llvm::Constant*, QualType> {
- CodeGenModule &CGM;
- ConstantEmitter &Emitter;
- llvm::LLVMContext &VMContext;
-public:
- ConstExprEmitter(ConstantEmitter &emitter)
- : CGM(emitter.CGM), Emitter(emitter), VMContext(CGM.getLLVMContext()) {
- }
-
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- llvm::Constant *VisitStmt(Stmt *S, QualType T) {
- return nullptr;
- }
-
- llvm::Constant *VisitConstantExpr(ConstantExpr *CE, QualType T) {
- return Visit(CE->getSubExpr(), T);
- }
-
- llvm::Constant *VisitParenExpr(ParenExpr *PE, QualType T) {
- return Visit(PE->getSubExpr(), T);
- }
-
- llvm::Constant *
- VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE,
- QualType T) {
- return Visit(PE->getReplacement(), T);
- }
-
- llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE,
- QualType T) {
- return Visit(GE->getResultExpr(), T);
- }
-
- llvm::Constant *VisitChooseExpr(ChooseExpr *CE, QualType T) {
- return Visit(CE->getChosenSubExpr(), T);
- }
-
- llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E, QualType T) {
- return Visit(E->getInitializer(), T);
- }
-
- llvm::Constant *VisitCastExpr(CastExpr *E, QualType destType) {
- if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
- CGM.EmitExplicitCastExprType(ECE, Emitter.CGF);
- Expr *subExpr = E->getSubExpr();
-
- switch (E->getCastKind()) {
- case CK_ToUnion: {
- // GCC cast to union extension
- assert(E->getType()->isUnionType() &&
- "Destination type is not union type!");
-
- auto field = E->getTargetUnionField();
-
- auto C = Emitter.tryEmitPrivateForMemory(subExpr, field->getType());
- if (!C) return nullptr;
-
- auto destTy = ConvertType(destType);
- if (C->getType() == destTy) return C;
-
- // Build a struct with the union sub-element as the first member,
- // and padded to the appropriate size.
- SmallVector<llvm::Constant*, 2> Elts;
- SmallVector<llvm::Type*, 2> Types;
- Elts.push_back(C);
- Types.push_back(C->getType());
- unsigned CurSize = CGM.getDataLayout().getTypeAllocSize(C->getType());
- unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destTy);
-
- assert(CurSize <= TotalSize && "Union size mismatch!");
- if (unsigned NumPadBytes = TotalSize - CurSize) {
- llvm::Type *Ty = CGM.Int8Ty;
- if (NumPadBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumPadBytes);
-
- Elts.push_back(llvm::UndefValue::get(Ty));
- Types.push_back(Ty);
- }
-
- llvm::StructType *STy = llvm::StructType::get(VMContext, Types, false);
- return llvm::ConstantStruct::get(STy, Elts);
- }
-
- case CK_AddressSpaceConversion: {
- auto C = Emitter.tryEmitPrivate(subExpr, subExpr->getType());
- if (!C) return nullptr;
- LangAS destAS = E->getType()->getPointeeType().getAddressSpace();
- LangAS srcAS = subExpr->getType()->getPointeeType().getAddressSpace();
- llvm::Type *destTy = ConvertType(E->getType());
- return CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGM, C, srcAS,
- destAS, destTy);
- }
-
- case CK_LValueToRValue:
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
- case CK_NoOp:
- case CK_ConstructorConversion:
- return Visit(subExpr, destType);
-
- case CK_IntToOCLSampler:
- llvm_unreachable("global sampler variables are not generated");
-
- case CK_Dependent: llvm_unreachable("saw dependent cast!");
-
- case CK_BuiltinFnToFnPtr:
- llvm_unreachable("builtin functions are handled elsewhere");
-
- case CK_ReinterpretMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_BaseToDerivedMemberPointer: {
- auto C = Emitter.tryEmitPrivate(subExpr, subExpr->getType());
- if (!C) return nullptr;
- return CGM.getCXXABI().EmitMemberPointerConversion(E, C);
- }
-
- // These will never be supported.
- case CK_ObjCObjectLValueCast:
- case CK_ARCProduceObject:
- case CK_ARCConsumeObject:
- case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject:
- case CK_CopyAndAutoreleaseBlockObject:
- return nullptr;
-
- // These don't need to be handled here because Evaluate knows how to
- // evaluate them in the cases where they can be folded.
- case CK_BitCast:
- case CK_ToVoid:
- case CK_Dynamic:
- case CK_LValueBitCast:
- case CK_NullToMemberPointer:
- case CK_UserDefinedConversion:
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
- case CK_BaseToDerived:
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase:
- case CK_MemberPointerToBoolean:
- case CK_VectorSplat:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
- case CK_NullToPointer:
- case CK_IntegralCast:
- case CK_BooleanToSignedIntegral:
- case CK_IntegralToPointer:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_FixedPointCast:
- case CK_FixedPointToBoolean:
- case CK_ZeroToOCLOpaqueType:
- return nullptr;
- }
- llvm_unreachable("Invalid CastKind");
- }
-
- llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE, QualType T) {
- return Visit(DAE->getExpr(), T);
- }
-
- llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE, QualType T) {
- // No need for a DefaultInitExprScope: we don't handle 'this' in a
- // constant expression.
- return Visit(DIE->getExpr(), T);
- }
-
- llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E, QualType T) {
- if (!E->cleanupsHaveSideEffects())
- return Visit(E->getSubExpr(), T);
- return nullptr;
- }
-
- llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E,
- QualType T) {
- return Visit(E->GetTemporaryExpr(), T);
- }
-
- llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) {
- auto *CAT = CGM.getContext().getAsConstantArrayType(ILE->getType());
- assert(CAT && "can't emit array init for non-constant-bound array");
- unsigned NumInitElements = ILE->getNumInits();
- unsigned NumElements = CAT->getSize().getZExtValue();
-
- // Initialising an array requires us to automatically
- // initialise any elements that have not been initialised explicitly
- unsigned NumInitableElts = std::min(NumInitElements, NumElements);
-
- QualType EltType = CAT->getElementType();
-
- // Initialize remaining array elements.
- llvm::Constant *fillC = nullptr;
- if (Expr *filler = ILE->getArrayFiller()) {
- fillC = Emitter.tryEmitAbstractForMemory(filler, EltType);
- if (!fillC)
- return nullptr;
- }
-
- // Copy initializer elements.
- SmallVector<llvm::Constant*, 16> Elts;
- if (fillC && fillC->isNullValue())
- Elts.reserve(NumInitableElts + 1);
- else
- Elts.reserve(NumElements);
-
- llvm::Type *CommonElementType = nullptr;
- for (unsigned i = 0; i < NumInitableElts; ++i) {
- Expr *Init = ILE->getInit(i);
- llvm::Constant *C = Emitter.tryEmitPrivateForMemory(Init, EltType);
- if (!C)
- return nullptr;
- if (i == 0)
- CommonElementType = C->getType();
- else if (C->getType() != CommonElementType)
- CommonElementType = nullptr;
- Elts.push_back(C);
- }
-
- return EmitArrayConstant(CGM, CAT, CommonElementType, NumElements, Elts,
- fillC);
- }
-
- llvm::Constant *EmitRecordInitialization(InitListExpr *ILE, QualType T) {
- return ConstStructBuilder::BuildStruct(Emitter, ILE, T);
- }
-
- llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E,
- QualType T) {
- return CGM.EmitNullConstant(T);
- }
-
- llvm::Constant *VisitInitListExpr(InitListExpr *ILE, QualType T) {
- if (ILE->isTransparent())
- return Visit(ILE->getInit(0), T);
-
- if (ILE->getType()->isArrayType())
- return EmitArrayInitialization(ILE, T);
-
- if (ILE->getType()->isRecordType())
- return EmitRecordInitialization(ILE, T);
-
- return nullptr;
- }
-
- llvm::Constant *EmitDesignatedInitUpdater(llvm::Constant *Base,
- InitListExpr *Updater,
- QualType destType) {
- if (auto destAT = CGM.getContext().getAsArrayType(destType)) {
- llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(destType));
- llvm::Type *ElemType = AType->getElementType();
-
- unsigned NumInitElements = Updater->getNumInits();
- unsigned NumElements = AType->getNumElements();
-
- std::vector<llvm::Constant *> Elts;
- Elts.reserve(NumElements);
-
- QualType destElemType = destAT->getElementType();
-
- if (auto DataArray = dyn_cast<llvm::ConstantDataArray>(Base))
- for (unsigned i = 0; i != NumElements; ++i)
- Elts.push_back(DataArray->getElementAsConstant(i));
- else if (auto Array = dyn_cast<llvm::ConstantArray>(Base))
- for (unsigned i = 0; i != NumElements; ++i)
- Elts.push_back(Array->getOperand(i));
- else
- return nullptr; // FIXME: other array types not implemented
-
- llvm::Constant *fillC = nullptr;
- if (Expr *filler = Updater->getArrayFiller())
- if (!isa<NoInitExpr>(filler))
- fillC = Emitter.tryEmitAbstractForMemory(filler, destElemType);
- bool RewriteType = (fillC && fillC->getType() != ElemType);
-
- for (unsigned i = 0; i != NumElements; ++i) {
- Expr *Init = nullptr;
- if (i < NumInitElements)
- Init = Updater->getInit(i);
-
- if (!Init && fillC)
- Elts[i] = fillC;
- else if (!Init || isa<NoInitExpr>(Init))
- ; // Do nothing.
- else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init))
- Elts[i] = EmitDesignatedInitUpdater(Elts[i], ChildILE, destElemType);
- else
- Elts[i] = Emitter.tryEmitPrivateForMemory(Init, destElemType);
-
- if (!Elts[i])
- return nullptr;
- RewriteType |= (Elts[i]->getType() != ElemType);
- }
-
- if (RewriteType) {
- std::vector<llvm::Type *> Types;
- Types.reserve(NumElements);
- for (unsigned i = 0; i != NumElements; ++i)
- Types.push_back(Elts[i]->getType());
- llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
- Types, true);
- return llvm::ConstantStruct::get(SType, Elts);
- }
-
- return llvm::ConstantArray::get(AType, Elts);
- }
-
- if (destType->isRecordType())
- return ConstStructBuilder::BuildStruct(Emitter, this, Base, Updater,
- destType);
-
- return nullptr;
- }
-
- llvm::Constant *VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E,
- QualType destType) {
- auto C = Visit(E->getBase(), destType);
- if (!C) return nullptr;
- return EmitDesignatedInitUpdater(C, E->getUpdater(), destType);
- }
-
- llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E, QualType Ty) {
- if (!E->getConstructor()->isTrivial())
- return nullptr;
-
- // FIXME: We should not have to call getBaseElementType here.
- const RecordType *RT =
- CGM.getContext().getBaseElementType(Ty)->getAs<RecordType>();
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
- // If the class doesn't have a trivial destructor, we can't emit it as a
- // constant expr.
- if (!RD->hasTrivialDestructor())
- return nullptr;
-
- // Only copy and default constructors can be trivial.
-
-
- if (E->getNumArgs()) {
- assert(E->getNumArgs() == 1 && "trivial ctor with > 1 argument");
- assert(E->getConstructor()->isCopyOrMoveConstructor() &&
- "trivial ctor has argument but isn't a copy/move ctor");
-
- Expr *Arg = E->getArg(0);
- assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) &&
- "argument to copy ctor is of wrong type");
-
- return Visit(Arg, Ty);
- }
-
- return CGM.EmitNullConstant(Ty);
- }
-
- llvm::Constant *VisitStringLiteral(StringLiteral *E, QualType T) {
- return CGM.GetConstantArrayFromStringLiteral(E);
- }
-
- llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E, QualType T) {
- // This must be an @encode initializing an array in a static initializer.
- // Don't emit it as the address of the string, emit the string data itself
- // as an inline array.
- std::string Str;
- CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str);
- const ConstantArrayType *CAT = CGM.getContext().getAsConstantArrayType(T);
-
- // Resize the string to the right size, adding zeros at the end, or
- // truncating as needed.
- Str.resize(CAT->getSize().getZExtValue(), '\0');
- return llvm::ConstantDataArray::getString(VMContext, Str, false);
- }
-
- llvm::Constant *VisitUnaryExtension(const UnaryOperator *E, QualType T) {
- return Visit(E->getSubExpr(), T);
- }
-
- // Utility methods
- llvm::Type *ConvertType(QualType T) {
- return CGM.getTypes().ConvertType(T);
- }
-};
-
-} // end anonymous namespace.
-
-bool ConstStructBuilder::Build(ConstExprEmitter *ExprEmitter,
- llvm::Constant *Base,
- InitListExpr *Updater) {
- assert(Base && "base expression should not be empty");
-
- QualType ExprType = Updater->getType();
- RecordDecl *RD = ExprType->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const llvm::StructLayout *BaseLayout = CGM.getDataLayout().getStructLayout(
- cast<llvm::StructType>(Base->getType()));
- unsigned FieldNo = -1;
- unsigned ElementNo = 0;
-
- // Bail out if we have base classes. We could support these, but they only
- // arise in C++1z where we will have already constant folded most interesting
- // cases. FIXME: There are still a few more cases we can handle this way.
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- if (CXXRD->getNumBases())
- return false;
-
- for (FieldDecl *Field : RD->fields()) {
- ++FieldNo;
-
- if (RD->isUnion() && Updater->getInitializedFieldInUnion() != Field)
- continue;
-
- // Skip anonymous bitfields.
- if (Field->isUnnamedBitfield())
- continue;
-
- llvm::Constant *EltInit = Base->getAggregateElement(ElementNo);
-
- // Bail out if the type of the ConstantStruct does not have the same layout
- // as the type of the InitListExpr.
- if (CGM.getTypes().ConvertType(Field->getType()) != EltInit->getType() ||
- Layout.getFieldOffset(ElementNo) !=
- BaseLayout->getElementOffsetInBits(ElementNo))
- return false;
-
- // Get the initializer. If we encounter an empty field or a NoInitExpr,
- // we use values from the base expression.
- Expr *Init = nullptr;
- if (ElementNo < Updater->getNumInits())
- Init = Updater->getInit(ElementNo);
-
- if (!Init || isa<NoInitExpr>(Init))
- ; // Do nothing.
- else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init))
- EltInit = ExprEmitter->EmitDesignatedInitUpdater(EltInit, ChildILE,
- Field->getType());
- else
- EltInit = Emitter.tryEmitPrivateForMemory(Init, Field->getType());
-
- ++ElementNo;
-
- if (!EltInit)
- return false;
-
- if (!Field->isBitField())
- AppendField(Field, Layout.getFieldOffset(FieldNo), EltInit);
- else if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(EltInit))
- AppendBitField(Field, Layout.getFieldOffset(FieldNo), CI);
- else
- // Initializing a bitfield with a non-trivial constant?
- return false;
- }
-
- return true;
-}
-
-llvm::Constant *ConstantEmitter::validateAndPopAbstract(llvm::Constant *C,
- AbstractState saved) {
- Abstract = saved.OldValue;
-
- assert(saved.OldPlaceholdersSize == PlaceholderAddresses.size() &&
- "created a placeholder while doing an abstract emission?");
-
- // No validation necessary for now.
- // No cleanup to do for now.
- return C;
-}
-
-llvm::Constant *
-ConstantEmitter::tryEmitAbstractForInitializer(const VarDecl &D) {
- auto state = pushAbstract();
- auto C = tryEmitPrivateForVarInit(D);
- return validateAndPopAbstract(C, state);
-}
-
-llvm::Constant *
-ConstantEmitter::tryEmitAbstract(const Expr *E, QualType destType) {
- auto state = pushAbstract();
- auto C = tryEmitPrivate(E, destType);
- return validateAndPopAbstract(C, state);
-}
-
-llvm::Constant *
-ConstantEmitter::tryEmitAbstract(const APValue &value, QualType destType) {
- auto state = pushAbstract();
- auto C = tryEmitPrivate(value, destType);
- return validateAndPopAbstract(C, state);
-}
-
-llvm::Constant *
-ConstantEmitter::emitAbstract(const Expr *E, QualType destType) {
- auto state = pushAbstract();
- auto C = tryEmitPrivate(E, destType);
- C = validateAndPopAbstract(C, state);
- if (!C) {
- CGM.Error(E->getExprLoc(),
- "internal error: could not emit constant value \"abstractly\"");
- C = CGM.EmitNullConstant(destType);
- }
- return C;
-}
-
-llvm::Constant *
-ConstantEmitter::emitAbstract(SourceLocation loc, const APValue &value,
- QualType destType) {
- auto state = pushAbstract();
- auto C = tryEmitPrivate(value, destType);
- C = validateAndPopAbstract(C, state);
- if (!C) {
- CGM.Error(loc,
- "internal error: could not emit constant value \"abstractly\"");
- C = CGM.EmitNullConstant(destType);
- }
- return C;
-}
-
-llvm::Constant *ConstantEmitter::tryEmitForInitializer(const VarDecl &D) {
- initializeNonAbstract(D.getType().getAddressSpace());
- return markIfFailed(tryEmitPrivateForVarInit(D));
-}
-
-llvm::Constant *ConstantEmitter::tryEmitForInitializer(const Expr *E,
- LangAS destAddrSpace,
- QualType destType) {
- initializeNonAbstract(destAddrSpace);
- return markIfFailed(tryEmitPrivateForMemory(E, destType));
-}
-
-llvm::Constant *ConstantEmitter::emitForInitializer(const APValue &value,
- LangAS destAddrSpace,
- QualType destType) {
- initializeNonAbstract(destAddrSpace);
- auto C = tryEmitPrivateForMemory(value, destType);
- assert(C && "couldn't emit constant value non-abstractly?");
- return C;
-}
-
-llvm::GlobalValue *ConstantEmitter::getCurrentAddrPrivate() {
- assert(!Abstract && "cannot get current address for abstract constant");
-
-
-
- // Make an obviously ill-formed global that should blow up compilation
- // if it survives.
- auto global = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty, true,
- llvm::GlobalValue::PrivateLinkage,
- /*init*/ nullptr,
- /*name*/ "",
- /*before*/ nullptr,
- llvm::GlobalVariable::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(DestAddressSpace));
-
- PlaceholderAddresses.push_back(std::make_pair(nullptr, global));
-
- return global;
-}
-
-void ConstantEmitter::registerCurrentAddrPrivate(llvm::Constant *signal,
- llvm::GlobalValue *placeholder) {
- assert(!PlaceholderAddresses.empty());
- assert(PlaceholderAddresses.back().first == nullptr);
- assert(PlaceholderAddresses.back().second == placeholder);
- PlaceholderAddresses.back().first = signal;
-}
-
-namespace {
- struct ReplacePlaceholders {
- CodeGenModule &CGM;
-
- /// The base address of the global.
- llvm::Constant *Base;
- llvm::Type *BaseValueTy = nullptr;
-
- /// The placeholder addresses that were registered during emission.
- llvm::DenseMap<llvm::Constant*, llvm::GlobalVariable*> PlaceholderAddresses;
-
- /// The locations of the placeholder signals.
- llvm::DenseMap<llvm::GlobalVariable*, llvm::Constant*> Locations;
-
- /// The current index stack. We use a simple unsigned stack because
- /// we assume that placeholders will be relatively sparse in the
- /// initializer, but we cache the index values we find just in case.
- llvm::SmallVector<unsigned, 8> Indices;
- llvm::SmallVector<llvm::Constant*, 8> IndexValues;
-
- ReplacePlaceholders(CodeGenModule &CGM, llvm::Constant *base,
- ArrayRef<std::pair<llvm::Constant*,
- llvm::GlobalVariable*>> addresses)
- : CGM(CGM), Base(base),
- PlaceholderAddresses(addresses.begin(), addresses.end()) {
- }
-
- void replaceInInitializer(llvm::Constant *init) {
- // Remember the type of the top-most initializer.
- BaseValueTy = init->getType();
-
- // Initialize the stack.
- Indices.push_back(0);
- IndexValues.push_back(nullptr);
-
- // Recurse into the initializer.
- findLocations(init);
-
- // Check invariants.
- assert(IndexValues.size() == Indices.size() && "mismatch");
- assert(Indices.size() == 1 && "didn't pop all indices");
-
- // Do the replacement; this basically invalidates 'init'.
- assert(Locations.size() == PlaceholderAddresses.size() &&
- "missed a placeholder?");
-
- // We're iterating over a hashtable, so this would be a source of
- // non-determinism in compiler output *except* that we're just
- // messing around with llvm::Constant structures, which never itself
- // does anything that should be visible in compiler output.
- for (auto &entry : Locations) {
- assert(entry.first->getParent() == nullptr && "not a placeholder!");
- entry.first->replaceAllUsesWith(entry.second);
- entry.first->eraseFromParent();
- }
- }
-
- private:
- void findLocations(llvm::Constant *init) {
- // Recurse into aggregates.
- if (auto agg = dyn_cast<llvm::ConstantAggregate>(init)) {
- for (unsigned i = 0, e = agg->getNumOperands(); i != e; ++i) {
- Indices.push_back(i);
- IndexValues.push_back(nullptr);
-
- findLocations(agg->getOperand(i));
-
- IndexValues.pop_back();
- Indices.pop_back();
- }
- return;
- }
-
- // Otherwise, check for registered constants.
- while (true) {
- auto it = PlaceholderAddresses.find(init);
- if (it != PlaceholderAddresses.end()) {
- setLocation(it->second);
- break;
- }
-
- // Look through bitcasts or other expressions.
- if (auto expr = dyn_cast<llvm::ConstantExpr>(init)) {
- init = expr->getOperand(0);
- } else {
- break;
- }
- }
- }
-
- void setLocation(llvm::GlobalVariable *placeholder) {
- assert(Locations.find(placeholder) == Locations.end() &&
- "already found location for placeholder!");
-
- // Lazily fill in IndexValues with the values from Indices.
- // We do this in reverse because we should always have a strict
- // prefix of indices from the start.
- assert(Indices.size() == IndexValues.size());
- for (size_t i = Indices.size() - 1; i != size_t(-1); --i) {
- if (IndexValues[i]) {
-#ifndef NDEBUG
- for (size_t j = 0; j != i + 1; ++j) {
- assert(IndexValues[j] &&
- isa<llvm::ConstantInt>(IndexValues[j]) &&
- cast<llvm::ConstantInt>(IndexValues[j])->getZExtValue()
- == Indices[j]);
- }
-#endif
- break;
- }
-
- IndexValues[i] = llvm::ConstantInt::get(CGM.Int32Ty, Indices[i]);
- }
-
- // Form a GEP and then bitcast to the placeholder type so that the
- // replacement will succeed.
- llvm::Constant *location =
- llvm::ConstantExpr::getInBoundsGetElementPtr(BaseValueTy,
- Base, IndexValues);
- location = llvm::ConstantExpr::getBitCast(location,
- placeholder->getType());
-
- Locations.insert({placeholder, location});
- }
- };
-}
-
-void ConstantEmitter::finalize(llvm::GlobalVariable *global) {
- assert(InitializedNonAbstract &&
- "finalizing emitter that was used for abstract emission?");
- assert(!Finalized && "finalizing emitter multiple times");
- assert(global->getInitializer());
-
- // Note that we might also be Failed.
- Finalized = true;
-
- if (!PlaceholderAddresses.empty()) {
- ReplacePlaceholders(CGM, global, PlaceholderAddresses)
- .replaceInInitializer(global->getInitializer());
- PlaceholderAddresses.clear(); // satisfy
- }
-}
-
-ConstantEmitter::~ConstantEmitter() {
- assert((!InitializedNonAbstract || Finalized || Failed) &&
- "not finalized after being initialized for non-abstract emission");
- assert(PlaceholderAddresses.empty() && "unhandled placeholders");
-}
-
-static QualType getNonMemoryType(CodeGenModule &CGM, QualType type) {
- if (auto AT = type->getAs<AtomicType>()) {
- return CGM.getContext().getQualifiedType(AT->getValueType(),
- type.getQualifiers());
- }
- return type;
-}
-
-llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
- // Make a quick check if variable can be default NULL initialized
- // and avoid going through rest of code which may do, for c++11,
- // initialization of memory to all NULLs.
- if (!D.hasLocalStorage()) {
- QualType Ty = CGM.getContext().getBaseElementType(D.getType());
- if (Ty->isRecordType())
- if (const CXXConstructExpr *E =
- dyn_cast_or_null<CXXConstructExpr>(D.getInit())) {
- const CXXConstructorDecl *CD = E->getConstructor();
- if (CD->isTrivial() && CD->isDefaultConstructor())
- return CGM.EmitNullConstant(D.getType());
- }
- InConstantContext = true;
- }
-
- QualType destType = D.getType();
-
- // Try to emit the initializer. Note that this can allow some things that
- // are not allowed by tryEmitPrivateForMemory alone.
- if (auto value = D.evaluateValue()) {
- return tryEmitPrivateForMemory(*value, destType);
- }
-
- // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a
- // reference is a constant expression, and the reference binds to a temporary,
- // then constant initialization is performed. ConstExprEmitter will
- // incorrectly emit a prvalue constant in this case, and the calling code
- // interprets that as the (pointer) value of the reference, rather than the
- // desired value of the referee.
- if (destType->isReferenceType())
- return nullptr;
-
- const Expr *E = D.getInit();
- assert(E && "No initializer to emit");
-
- auto nonMemoryDestType = getNonMemoryType(CGM, destType);
- auto C =
- ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), nonMemoryDestType);
- return (C ? emitForMemory(C, destType) : nullptr);
-}
-
-llvm::Constant *
-ConstantEmitter::tryEmitAbstractForMemory(const Expr *E, QualType destType) {
- auto nonMemoryDestType = getNonMemoryType(CGM, destType);
- auto C = tryEmitAbstract(E, nonMemoryDestType);
- return (C ? emitForMemory(C, destType) : nullptr);
-}
-
-llvm::Constant *
-ConstantEmitter::tryEmitAbstractForMemory(const APValue &value,
- QualType destType) {
- auto nonMemoryDestType = getNonMemoryType(CGM, destType);
- auto C = tryEmitAbstract(value, nonMemoryDestType);
- return (C ? emitForMemory(C, destType) : nullptr);
-}
-
-llvm::Constant *ConstantEmitter::tryEmitPrivateForMemory(const Expr *E,
- QualType destType) {
- auto nonMemoryDestType = getNonMemoryType(CGM, destType);
- llvm::Constant *C = tryEmitPrivate(E, nonMemoryDestType);
- return (C ? emitForMemory(C, destType) : nullptr);
-}
-
-llvm::Constant *ConstantEmitter::tryEmitPrivateForMemory(const APValue &value,
- QualType destType) {
- auto nonMemoryDestType = getNonMemoryType(CGM, destType);
- auto C = tryEmitPrivate(value, nonMemoryDestType);
- return (C ? emitForMemory(C, destType) : nullptr);
-}
-
-llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM,
- llvm::Constant *C,
- QualType destType) {
- // For an _Atomic-qualified constant, we may need to add tail padding.
- if (auto AT = destType->getAs<AtomicType>()) {
- QualType destValueType = AT->getValueType();
- C = emitForMemory(CGM, C, destValueType);
-
- uint64_t innerSize = CGM.getContext().getTypeSize(destValueType);
- uint64_t outerSize = CGM.getContext().getTypeSize(destType);
- if (innerSize == outerSize)
- return C;
-
- assert(innerSize < outerSize && "emitted over-large constant for atomic");
- llvm::Constant *elts[] = {
- C,
- llvm::ConstantAggregateZero::get(
- llvm::ArrayType::get(CGM.Int8Ty, (outerSize - innerSize) / 8))
- };
- return llvm::ConstantStruct::getAnon(elts);
- }
-
- // Zero-extend bool.
- if (C->getType()->isIntegerTy(1)) {
- llvm::Type *boolTy = CGM.getTypes().ConvertTypeForMem(destType);
- return llvm::ConstantExpr::getZExt(C, boolTy);
- }
-
- return C;
-}
-
-llvm::Constant *ConstantEmitter::tryEmitPrivate(const Expr *E,
- QualType destType) {
- Expr::EvalResult Result;
-
- bool Success = false;
-
- if (destType->isReferenceType())
- Success = E->EvaluateAsLValue(Result, CGM.getContext());
- else
- Success = E->EvaluateAsRValue(Result, CGM.getContext(), InConstantContext);
-
- llvm::Constant *C;
- if (Success && !Result.HasSideEffects)
- C = tryEmitPrivate(Result.Val, destType);
- else
- C = ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), destType);
-
- return C;
-}
-
-llvm::Constant *CodeGenModule::getNullPointer(llvm::PointerType *T, QualType QT) {
- return getTargetCodeGenInfo().getNullPointer(*this, T, QT);
-}
-
-namespace {
-/// A struct which can be used to peephole certain kinds of finalization
-/// that normally happen during l-value emission.
-struct ConstantLValue {
- llvm::Constant *Value;
- bool HasOffsetApplied;
-
- /*implicit*/ ConstantLValue(llvm::Constant *value,
- bool hasOffsetApplied = false)
- : Value(value), HasOffsetApplied(false) {}
-
- /*implicit*/ ConstantLValue(ConstantAddress address)
- : ConstantLValue(address.getPointer()) {}
-};
-
-/// A helper class for emitting constant l-values.
-class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
- ConstantLValue> {
- CodeGenModule &CGM;
- ConstantEmitter &Emitter;
- const APValue &Value;
- QualType DestType;
-
- // Befriend StmtVisitorBase so that we don't have to expose Visit*.
- friend StmtVisitorBase;
-
-public:
- ConstantLValueEmitter(ConstantEmitter &emitter, const APValue &value,
- QualType destType)
- : CGM(emitter.CGM), Emitter(emitter), Value(value), DestType(destType) {}
-
- llvm::Constant *tryEmit();
-
-private:
- llvm::Constant *tryEmitAbsolute(llvm::Type *destTy);
- ConstantLValue tryEmitBase(const APValue::LValueBase &base);
-
- ConstantLValue VisitStmt(const Stmt *S) { return nullptr; }
- ConstantLValue VisitConstantExpr(const ConstantExpr *E);
- ConstantLValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
- ConstantLValue VisitStringLiteral(const StringLiteral *E);
- ConstantLValue VisitObjCEncodeExpr(const ObjCEncodeExpr *E);
- ConstantLValue VisitObjCStringLiteral(const ObjCStringLiteral *E);
- ConstantLValue VisitPredefinedExpr(const PredefinedExpr *E);
- ConstantLValue VisitAddrLabelExpr(const AddrLabelExpr *E);
- ConstantLValue VisitCallExpr(const CallExpr *E);
- ConstantLValue VisitBlockExpr(const BlockExpr *E);
- ConstantLValue VisitCXXTypeidExpr(const CXXTypeidExpr *E);
- ConstantLValue VisitCXXUuidofExpr(const CXXUuidofExpr *E);
- ConstantLValue VisitMaterializeTemporaryExpr(
- const MaterializeTemporaryExpr *E);
-
- bool hasNonZeroOffset() const {
- return !Value.getLValueOffset().isZero();
- }
-
- /// Return the value offset.
- llvm::Constant *getOffset() {
- return llvm::ConstantInt::get(CGM.Int64Ty,
- Value.getLValueOffset().getQuantity());
- }
-
- /// Apply the value offset to the given constant.
- llvm::Constant *applyOffset(llvm::Constant *C) {
- if (!hasNonZeroOffset())
- return C;
-
- llvm::Type *origPtrTy = C->getType();
- unsigned AS = origPtrTy->getPointerAddressSpace();
- llvm::Type *charPtrTy = CGM.Int8Ty->getPointerTo(AS);
- C = llvm::ConstantExpr::getBitCast(C, charPtrTy);
- C = llvm::ConstantExpr::getGetElementPtr(CGM.Int8Ty, C, getOffset());
- C = llvm::ConstantExpr::getPointerCast(C, origPtrTy);
- return C;
- }
-};
-
-}
-
-llvm::Constant *ConstantLValueEmitter::tryEmit() {
- const APValue::LValueBase &base = Value.getLValueBase();
-
- // Certain special array initializers are represented in APValue
- // as l-values referring to the base expression which generates the
- // array. This happens with e.g. string literals. These should
- // probably just get their own representation kind in APValue.
- if (DestType->isArrayType()) {
- assert(!hasNonZeroOffset() && "offset on array initializer");
- auto expr = const_cast<Expr*>(base.get<const Expr*>());
- return ConstExprEmitter(Emitter).Visit(expr, DestType);
- }
-
- // Otherwise, the destination type should be a pointer or reference
- // type, but it might also be a cast thereof.
- //
- // FIXME: the chain of casts required should be reflected in the APValue.
- // We need this in order to correctly handle things like a ptrtoint of a
- // non-zero null pointer and addrspace casts that aren't trivially
- // represented in LLVM IR.
- auto destTy = CGM.getTypes().ConvertTypeForMem(DestType);
- assert(isa<llvm::IntegerType>(destTy) || isa<llvm::PointerType>(destTy));
-
- // If there's no base at all, this is a null or absolute pointer,
- // possibly cast back to an integer type.
- if (!base) {
- return tryEmitAbsolute(destTy);
- }
-
- // Otherwise, try to emit the base.
- ConstantLValue result = tryEmitBase(base);
-
- // If that failed, we're done.
- llvm::Constant *value = result.Value;
- if (!value) return nullptr;
-
- // Apply the offset if necessary and not already done.
- if (!result.HasOffsetApplied) {
- value = applyOffset(value);
- }
-
- // Convert to the appropriate type; this could be an lvalue for
- // an integer. FIXME: performAddrSpaceCast
- if (isa<llvm::PointerType>(destTy))
- return llvm::ConstantExpr::getPointerCast(value, destTy);
-
- return llvm::ConstantExpr::getPtrToInt(value, destTy);
-}
-
-/// Try to emit an absolute l-value, such as a null pointer or an integer
-/// bitcast to pointer type.
-llvm::Constant *
-ConstantLValueEmitter::tryEmitAbsolute(llvm::Type *destTy) {
- auto offset = getOffset();
-
- // If we're producing a pointer, this is easy.
- if (auto destPtrTy = cast<llvm::PointerType>(destTy)) {
- if (Value.isNullPointer()) {
- // FIXME: integer offsets from non-zero null pointers.
- return CGM.getNullPointer(destPtrTy, DestType);
- }
-
- // Convert the integer to a pointer-sized integer before converting it
- // to a pointer.
- // FIXME: signedness depends on the original integer type.
- auto intptrTy = CGM.getDataLayout().getIntPtrType(destPtrTy);
- llvm::Constant *C = offset;
- C = llvm::ConstantExpr::getIntegerCast(getOffset(), intptrTy,
- /*isSigned*/ false);
- C = llvm::ConstantExpr::getIntToPtr(C, destPtrTy);
- return C;
- }
-
- // Otherwise, we're basically returning an integer constant.
-
- // FIXME: this does the wrong thing with ptrtoint of a null pointer,
- // but since we don't know the original pointer type, there's not much
- // we can do about it.
-
- auto C = getOffset();
- C = llvm::ConstantExpr::getIntegerCast(C, destTy, /*isSigned*/ false);
- return C;
-}
-
-ConstantLValue
-ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
- // Handle values.
- if (const ValueDecl *D = base.dyn_cast<const ValueDecl*>()) {
- if (D->hasAttr<WeakRefAttr>())
- return CGM.GetWeakRefReference(D).getPointer();
-
- if (auto FD = dyn_cast<FunctionDecl>(D))
- return CGM.GetAddrOfFunction(FD);
-
- if (auto VD = dyn_cast<VarDecl>(D)) {
- // We can never refer to a variable with local storage.
- if (!VD->hasLocalStorage()) {
- if (VD->isFileVarDecl() || VD->hasExternalStorage())
- return CGM.GetAddrOfGlobalVar(VD);
-
- if (VD->isLocalVarDecl()) {
- return CGM.getOrCreateStaticVarDecl(
- *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false));
- }
- }
- }
-
- return nullptr;
- }
-
- // Otherwise, it must be an expression.
- return Visit(base.get<const Expr*>());
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitConstantExpr(const ConstantExpr *E) {
- return Visit(E->getSubExpr());
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
- return tryEmitGlobalCompoundLiteral(CGM, Emitter.CGF, E);
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitStringLiteral(const StringLiteral *E) {
- return CGM.GetAddrOfConstantStringFromLiteral(E);
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
- return CGM.GetAddrOfConstantStringFromObjCEncode(E);
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitObjCStringLiteral(const ObjCStringLiteral *E) {
- auto C = CGM.getObjCRuntime().GenerateConstantString(E->getString());
- return C.getElementBitCast(CGM.getTypes().ConvertTypeForMem(E->getType()));
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitPredefinedExpr(const PredefinedExpr *E) {
- if (auto CGF = Emitter.CGF) {
- LValue Res = CGF->EmitPredefinedLValue(E);
- return cast<ConstantAddress>(Res.getAddress());
- }
-
- auto kind = E->getIdentKind();
- if (kind == PredefinedExpr::PrettyFunction) {
- return CGM.GetAddrOfConstantCString("top level", ".tmp");
- }
-
- return CGM.GetAddrOfConstantCString("", ".tmp");
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitAddrLabelExpr(const AddrLabelExpr *E) {
- assert(Emitter.CGF && "Invalid address of label expression outside function");
- llvm::Constant *Ptr = Emitter.CGF->GetAddrOfLabel(E->getLabel());
- Ptr = llvm::ConstantExpr::getBitCast(Ptr,
- CGM.getTypes().ConvertType(E->getType()));
- return Ptr;
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
- unsigned builtin = E->getBuiltinCallee();
- if (builtin != Builtin::BI__builtin___CFStringMakeConstantString &&
- builtin != Builtin::BI__builtin___NSStringMakeConstantString)
- return nullptr;
-
- auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts());
- if (builtin == Builtin::BI__builtin___NSStringMakeConstantString) {
- return CGM.getObjCRuntime().GenerateConstantString(literal);
- } else {
- // FIXME: need to deal with UCN conversion issues.
- return CGM.GetAddrOfConstantCFString(literal);
- }
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *E) {
- StringRef functionName;
- if (auto CGF = Emitter.CGF)
- functionName = CGF->CurFn->getName();
- else
- functionName = "global";
-
- return CGM.GetAddrOfGlobalBlock(E, functionName);
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
- QualType T;
- if (E->isTypeOperand())
- T = E->getTypeOperand(CGM.getContext());
- else
- T = E->getExprOperand()->getType();
- return CGM.GetAddrOfRTTIDescriptor(T);
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
- return CGM.GetAddrOfUuidDescriptor(E);
-}
-
-ConstantLValue
-ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
- const MaterializeTemporaryExpr *E) {
- assert(E->getStorageDuration() == SD_Static);
- SmallVector<const Expr *, 2> CommaLHSs;
- SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Inner = E->GetTemporaryExpr()
- ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
- return CGM.GetAddrOfGlobalTemporary(E, Inner);
-}
-
-llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value,
- QualType DestType) {
- switch (Value.getKind()) {
- case APValue::Uninitialized:
- llvm_unreachable("Constant expressions should be initialized.");
- case APValue::LValue:
- return ConstantLValueEmitter(*this, Value, DestType).tryEmit();
- case APValue::Int:
- return llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getInt());
- case APValue::ComplexInt: {
- llvm::Constant *Complex[2];
-
- Complex[0] = llvm::ConstantInt::get(CGM.getLLVMContext(),
- Value.getComplexIntReal());
- Complex[1] = llvm::ConstantInt::get(CGM.getLLVMContext(),
- Value.getComplexIntImag());
-
- // FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy =
- llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType());
- return llvm::ConstantStruct::get(STy, Complex);
- }
- case APValue::Float: {
- const llvm::APFloat &Init = Value.getFloat();
- if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf() &&
- !CGM.getContext().getLangOpts().NativeHalfType &&
- CGM.getContext().getTargetInfo().useFP16ConversionIntrinsics())
- return llvm::ConstantInt::get(CGM.getLLVMContext(),
- Init.bitcastToAPInt());
- else
- return llvm::ConstantFP::get(CGM.getLLVMContext(), Init);
- }
- case APValue::ComplexFloat: {
- llvm::Constant *Complex[2];
-
- Complex[0] = llvm::ConstantFP::get(CGM.getLLVMContext(),
- Value.getComplexFloatReal());
- Complex[1] = llvm::ConstantFP::get(CGM.getLLVMContext(),
- Value.getComplexFloatImag());
-
- // FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy =
- llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType());
- return llvm::ConstantStruct::get(STy, Complex);
- }
- case APValue::Vector: {
- unsigned NumElts = Value.getVectorLength();
- SmallVector<llvm::Constant *, 4> Inits(NumElts);
-
- for (unsigned I = 0; I != NumElts; ++I) {
- const APValue &Elt = Value.getVectorElt(I);
- if (Elt.isInt())
- Inits[I] = llvm::ConstantInt::get(CGM.getLLVMContext(), Elt.getInt());
- else if (Elt.isFloat())
- Inits[I] = llvm::ConstantFP::get(CGM.getLLVMContext(), Elt.getFloat());
- else
- llvm_unreachable("unsupported vector element type");
- }
- return llvm::ConstantVector::get(Inits);
- }
- case APValue::AddrLabelDiff: {
- const AddrLabelExpr *LHSExpr = Value.getAddrLabelDiffLHS();
- const AddrLabelExpr *RHSExpr = Value.getAddrLabelDiffRHS();
- llvm::Constant *LHS = tryEmitPrivate(LHSExpr, LHSExpr->getType());
- llvm::Constant *RHS = tryEmitPrivate(RHSExpr, RHSExpr->getType());
- if (!LHS || !RHS) return nullptr;
-
- // Compute difference
- llvm::Type *ResultType = CGM.getTypes().ConvertType(DestType);
- LHS = llvm::ConstantExpr::getPtrToInt(LHS, CGM.IntPtrTy);
- RHS = llvm::ConstantExpr::getPtrToInt(RHS, CGM.IntPtrTy);
- llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS);
-
- // LLVM is a bit sensitive about the exact format of the
- // address-of-label difference; make sure to truncate after
- // the subtraction.
- return llvm::ConstantExpr::getTruncOrBitCast(AddrLabelDiff, ResultType);
- }
- case APValue::Struct:
- case APValue::Union:
- return ConstStructBuilder::BuildStruct(*this, Value, DestType);
- case APValue::Array: {
- const ConstantArrayType *CAT =
- CGM.getContext().getAsConstantArrayType(DestType);
- unsigned NumElements = Value.getArraySize();
- unsigned NumInitElts = Value.getArrayInitializedElts();
-
- // Emit array filler, if there is one.
- llvm::Constant *Filler = nullptr;
- if (Value.hasArrayFiller()) {
- Filler = tryEmitAbstractForMemory(Value.getArrayFiller(),
- CAT->getElementType());
- if (!Filler)
- return nullptr;
- }
-
- // Emit initializer elements.
- SmallVector<llvm::Constant*, 16> Elts;
- if (Filler && Filler->isNullValue())
- Elts.reserve(NumInitElts + 1);
- else
- Elts.reserve(NumElements);
-
- llvm::Type *CommonElementType = nullptr;
- for (unsigned I = 0; I < NumInitElts; ++I) {
- llvm::Constant *C = tryEmitPrivateForMemory(
- Value.getArrayInitializedElt(I), CAT->getElementType());
- if (!C) return nullptr;
-
- if (I == 0)
- CommonElementType = C->getType();
- else if (C->getType() != CommonElementType)
- CommonElementType = nullptr;
- Elts.push_back(C);
- }
-
- // This means that the array type is probably "IncompleteType" or some
- // type that is not ConstantArray.
- if (CAT == nullptr && CommonElementType == nullptr && !NumInitElts) {
- const ArrayType *AT = CGM.getContext().getAsArrayType(DestType);
- CommonElementType = CGM.getTypes().ConvertType(AT->getElementType());
- llvm::ArrayType *AType = llvm::ArrayType::get(CommonElementType,
- NumElements);
- return llvm::ConstantAggregateZero::get(AType);
- }
-
- return EmitArrayConstant(CGM, CAT, CommonElementType, NumElements, Elts,
- Filler);
- }
- case APValue::MemberPointer:
- return CGM.getCXXABI().EmitMemberPointer(Value, DestType);
- }
- llvm_unreachable("Unknown APValue kind");
-}
-
-llvm::GlobalVariable *CodeGenModule::getAddrOfConstantCompoundLiteralIfEmitted(
- const CompoundLiteralExpr *E) {
- return EmittedCompoundLiterals.lookup(E);
-}
-
-void CodeGenModule::setAddrOfConstantCompoundLiteral(
- const CompoundLiteralExpr *CLE, llvm::GlobalVariable *GV) {
- bool Ok = EmittedCompoundLiterals.insert(std::make_pair(CLE, GV)).second;
- (void)Ok;
- assert(Ok && "CLE has already been emitted!");
-}
-
-ConstantAddress
-CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) {
- assert(E->isFileScope() && "not a file-scope compound literal expr");
- return tryEmitGlobalCompoundLiteral(*this, nullptr, E);
-}
-
-llvm::Constant *
-CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) {
- // Member pointer constants always have a very particular form.
- const MemberPointerType *type = cast<MemberPointerType>(uo->getType());
- const ValueDecl *decl = cast<DeclRefExpr>(uo->getSubExpr())->getDecl();
-
- // A member function pointer.
- if (const CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(decl))
- return getCXXABI().EmitMemberFunctionPointer(method);
-
- // Otherwise, a member data pointer.
- uint64_t fieldOffset = getContext().getFieldOffset(decl);
- CharUnits chars = getContext().toCharUnitsFromBits((int64_t) fieldOffset);
- return getCXXABI().EmitMemberDataPointer(type, chars);
-}
-
-static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
- llvm::Type *baseType,
- const CXXRecordDecl *base);
-
-static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
- const RecordDecl *record,
- bool asCompleteObject) {
- const CGRecordLayout &layout = CGM.getTypes().getCGRecordLayout(record);
- llvm::StructType *structure =
- (asCompleteObject ? layout.getLLVMType()
- : layout.getBaseSubobjectLLVMType());
-
- unsigned numElements = structure->getNumElements();
- std::vector<llvm::Constant *> elements(numElements);
-
- auto CXXR = dyn_cast<CXXRecordDecl>(record);
- // Fill in all the bases.
- if (CXXR) {
- for (const auto &I : CXXR->bases()) {
- if (I.isVirtual()) {
- // Ignore virtual bases; if we're laying out for a complete
- // object, we'll lay these out later.
- continue;
- }
-
- const CXXRecordDecl *base =
- cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
-
- // Ignore empty bases.
- if (base->isEmpty() ||
- CGM.getContext().getASTRecordLayout(base).getNonVirtualSize()
- .isZero())
- continue;
-
- unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base);
- llvm::Type *baseType = structure->getElementType(fieldIndex);
- elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
- }
- }
-
- // Fill in all the fields.
- for (const auto *Field : record->fields()) {
- // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
- // will fill in later.)
- if (!Field->isBitField()) {
- unsigned fieldIndex = layout.getLLVMFieldNo(Field);
- elements[fieldIndex] = CGM.EmitNullConstant(Field->getType());
- }
-
- // For unions, stop after the first named field.
- if (record->isUnion()) {
- if (Field->getIdentifier())
- break;
- if (const auto *FieldRD = Field->getType()->getAsRecordDecl())
- if (FieldRD->findFirstNamedDataMember())
- break;
- }
- }
-
- // Fill in the virtual bases, if we're working with the complete object.
- if (CXXR && asCompleteObject) {
- for (const auto &I : CXXR->vbases()) {
- const CXXRecordDecl *base =
- cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
-
- // Ignore empty bases.
- if (base->isEmpty())
- continue;
-
- unsigned fieldIndex = layout.getVirtualBaseIndex(base);
-
- // We might have already laid this field out.
- if (elements[fieldIndex]) continue;
-
- llvm::Type *baseType = structure->getElementType(fieldIndex);
- elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
- }
- }
-
- // Now go through all other fields and zero them out.
- for (unsigned i = 0; i != numElements; ++i) {
- if (!elements[i])
- elements[i] = llvm::Constant::getNullValue(structure->getElementType(i));
- }
-
- return llvm::ConstantStruct::get(structure, elements);
-}
-
-/// Emit the null constant for a base subobject.
-static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
- llvm::Type *baseType,
- const CXXRecordDecl *base) {
- const CGRecordLayout &baseLayout = CGM.getTypes().getCGRecordLayout(base);
-
- // Just zero out bases that don't have any pointer to data members.
- if (baseLayout.isZeroInitializableAsBase())
- return llvm::Constant::getNullValue(baseType);
-
- // Otherwise, we can just use its null constant.
- return EmitNullConstant(CGM, base, /*asCompleteObject=*/false);
-}
-
-llvm::Constant *ConstantEmitter::emitNullForMemory(CodeGenModule &CGM,
- QualType T) {
- return emitForMemory(CGM, CGM.EmitNullConstant(T), T);
-}
-
-llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
- if (T->getAs<PointerType>())
- return getNullPointer(
- cast<llvm::PointerType>(getTypes().ConvertTypeForMem(T)), T);
-
- if (getTypes().isZeroInitializable(T))
- return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
-
- if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
- llvm::ArrayType *ATy =
- cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
-
- QualType ElementTy = CAT->getElementType();
-
- llvm::Constant *Element =
- ConstantEmitter::emitNullForMemory(*this, ElementTy);
- unsigned NumElements = CAT->getSize().getZExtValue();
- SmallVector<llvm::Constant *, 8> Array(NumElements, Element);
- return llvm::ConstantArray::get(ATy, Array);
- }
-
- if (const RecordType *RT = T->getAs<RecordType>())
- return ::EmitNullConstant(*this, RT->getDecl(), /*complete object*/ true);
-
- assert(T->isMemberDataPointerType() &&
- "Should only see pointers to data members here!");
-
- return getCXXABI().EmitNullMemberPointer(T->castAs<MemberPointerType>());
-}
-
-llvm::Constant *
-CodeGenModule::EmitNullConstantForBase(const CXXRecordDecl *Record) {
- return ::EmitNullConstant(*this, Record, false);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp
deleted file mode 100644
index 1c14d4c99a2..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp
+++ /dev/null
@@ -1,4526 +0,0 @@
-//===--- CGExprScalar.cpp - Emit LLVM Code for Scalar Exprs ---------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Expr nodes with scalar LLVM types as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-#include "CGDebugInfo.h"
-#include "CGObjCRuntime.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/FixedPoint.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/IR/CFG.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/GetElementPtrTypeIterator.h"
-#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Module.h"
-#include <cstdarg>
-
-using namespace clang;
-using namespace CodeGen;
-using llvm::Value;
-
-//===----------------------------------------------------------------------===//
-// Scalar Expression Emitter
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-/// Determine whether the given binary operation may overflow.
-/// Sets \p Result to the value of the operation for BO_Add, BO_Sub, BO_Mul,
-/// and signed BO_{Div,Rem}. For these opcodes, and for unsigned BO_{Div,Rem},
-/// the returned overflow check is precise. The returned value is 'true' for
-/// all other opcodes, to be conservative.
-bool mayHaveIntegerOverflow(llvm::ConstantInt *LHS, llvm::ConstantInt *RHS,
- BinaryOperator::Opcode Opcode, bool Signed,
- llvm::APInt &Result) {
- // Assume overflow is possible, unless we can prove otherwise.
- bool Overflow = true;
- const auto &LHSAP = LHS->getValue();
- const auto &RHSAP = RHS->getValue();
- if (Opcode == BO_Add) {
- if (Signed)
- Result = LHSAP.sadd_ov(RHSAP, Overflow);
- else
- Result = LHSAP.uadd_ov(RHSAP, Overflow);
- } else if (Opcode == BO_Sub) {
- if (Signed)
- Result = LHSAP.ssub_ov(RHSAP, Overflow);
- else
- Result = LHSAP.usub_ov(RHSAP, Overflow);
- } else if (Opcode == BO_Mul) {
- if (Signed)
- Result = LHSAP.smul_ov(RHSAP, Overflow);
- else
- Result = LHSAP.umul_ov(RHSAP, Overflow);
- } else if (Opcode == BO_Div || Opcode == BO_Rem) {
- if (Signed && !RHS->isZero())
- Result = LHSAP.sdiv_ov(RHSAP, Overflow);
- else
- return false;
- }
- return Overflow;
-}
-
-struct BinOpInfo {
- Value *LHS;
- Value *RHS;
- QualType Ty; // Computation Type.
- BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
- FPOptions FPFeatures;
- const Expr *E; // Entire expr, for error unsupported. May not be binop.
-
- /// Check if the binop can result in integer overflow.
- bool mayHaveIntegerOverflow() const {
- // Without constant input, we can't rule out overflow.
- auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS);
- auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS);
- if (!LHSCI || !RHSCI)
- return true;
-
- llvm::APInt Result;
- return ::mayHaveIntegerOverflow(
- LHSCI, RHSCI, Opcode, Ty->hasSignedIntegerRepresentation(), Result);
- }
-
- /// Check if the binop computes a division or a remainder.
- bool isDivremOp() const {
- return Opcode == BO_Div || Opcode == BO_Rem || Opcode == BO_DivAssign ||
- Opcode == BO_RemAssign;
- }
-
- /// Check if the binop can result in an integer division by zero.
- bool mayHaveIntegerDivisionByZero() const {
- if (isDivremOp())
- if (auto *CI = dyn_cast<llvm::ConstantInt>(RHS))
- return CI->isZero();
- return true;
- }
-
- /// Check if the binop can result in a float division by zero.
- bool mayHaveFloatDivisionByZero() const {
- if (isDivremOp())
- if (auto *CFP = dyn_cast<llvm::ConstantFP>(RHS))
- return CFP->isZero();
- return true;
- }
-};
-
-static bool MustVisitNullValue(const Expr *E) {
- // If a null pointer expression's type is the C++0x nullptr_t, then
- // it's not necessarily a simple constant and it must be evaluated
- // for its potential side effects.
- return E->getType()->isNullPtrType();
-}
-
-/// If \p E is a widened promoted integer, get its base (unpromoted) type.
-static llvm::Optional<QualType> getUnwidenedIntegerType(const ASTContext &Ctx,
- const Expr *E) {
- const Expr *Base = E->IgnoreImpCasts();
- if (E == Base)
- return llvm::None;
-
- QualType BaseTy = Base->getType();
- if (!BaseTy->isPromotableIntegerType() ||
- Ctx.getTypeSize(BaseTy) >= Ctx.getTypeSize(E->getType()))
- return llvm::None;
-
- return BaseTy;
-}
-
-/// Check if \p E is a widened promoted integer.
-static bool IsWidenedIntegerOp(const ASTContext &Ctx, const Expr *E) {
- return getUnwidenedIntegerType(Ctx, E).hasValue();
-}
-
-/// Check if we can skip the overflow check for \p Op.
-static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
- assert((isa<UnaryOperator>(Op.E) || isa<BinaryOperator>(Op.E)) &&
- "Expected a unary or binary operator");
-
- // If the binop has constant inputs and we can prove there is no overflow,
- // we can elide the overflow check.
- if (!Op.mayHaveIntegerOverflow())
- return true;
-
- // If a unary op has a widened operand, the op cannot overflow.
- if (const auto *UO = dyn_cast<UnaryOperator>(Op.E))
- return !UO->canOverflow();
-
- // We usually don't need overflow checks for binops with widened operands.
- // Multiplication with promoted unsigned operands is a special case.
- const auto *BO = cast<BinaryOperator>(Op.E);
- auto OptionalLHSTy = getUnwidenedIntegerType(Ctx, BO->getLHS());
- if (!OptionalLHSTy)
- return false;
-
- auto OptionalRHSTy = getUnwidenedIntegerType(Ctx, BO->getRHS());
- if (!OptionalRHSTy)
- return false;
-
- QualType LHSTy = *OptionalLHSTy;
- QualType RHSTy = *OptionalRHSTy;
-
- // This is the simple case: binops without unsigned multiplication, and with
- // widened operands. No overflow check is needed here.
- if ((Op.Opcode != BO_Mul && Op.Opcode != BO_MulAssign) ||
- !LHSTy->isUnsignedIntegerType() || !RHSTy->isUnsignedIntegerType())
- return true;
-
- // For unsigned multiplication the overflow check can be elided if either one
- // of the unpromoted types are less than half the size of the promoted type.
- unsigned PromotedSize = Ctx.getTypeSize(Op.E->getType());
- return (2 * Ctx.getTypeSize(LHSTy)) < PromotedSize ||
- (2 * Ctx.getTypeSize(RHSTy)) < PromotedSize;
-}
-
-/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
-static void updateFastMathFlags(llvm::FastMathFlags &FMF,
- FPOptions FPFeatures) {
- FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement());
-}
-
-/// Propagate fast-math flags from \p Op to the instruction in \p V.
-static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) {
- if (auto *I = dyn_cast<llvm::Instruction>(V)) {
- llvm::FastMathFlags FMF = I->getFastMathFlags();
- updateFastMathFlags(FMF, Op.FPFeatures);
- I->setFastMathFlags(FMF);
- }
- return V;
-}
-
-class ScalarExprEmitter
- : public StmtVisitor<ScalarExprEmitter, Value*> {
- CodeGenFunction &CGF;
- CGBuilderTy &Builder;
- bool IgnoreResultAssign;
- llvm::LLVMContext &VMContext;
-public:
-
- ScalarExprEmitter(CodeGenFunction &cgf, bool ira=false)
- : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira),
- VMContext(cgf.getLLVMContext()) {
- }
-
- //===--------------------------------------------------------------------===//
- // Utilities
- //===--------------------------------------------------------------------===//
-
- bool TestAndClearIgnoreResultAssign() {
- bool I = IgnoreResultAssign;
- IgnoreResultAssign = false;
- return I;
- }
-
- llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
- LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
- LValue EmitCheckedLValue(const Expr *E, CodeGenFunction::TypeCheckKind TCK) {
- return CGF.EmitCheckedLValue(E, TCK);
- }
-
- void EmitBinOpCheck(ArrayRef<std::pair<Value *, SanitizerMask>> Checks,
- const BinOpInfo &Info);
-
- Value *EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
- return CGF.EmitLoadOfLValue(LV, Loc).getScalarVal();
- }
-
- void EmitLValueAlignmentAssumption(const Expr *E, Value *V) {
- const AlignValueAttr *AVAttr = nullptr;
- if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
- const ValueDecl *VD = DRE->getDecl();
-
- if (VD->getType()->isReferenceType()) {
- if (const auto *TTy =
- dyn_cast<TypedefType>(VD->getType().getNonReferenceType()))
- AVAttr = TTy->getDecl()->getAttr<AlignValueAttr>();
- } else {
- // Assumptions for function parameters are emitted at the start of the
- // function, so there is no need to repeat that here,
- // unless the alignment-assumption sanitizer is enabled,
- // then we prefer the assumption over alignment attribute
- // on IR function param.
- if (isa<ParmVarDecl>(VD) && !CGF.SanOpts.has(SanitizerKind::Alignment))
- return;
-
- AVAttr = VD->getAttr<AlignValueAttr>();
- }
- }
-
- if (!AVAttr)
- if (const auto *TTy =
- dyn_cast<TypedefType>(E->getType()))
- AVAttr = TTy->getDecl()->getAttr<AlignValueAttr>();
-
- if (!AVAttr)
- return;
-
- Value *AlignmentValue = CGF.EmitScalarExpr(AVAttr->getAlignment());
- llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(AlignmentValue);
- CGF.EmitAlignmentAssumption(V, E, AVAttr->getLocation(),
- AlignmentCI->getZExtValue());
- }
-
- /// EmitLoadOfLValue - Given an expression with complex type that represents a
- /// value l-value, this method emits the address of the l-value, then loads
- /// and returns the result.
- Value *EmitLoadOfLValue(const Expr *E) {
- Value *V = EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load),
- E->getExprLoc());
-
- EmitLValueAlignmentAssumption(E, V);
- return V;
- }
-
- /// EmitConversionToBool - Convert the specified expression value to a
- /// boolean (i1) truth value. This is equivalent to "Val != 0".
- Value *EmitConversionToBool(Value *Src, QualType DstTy);
-
- /// Emit a check that a conversion to or from a floating-point type does not
- /// overflow.
- void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType,
- Value *Src, QualType SrcType, QualType DstType,
- llvm::Type *DstTy, SourceLocation Loc);
-
- /// Known implicit conversion check kinds.
- /// Keep in sync with the enum of the same name in ubsan_handlers.h
- enum ImplicitConversionCheckKind : unsigned char {
- ICCK_IntegerTruncation = 0, // Legacy, was only used by clang 7.
- ICCK_UnsignedIntegerTruncation = 1,
- ICCK_SignedIntegerTruncation = 2,
- ICCK_IntegerSignChange = 3,
- ICCK_SignedIntegerTruncationOrSignChange = 4,
- };
-
- /// Emit a check that an [implicit] truncation of an integer does not
- /// discard any bits. It is not UB, so we use the value after truncation.
- void EmitIntegerTruncationCheck(Value *Src, QualType SrcType, Value *Dst,
- QualType DstType, SourceLocation Loc);
-
- /// Emit a check that an [implicit] conversion of an integer does not change
- /// the sign of the value. It is not UB, so we use the value after conversion.
- /// NOTE: Src and Dst may be the exact same value! (point to the same thing)
- void EmitIntegerSignChangeCheck(Value *Src, QualType SrcType, Value *Dst,
- QualType DstType, SourceLocation Loc);
-
- /// Emit a conversion from the specified type to the specified destination
- /// type, both of which are LLVM scalar types.
- struct ScalarConversionOpts {
- bool TreatBooleanAsSigned;
- bool EmitImplicitIntegerTruncationChecks;
- bool EmitImplicitIntegerSignChangeChecks;
-
- ScalarConversionOpts()
- : TreatBooleanAsSigned(false),
- EmitImplicitIntegerTruncationChecks(false),
- EmitImplicitIntegerSignChangeChecks(false) {}
-
- ScalarConversionOpts(clang::SanitizerSet SanOpts)
- : TreatBooleanAsSigned(false),
- EmitImplicitIntegerTruncationChecks(
- SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),
- EmitImplicitIntegerSignChangeChecks(
- SanOpts.has(SanitizerKind::ImplicitIntegerSignChange)) {}
- };
- Value *
- EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy,
- SourceLocation Loc,
- ScalarConversionOpts Opts = ScalarConversionOpts());
-
- Value *EmitFixedPointConversion(Value *Src, QualType SrcTy, QualType DstTy,
- SourceLocation Loc);
-
- /// Emit a conversion from the specified complex type to the specified
- /// destination type, where the destination type is an LLVM scalar type.
- Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
- QualType SrcTy, QualType DstTy,
- SourceLocation Loc);
-
- /// EmitNullValue - Emit a value that corresponds to null for the given type.
- Value *EmitNullValue(QualType Ty);
-
- /// EmitFloatToBoolConversion - Perform an FP to boolean conversion.
- Value *EmitFloatToBoolConversion(Value *V) {
- // Compare against 0.0 for fp scalars.
- llvm::Value *Zero = llvm::Constant::getNullValue(V->getType());
- return Builder.CreateFCmpUNE(V, Zero, "tobool");
- }
-
- /// EmitPointerToBoolConversion - Perform a pointer to boolean conversion.
- Value *EmitPointerToBoolConversion(Value *V, QualType QT) {
- Value *Zero = CGF.CGM.getNullPointer(cast<llvm::PointerType>(V->getType()), QT);
-
- return Builder.CreateICmpNE(V, Zero, "tobool");
- }
-
- Value *EmitIntToBoolConversion(Value *V) {
- // Because of the type rules of C, we often end up computing a
- // logical value, then zero extending it to int, then wanting it
- // as a logical value again. Optimize this common case.
- if (llvm::ZExtInst *ZI = dyn_cast<llvm::ZExtInst>(V)) {
- if (ZI->getOperand(0)->getType() == Builder.getInt1Ty()) {
- Value *Result = ZI->getOperand(0);
- // If there aren't any more uses, zap the instruction to save space.
- // Note that there can be more uses, for example if this
- // is the result of an assignment.
- if (ZI->use_empty())
- ZI->eraseFromParent();
- return Result;
- }
- }
-
- return Builder.CreateIsNotNull(V, "tobool");
- }
-
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- Value *Visit(Expr *E) {
- ApplyDebugLocation DL(CGF, E);
- return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
- }
-
- Value *VisitStmt(Stmt *S) {
- S->dump(CGF.getContext().getSourceManager());
- llvm_unreachable("Stmt can't have complex result type!");
- }
- Value *VisitExpr(Expr *S);
-
- Value *VisitConstantExpr(ConstantExpr *E) {
- return Visit(E->getSubExpr());
- }
- Value *VisitParenExpr(ParenExpr *PE) {
- return Visit(PE->getSubExpr());
- }
- Value *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
- return Visit(E->getReplacement());
- }
- Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
- return Visit(GE->getResultExpr());
- }
- Value *VisitCoawaitExpr(CoawaitExpr *S) {
- return CGF.EmitCoawaitExpr(*S).getScalarVal();
- }
- Value *VisitCoyieldExpr(CoyieldExpr *S) {
- return CGF.EmitCoyieldExpr(*S).getScalarVal();
- }
- Value *VisitUnaryCoawait(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
-
- // Leaves.
- Value *VisitIntegerLiteral(const IntegerLiteral *E) {
- return Builder.getInt(E->getValue());
- }
- Value *VisitFixedPointLiteral(const FixedPointLiteral *E) {
- return Builder.getInt(E->getValue());
- }
- Value *VisitFloatingLiteral(const FloatingLiteral *E) {
- return llvm::ConstantFP::get(VMContext, E->getValue());
- }
- Value *VisitCharacterLiteral(const CharacterLiteral *E) {
- return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
- }
- Value *VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) {
- return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
- }
- Value *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
- return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
- }
- Value *VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
- return EmitNullValue(E->getType());
- }
- Value *VisitGNUNullExpr(const GNUNullExpr *E) {
- return EmitNullValue(E->getType());
- }
- Value *VisitOffsetOfExpr(OffsetOfExpr *E);
- Value *VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
- Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
- llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel());
- return Builder.CreateBitCast(V, ConvertType(E->getType()));
- }
-
- Value *VisitSizeOfPackExpr(SizeOfPackExpr *E) {
- return llvm::ConstantInt::get(ConvertType(E->getType()),E->getPackLength());
- }
-
- Value *VisitPseudoObjectExpr(PseudoObjectExpr *E) {
- return CGF.EmitPseudoObjectRValue(E).getScalarVal();
- }
-
- Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
- if (E->isGLValue())
- return EmitLoadOfLValue(CGF.getOrCreateOpaqueLValueMapping(E),
- E->getExprLoc());
-
- // Otherwise, assume the mapping is the scalar directly.
- return CGF.getOrCreateOpaqueRValueMapping(E).getScalarVal();
- }
-
- // l-values.
- Value *VisitDeclRefExpr(DeclRefExpr *E) {
- if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E))
- return CGF.emitScalarConstant(Constant, E);
- return EmitLoadOfLValue(E);
- }
-
- Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
- return CGF.EmitObjCSelectorExpr(E);
- }
- Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
- return CGF.EmitObjCProtocolExpr(E);
- }
- Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
- return EmitLoadOfLValue(E);
- }
- Value *VisitObjCMessageExpr(ObjCMessageExpr *E) {
- if (E->getMethodDecl() &&
- E->getMethodDecl()->getReturnType()->isReferenceType())
- return EmitLoadOfLValue(E);
- return CGF.EmitObjCMessageExpr(E).getScalarVal();
- }
-
- Value *VisitObjCIsaExpr(ObjCIsaExpr *E) {
- LValue LV = CGF.EmitObjCIsaExpr(E);
- Value *V = CGF.EmitLoadOfLValue(LV, E->getExprLoc()).getScalarVal();
- return V;
- }
-
- Value *VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
- VersionTuple Version = E->getVersion();
-
- // If we're checking for a platform older than our minimum deployment
- // target, we can fold the check away.
- if (Version <= CGF.CGM.getTarget().getPlatformMinVersion())
- return llvm::ConstantInt::get(Builder.getInt1Ty(), 1);
-
- Optional<unsigned> Min = Version.getMinor(), SMin = Version.getSubminor();
- llvm::Value *Args[] = {
- llvm::ConstantInt::get(CGF.CGM.Int32Ty, Version.getMajor()),
- llvm::ConstantInt::get(CGF.CGM.Int32Ty, Min ? *Min : 0),
- llvm::ConstantInt::get(CGF.CGM.Int32Ty, SMin ? *SMin : 0),
- };
-
- return CGF.EmitBuiltinAvailable(Args);
- }
-
- Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
- Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
- Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
- Value *VisitMemberExpr(MemberExpr *E);
- Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
- Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- return EmitLoadOfLValue(E);
- }
-
- Value *VisitInitListExpr(InitListExpr *E);
-
- Value *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) {
- assert(CGF.getArrayInitIndex() &&
- "ArrayInitIndexExpr not inside an ArrayInitLoopExpr?");
- return CGF.getArrayInitIndex();
- }
-
- Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
- return EmitNullValue(E->getType());
- }
- Value *VisitExplicitCastExpr(ExplicitCastExpr *E) {
- CGF.CGM.EmitExplicitCastExprType(E, &CGF);
- return VisitCastExpr(E);
- }
- Value *VisitCastExpr(CastExpr *E);
-
- Value *VisitCallExpr(const CallExpr *E) {
- if (E->getCallReturnType(CGF.getContext())->isReferenceType())
- return EmitLoadOfLValue(E);
-
- Value *V = CGF.EmitCallExpr(E).getScalarVal();
-
- EmitLValueAlignmentAssumption(E, V);
- return V;
- }
-
- Value *VisitStmtExpr(const StmtExpr *E);
-
- // Unary Operators.
- Value *VisitUnaryPostDec(const UnaryOperator *E) {
- LValue LV = EmitLValue(E->getSubExpr());
- return EmitScalarPrePostIncDec(E, LV, false, false);
- }
- Value *VisitUnaryPostInc(const UnaryOperator *E) {
- LValue LV = EmitLValue(E->getSubExpr());
- return EmitScalarPrePostIncDec(E, LV, true, false);
- }
- Value *VisitUnaryPreDec(const UnaryOperator *E) {
- LValue LV = EmitLValue(E->getSubExpr());
- return EmitScalarPrePostIncDec(E, LV, false, true);
- }
- Value *VisitUnaryPreInc(const UnaryOperator *E) {
- LValue LV = EmitLValue(E->getSubExpr());
- return EmitScalarPrePostIncDec(E, LV, true, true);
- }
-
- llvm::Value *EmitIncDecConsiderOverflowBehavior(const UnaryOperator *E,
- llvm::Value *InVal,
- bool IsInc);
-
- llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
- bool isInc, bool isPre);
-
-
- Value *VisitUnaryAddrOf(const UnaryOperator *E) {
- if (isa<MemberPointerType>(E->getType())) // never sugared
- return CGF.CGM.getMemberPointerConstant(E);
-
- return EmitLValue(E->getSubExpr()).getPointer();
- }
- Value *VisitUnaryDeref(const UnaryOperator *E) {
- if (E->getType()->isVoidType())
- return Visit(E->getSubExpr()); // the actual value should be unused
- return EmitLoadOfLValue(E);
- }
- Value *VisitUnaryPlus(const UnaryOperator *E) {
- // This differs from gcc, though, most likely due to a bug in gcc.
- TestAndClearIgnoreResultAssign();
- return Visit(E->getSubExpr());
- }
- Value *VisitUnaryMinus (const UnaryOperator *E);
- Value *VisitUnaryNot (const UnaryOperator *E);
- Value *VisitUnaryLNot (const UnaryOperator *E);
- Value *VisitUnaryReal (const UnaryOperator *E);
- Value *VisitUnaryImag (const UnaryOperator *E);
- Value *VisitUnaryExtension(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
-
- // C++
- Value *VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E) {
- return EmitLoadOfLValue(E);
- }
-
- Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
- return Visit(DAE->getExpr());
- }
- Value *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
- CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
- return Visit(DIE->getExpr());
- }
- Value *VisitCXXThisExpr(CXXThisExpr *TE) {
- return CGF.LoadCXXThis();
- }
-
- Value *VisitExprWithCleanups(ExprWithCleanups *E);
- Value *VisitCXXNewExpr(const CXXNewExpr *E) {
- return CGF.EmitCXXNewExpr(E);
- }
- Value *VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
- CGF.EmitCXXDeleteExpr(E);
- return nullptr;
- }
-
- Value *VisitTypeTraitExpr(const TypeTraitExpr *E) {
- return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
- }
-
- Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
- return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue());
- }
-
- Value *VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
- return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue());
- }
-
- Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) {
- // C++ [expr.pseudo]p1:
- // The result shall only be used as the operand for the function call
- // operator (), and the result of such a call has type void. The only
- // effect is the evaluation of the postfix-expression before the dot or
- // arrow.
- CGF.EmitScalarExpr(E->getBase());
- return nullptr;
- }
-
- Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
- return EmitNullValue(E->getType());
- }
-
- Value *VisitCXXThrowExpr(const CXXThrowExpr *E) {
- CGF.EmitCXXThrowExpr(E);
- return nullptr;
- }
-
- Value *VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
- return Builder.getInt1(E->getValue());
- }
-
- // Binary Operators.
- Value *EmitMul(const BinOpInfo &Ops) {
- if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Defined:
- return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
- case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
- return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
- LLVM_FALLTHROUGH;
- case LangOptions::SOB_Trapping:
- if (CanElideOverflowCheck(CGF.getContext(), Ops))
- return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
- return EmitOverflowCheckedBinOp(Ops);
- }
- }
-
- if (Ops.Ty->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
- !CanElideOverflowCheck(CGF.getContext(), Ops))
- return EmitOverflowCheckedBinOp(Ops);
-
- if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
- Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
- return propagateFMFlags(V, Ops);
- }
- return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
- }
- /// Create a binary op that checks for overflow.
- /// Currently only supports +, - and *.
- Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops);
-
- // Check for undefined division and modulus behaviors.
- void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
- llvm::Value *Zero,bool isDiv);
- // Common helper for getting how wide LHS of shift is.
- static Value *GetWidthMinusOneValue(Value* LHS,Value* RHS);
- Value *EmitDiv(const BinOpInfo &Ops);
- Value *EmitRem(const BinOpInfo &Ops);
- Value *EmitAdd(const BinOpInfo &Ops);
- Value *EmitSub(const BinOpInfo &Ops);
- Value *EmitShl(const BinOpInfo &Ops);
- Value *EmitShr(const BinOpInfo &Ops);
- Value *EmitAnd(const BinOpInfo &Ops) {
- return Builder.CreateAnd(Ops.LHS, Ops.RHS, "and");
- }
- Value *EmitXor(const BinOpInfo &Ops) {
- return Builder.CreateXor(Ops.LHS, Ops.RHS, "xor");
- }
- Value *EmitOr (const BinOpInfo &Ops) {
- return Builder.CreateOr(Ops.LHS, Ops.RHS, "or");
- }
-
- BinOpInfo EmitBinOps(const BinaryOperator *E);
- LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
- Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
- Value *&Result);
-
- Value *EmitCompoundAssign(const CompoundAssignOperator *E,
- Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
-
- // Binary operators and binary compound assignment operators.
-#define HANDLEBINOP(OP) \
- Value *VisitBin ## OP(const BinaryOperator *E) { \
- return Emit ## OP(EmitBinOps(E)); \
- } \
- Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \
- return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \
- }
- HANDLEBINOP(Mul)
- HANDLEBINOP(Div)
- HANDLEBINOP(Rem)
- HANDLEBINOP(Add)
- HANDLEBINOP(Sub)
- HANDLEBINOP(Shl)
- HANDLEBINOP(Shr)
- HANDLEBINOP(And)
- HANDLEBINOP(Xor)
- HANDLEBINOP(Or)
-#undef HANDLEBINOP
-
- // Comparisons.
- Value *EmitCompare(const BinaryOperator *E, llvm::CmpInst::Predicate UICmpOpc,
- llvm::CmpInst::Predicate SICmpOpc,
- llvm::CmpInst::Predicate FCmpOpc);
-#define VISITCOMP(CODE, UI, SI, FP) \
- Value *VisitBin##CODE(const BinaryOperator *E) { \
- return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \
- llvm::FCmpInst::FP); }
- VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT)
- VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT)
- VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE)
- VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE)
- VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ)
- VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE)
-#undef VISITCOMP
-
- Value *VisitBinAssign (const BinaryOperator *E);
-
- Value *VisitBinLAnd (const BinaryOperator *E);
- Value *VisitBinLOr (const BinaryOperator *E);
- Value *VisitBinComma (const BinaryOperator *E);
-
- Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); }
- Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); }
-
- // Other Operators.
- Value *VisitBlockExpr(const BlockExpr *BE);
- Value *VisitAbstractConditionalOperator(const AbstractConditionalOperator *);
- Value *VisitChooseExpr(ChooseExpr *CE);
- Value *VisitVAArgExpr(VAArgExpr *VE);
- Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
- return CGF.EmitObjCStringLiteral(E);
- }
- Value *VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
- return CGF.EmitObjCBoxedExpr(E);
- }
- Value *VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
- return CGF.EmitObjCArrayLiteral(E);
- }
- Value *VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
- return CGF.EmitObjCDictionaryLiteral(E);
- }
- Value *VisitAsTypeExpr(AsTypeExpr *CE);
- Value *VisitAtomicExpr(AtomicExpr *AE);
-};
-} // end anonymous namespace.
-
-//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-/// EmitConversionToBool - Convert the specified expression value to a
-/// boolean (i1) truth value. This is equivalent to "Val != 0".
-Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
- assert(SrcType.isCanonical() && "EmitScalarConversion strips typedefs");
-
- if (SrcType->isRealFloatingType())
- return EmitFloatToBoolConversion(Src);
-
- if (const MemberPointerType *MPT = dyn_cast<MemberPointerType>(SrcType))
- return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, Src, MPT);
-
- assert((SrcType->isIntegerType() || isa<llvm::PointerType>(Src->getType())) &&
- "Unknown scalar type to convert");
-
- if (isa<llvm::IntegerType>(Src->getType()))
- return EmitIntToBoolConversion(Src);
-
- assert(isa<llvm::PointerType>(Src->getType()));
- return EmitPointerToBoolConversion(Src, SrcType);
-}
-
-void ScalarExprEmitter::EmitFloatConversionCheck(
- Value *OrigSrc, QualType OrigSrcType, Value *Src, QualType SrcType,
- QualType DstType, llvm::Type *DstTy, SourceLocation Loc) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
- using llvm::APFloat;
- using llvm::APSInt;
-
- llvm::Type *SrcTy = Src->getType();
-
- llvm::Value *Check = nullptr;
- if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) {
- // Integer to floating-point. This can fail for unsigned short -> __half
- // or unsigned __int128 -> float.
- assert(DstType->isFloatingType());
- bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType();
-
- APFloat LargestFloat =
- APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType));
- APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned);
-
- bool IsExact;
- if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero,
- &IsExact) != APFloat::opOK)
- // The range of representable values of this floating point type includes
- // all values of this integer type. Don't need an overflow check.
- return;
-
- llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt);
- if (SrcIsUnsigned)
- Check = Builder.CreateICmpULE(Src, Max);
- else {
- llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt);
- llvm::Value *GE = Builder.CreateICmpSGE(Src, Min);
- llvm::Value *LE = Builder.CreateICmpSLE(Src, Max);
- Check = Builder.CreateAnd(GE, LE);
- }
- } else {
- const llvm::fltSemantics &SrcSema =
- CGF.getContext().getFloatTypeSemantics(OrigSrcType);
- if (isa<llvm::IntegerType>(DstTy)) {
- // Floating-point to integer. This has undefined behavior if the source is
- // +-Inf, NaN, or doesn't fit into the destination type (after truncation
- // to an integer).
- unsigned Width = CGF.getContext().getIntWidth(DstType);
- bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
-
- APSInt Min = APSInt::getMinValue(Width, Unsigned);
- APFloat MinSrc(SrcSema, APFloat::uninitialized);
- if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
- APFloat::opOverflow)
- // Don't need an overflow check for lower bound. Just check for
- // -Inf/NaN.
- MinSrc = APFloat::getInf(SrcSema, true);
- else
- // Find the largest value which is too small to represent (before
- // truncation toward zero).
- MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
-
- APSInt Max = APSInt::getMaxValue(Width, Unsigned);
- APFloat MaxSrc(SrcSema, APFloat::uninitialized);
- if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
- APFloat::opOverflow)
- // Don't need an overflow check for upper bound. Just check for
- // +Inf/NaN.
- MaxSrc = APFloat::getInf(SrcSema, false);
- else
- // Find the smallest value which is too large to represent (before
- // truncation toward zero).
- MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive);
-
- // If we're converting from __half, convert the range to float to match
- // the type of src.
- if (OrigSrcType->isHalfType()) {
- const llvm::fltSemantics &Sema =
- CGF.getContext().getFloatTypeSemantics(SrcType);
- bool IsInexact;
- MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
- MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
- }
-
- llvm::Value *GE =
- Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc));
- llvm::Value *LE =
- Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
- Check = Builder.CreateAnd(GE, LE);
- } else {
- // FIXME: Maybe split this sanitizer out from float-cast-overflow.
- //
- // Floating-point to floating-point. This has undefined behavior if the
- // source is not in the range of representable values of the destination
- // type. The C and C++ standards are spectacularly unclear here. We
- // diagnose finite out-of-range conversions, but allow infinities and NaNs
- // to convert to the corresponding value in the smaller type.
- //
- // C11 Annex F gives all such conversions defined behavior for IEC 60559
- // conforming implementations. Unfortunately, LLVM's fptrunc instruction
- // does not.
-
- // Converting from a lower rank to a higher rank can never have
- // undefined behavior, since higher-rank types must have a superset
- // of values of lower-rank types.
- if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1)
- return;
-
- assert(!OrigSrcType->isHalfType() &&
- "should not check conversion from __half, it has the lowest rank");
-
- const llvm::fltSemantics &DstSema =
- CGF.getContext().getFloatTypeSemantics(DstType);
- APFloat MinBad = APFloat::getLargest(DstSema, false);
- APFloat MaxBad = APFloat::getInf(DstSema, false);
-
- bool IsInexact;
- MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
- MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
-
- Value *AbsSrc = CGF.EmitNounwindRuntimeCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src);
- llvm::Value *GE =
- Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad));
- llvm::Value *LE =
- Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad));
- Check = Builder.CreateNot(Builder.CreateAnd(GE, LE));
- }
- }
-
- llvm::Constant *StaticArgs[] = {CGF.EmitCheckSourceLocation(Loc),
- CGF.EmitCheckTypeDescriptor(OrigSrcType),
- CGF.EmitCheckTypeDescriptor(DstType)};
- CGF.EmitCheck(std::make_pair(Check, SanitizerKind::FloatCastOverflow),
- SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc);
-}
-
-// Should be called within CodeGenFunction::SanitizerScope RAII scope.
-// Returns 'i1 false' when the truncation Src -> Dst was lossy.
-static std::pair<ScalarExprEmitter::ImplicitConversionCheckKind,
- std::pair<llvm::Value *, SanitizerMask>>
-EmitIntegerTruncationCheckHelper(Value *Src, QualType SrcType, Value *Dst,
- QualType DstType, CGBuilderTy &Builder) {
- llvm::Type *SrcTy = Src->getType();
- llvm::Type *DstTy = Dst->getType();
- (void)DstTy; // Only used in assert()
-
- // This should be truncation of integral types.
- assert(Src != Dst);
- assert(SrcTy->getScalarSizeInBits() > Dst->getType()->getScalarSizeInBits());
- assert(isa<llvm::IntegerType>(SrcTy) && isa<llvm::IntegerType>(DstTy) &&
- "non-integer llvm type");
-
- bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType();
- bool DstSigned = DstType->isSignedIntegerOrEnumerationType();
-
- // If both (src and dst) types are unsigned, then it's an unsigned truncation.
- // Else, it is a signed truncation.
- ScalarExprEmitter::ImplicitConversionCheckKind Kind;
- SanitizerMask Mask;
- if (!SrcSigned && !DstSigned) {
- Kind = ScalarExprEmitter::ICCK_UnsignedIntegerTruncation;
- Mask = SanitizerKind::ImplicitUnsignedIntegerTruncation;
- } else {
- Kind = ScalarExprEmitter::ICCK_SignedIntegerTruncation;
- Mask = SanitizerKind::ImplicitSignedIntegerTruncation;
- }
-
- llvm::Value *Check = nullptr;
- // 1. Extend the truncated value back to the same width as the Src.
- Check = Builder.CreateIntCast(Dst, SrcTy, DstSigned, "anyext");
- // 2. Equality-compare with the original source value
- Check = Builder.CreateICmpEQ(Check, Src, "truncheck");
- // If the comparison result is 'i1 false', then the truncation was lossy.
- return std::make_pair(Kind, std::make_pair(Check, Mask));
-}
-
-void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
- Value *Dst, QualType DstType,
- SourceLocation Loc) {
- if (!CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation))
- return;
-
- // We only care about int->int conversions here.
- // We ignore conversions to/from pointer and/or bool.
- if (!(SrcType->isIntegerType() && DstType->isIntegerType()))
- return;
-
- unsigned SrcBits = Src->getType()->getScalarSizeInBits();
- unsigned DstBits = Dst->getType()->getScalarSizeInBits();
- // This must be truncation. Else we do not care.
- if (SrcBits <= DstBits)
- return;
-
- assert(!DstType->isBooleanType() && "we should not get here with booleans.");
-
- // If the integer sign change sanitizer is enabled,
- // and we are truncating from larger unsigned type to smaller signed type,
- // let that next sanitizer deal with it.
- bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType();
- bool DstSigned = DstType->isSignedIntegerOrEnumerationType();
- if (CGF.SanOpts.has(SanitizerKind::ImplicitIntegerSignChange) &&
- (!SrcSigned && DstSigned))
- return;
-
- CodeGenFunction::SanitizerScope SanScope(&CGF);
-
- std::pair<ScalarExprEmitter::ImplicitConversionCheckKind,
- std::pair<llvm::Value *, SanitizerMask>>
- Check =
- EmitIntegerTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder);
- // If the comparison result is 'i1 false', then the truncation was lossy.
-
- // Do we care about this type of truncation?
- if (!CGF.SanOpts.has(Check.second.second))
- return;
-
- llvm::Constant *StaticArgs[] = {
- CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType),
- CGF.EmitCheckTypeDescriptor(DstType),
- llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first)};
- CGF.EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs,
- {Src, Dst});
-}
-
-// Should be called within CodeGenFunction::SanitizerScope RAII scope.
-// Returns 'i1 false' when the conversion Src -> Dst changed the sign.
-static std::pair<ScalarExprEmitter::ImplicitConversionCheckKind,
- std::pair<llvm::Value *, SanitizerMask>>
-EmitIntegerSignChangeCheckHelper(Value *Src, QualType SrcType, Value *Dst,
- QualType DstType, CGBuilderTy &Builder) {
- llvm::Type *SrcTy = Src->getType();
- llvm::Type *DstTy = Dst->getType();
-
- assert(isa<llvm::IntegerType>(SrcTy) && isa<llvm::IntegerType>(DstTy) &&
- "non-integer llvm type");
-
- bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType();
- bool DstSigned = DstType->isSignedIntegerOrEnumerationType();
- (void)SrcSigned; // Only used in assert()
- (void)DstSigned; // Only used in assert()
- unsigned SrcBits = SrcTy->getScalarSizeInBits();
- unsigned DstBits = DstTy->getScalarSizeInBits();
- (void)SrcBits; // Only used in assert()
- (void)DstBits; // Only used in assert()
-
- assert(((SrcBits != DstBits) || (SrcSigned != DstSigned)) &&
- "either the widths should be different, or the signednesses.");
-
- // NOTE: zero value is considered to be non-negative.
- auto EmitIsNegativeTest = [&Builder](Value *V, QualType VType,
- const char *Name) -> Value * {
- // Is this value a signed type?
- bool VSigned = VType->isSignedIntegerOrEnumerationType();
- llvm::Type *VTy = V->getType();
- if (!VSigned) {
- // If the value is unsigned, then it is never negative.
- // FIXME: can we encounter non-scalar VTy here?
- return llvm::ConstantInt::getFalse(VTy->getContext());
- }
- // Get the zero of the same type with which we will be comparing.
- llvm::Constant *Zero = llvm::ConstantInt::get(VTy, 0);
- // %V.isnegative = icmp slt %V, 0
- // I.e is %V *strictly* less than zero, does it have negative value?
- return Builder.CreateICmp(llvm::ICmpInst::ICMP_SLT, V, Zero,
- llvm::Twine(Name) + "." + V->getName() +
- ".negativitycheck");
- };
-
- // 1. Was the old Value negative?
- llvm::Value *SrcIsNegative = EmitIsNegativeTest(Src, SrcType, "src");
- // 2. Is the new Value negative?
- llvm::Value *DstIsNegative = EmitIsNegativeTest(Dst, DstType, "dst");
- // 3. Now, was the 'negativity status' preserved during the conversion?
- // NOTE: conversion from negative to zero is considered to change the sign.
- // (We want to get 'false' when the conversion changed the sign)
- // So we should just equality-compare the negativity statuses.
- llvm::Value *Check = nullptr;
- Check = Builder.CreateICmpEQ(SrcIsNegative, DstIsNegative, "signchangecheck");
- // If the comparison result is 'false', then the conversion changed the sign.
- return std::make_pair(
- ScalarExprEmitter::ICCK_IntegerSignChange,
- std::make_pair(Check, SanitizerKind::ImplicitIntegerSignChange));
-}
-
-void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType,
- Value *Dst, QualType DstType,
- SourceLocation Loc) {
- if (!CGF.SanOpts.has(SanitizerKind::ImplicitIntegerSignChange))
- return;
-
- llvm::Type *SrcTy = Src->getType();
- llvm::Type *DstTy = Dst->getType();
-
- // We only care about int->int conversions here.
- // We ignore conversions to/from pointer and/or bool.
- if (!(SrcType->isIntegerType() && DstType->isIntegerType()))
- return;
-
- bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType();
- bool DstSigned = DstType->isSignedIntegerOrEnumerationType();
- unsigned SrcBits = SrcTy->getScalarSizeInBits();
- unsigned DstBits = DstTy->getScalarSizeInBits();
-
- // Now, we do not need to emit the check in *all* of the cases.
- // We can avoid emitting it in some obvious cases where it would have been
- // dropped by the opt passes (instcombine) always anyways.
- // If it's a cast between effectively the same type, no check.
- // NOTE: this is *not* equivalent to checking the canonical types.
- if (SrcSigned == DstSigned && SrcBits == DstBits)
- return;
- // At least one of the values needs to have signed type.
- // If both are unsigned, then obviously, neither of them can be negative.
- if (!SrcSigned && !DstSigned)
- return;
- // If the conversion is to *larger* *signed* type, then no check is needed.
- // Because either sign-extension happens (so the sign will remain),
- // or zero-extension will happen (the sign bit will be zero.)
- if ((DstBits > SrcBits) && DstSigned)
- return;
- if (CGF.SanOpts.has(SanitizerKind::ImplicitSignedIntegerTruncation) &&
- (SrcBits > DstBits) && SrcSigned) {
- // If the signed integer truncation sanitizer is enabled,
- // and this is a truncation from signed type, then no check is needed.
- // Because here sign change check is interchangeable with truncation check.
- return;
- }
- // That's it. We can't rule out any more cases with the data we have.
-
- CodeGenFunction::SanitizerScope SanScope(&CGF);
-
- std::pair<ScalarExprEmitter::ImplicitConversionCheckKind,
- std::pair<llvm::Value *, SanitizerMask>>
- Check;
-
- // Each of these checks needs to return 'false' when an issue was detected.
- ImplicitConversionCheckKind CheckKind;
- llvm::SmallVector<std::pair<llvm::Value *, SanitizerMask>, 2> Checks;
- // So we can 'and' all the checks together, and still get 'false',
- // if at least one of the checks detected an issue.
-
- Check = EmitIntegerSignChangeCheckHelper(Src, SrcType, Dst, DstType, Builder);
- CheckKind = Check.first;
- Checks.emplace_back(Check.second);
-
- if (CGF.SanOpts.has(SanitizerKind::ImplicitSignedIntegerTruncation) &&
- (SrcBits > DstBits) && !SrcSigned && DstSigned) {
- // If the signed integer truncation sanitizer was enabled,
- // and we are truncating from larger unsigned type to smaller signed type,
- // let's handle the case we skipped in that check.
- Check =
- EmitIntegerTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder);
- CheckKind = ICCK_SignedIntegerTruncationOrSignChange;
- Checks.emplace_back(Check.second);
- // If the comparison result is 'i1 false', then the truncation was lossy.
- }
-
- llvm::Constant *StaticArgs[] = {
- CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType),
- CGF.EmitCheckTypeDescriptor(DstType),
- llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind)};
- // EmitCheck() will 'and' all the checks together.
- CGF.EmitCheck(Checks, SanitizerHandler::ImplicitConversion, StaticArgs,
- {Src, Dst});
-}
-
-/// Emit a conversion from the specified type to the specified destination type,
-/// both of which are LLVM scalar types.
-Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
- QualType DstType,
- SourceLocation Loc,
- ScalarConversionOpts Opts) {
- // All conversions involving fixed point types should be handled by the
- // EmitFixedPoint family functions. This is done to prevent bloating up this
- // function more, and although fixed point numbers are represented by
- // integers, we do not want to follow any logic that assumes they should be
- // treated as integers.
- // TODO(leonardchan): When necessary, add another if statement checking for
- // conversions to fixed point types from other types.
- if (SrcType->isFixedPointType()) {
- if (DstType->isFixedPointType()) {
- return EmitFixedPointConversion(Src, SrcType, DstType, Loc);
- } else if (DstType->isBooleanType()) {
- // We do not need to check the padding bit on unsigned types if unsigned
- // padding is enabled because overflow into this bit is undefined
- // behavior.
- return Builder.CreateIsNotNull(Src, "tobool");
- }
-
- llvm_unreachable(
- "Unhandled scalar conversion involving a fixed point type.");
- }
-
- QualType NoncanonicalSrcType = SrcType;
- QualType NoncanonicalDstType = DstType;
-
- SrcType = CGF.getContext().getCanonicalType(SrcType);
- DstType = CGF.getContext().getCanonicalType(DstType);
- if (SrcType == DstType) return Src;
-
- if (DstType->isVoidType()) return nullptr;
-
- llvm::Value *OrigSrc = Src;
- QualType OrigSrcType = SrcType;
- llvm::Type *SrcTy = Src->getType();
-
- // Handle conversions to bool first, they are special: comparisons against 0.
- if (DstType->isBooleanType())
- return EmitConversionToBool(Src, SrcType);
-
- llvm::Type *DstTy = ConvertType(DstType);
-
- // Cast from half through float if half isn't a native type.
- if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
- // Cast to FP using the intrinsic if the half type itself isn't supported.
- if (DstTy->isFloatingPointTy()) {
- if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics())
- return Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, DstTy),
- Src);
- } else {
- // Cast to other types through float, using either the intrinsic or FPExt,
- // depending on whether the half type itself is supported
- // (as opposed to operations on half, available with NativeHalfType).
- if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
- Src = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
- CGF.CGM.FloatTy),
- Src);
- } else {
- Src = Builder.CreateFPExt(Src, CGF.CGM.FloatTy, "conv");
- }
- SrcType = CGF.getContext().FloatTy;
- SrcTy = CGF.FloatTy;
- }
- }
-
- // Ignore conversions like int -> uint.
- if (SrcTy == DstTy) {
- if (Opts.EmitImplicitIntegerSignChangeChecks)
- EmitIntegerSignChangeCheck(Src, NoncanonicalSrcType, Src,
- NoncanonicalDstType, Loc);
-
- return Src;
- }
-
- // Handle pointer conversions next: pointers can only be converted to/from
- // other pointers and integers. Check for pointer types in terms of LLVM, as
- // some native types (like Obj-C id) may map to a pointer type.
- if (auto DstPT = dyn_cast<llvm::PointerType>(DstTy)) {
- // The source value may be an integer, or a pointer.
- if (isa<llvm::PointerType>(SrcTy))
- return Builder.CreateBitCast(Src, DstTy, "conv");
-
- assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?");
- // First, convert to the correct width so that we control the kind of
- // extension.
- llvm::Type *MiddleTy = CGF.CGM.getDataLayout().getIntPtrType(DstPT);
- bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
- llvm::Value* IntResult =
- Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
- // Then, cast to pointer.
- return Builder.CreateIntToPtr(IntResult, DstTy, "conv");
- }
-
- if (isa<llvm::PointerType>(SrcTy)) {
- // Must be an ptr to int cast.
- assert(isa<llvm::IntegerType>(DstTy) && "not ptr->int?");
- return Builder.CreatePtrToInt(Src, DstTy, "conv");
- }
-
- // A scalar can be splatted to an extended vector of the same element type
- if (DstType->isExtVectorType() && !SrcType->isVectorType()) {
- // Sema should add casts to make sure that the source expression's type is
- // the same as the vector's element type (sans qualifiers)
- assert(DstType->castAs<ExtVectorType>()->getElementType().getTypePtr() ==
- SrcType.getTypePtr() &&
- "Splatted expr doesn't match with vector element type?");
-
- // Splat the element across to all elements
- unsigned NumElements = DstTy->getVectorNumElements();
- return Builder.CreateVectorSplat(NumElements, Src, "splat");
- }
-
- if (isa<llvm::VectorType>(SrcTy) || isa<llvm::VectorType>(DstTy)) {
- // Allow bitcast from vector to integer/fp of the same size.
- unsigned SrcSize = SrcTy->getPrimitiveSizeInBits();
- unsigned DstSize = DstTy->getPrimitiveSizeInBits();
- if (SrcSize == DstSize)
- return Builder.CreateBitCast(Src, DstTy, "conv");
-
- // Conversions between vectors of different sizes are not allowed except
- // when vectors of half are involved. Operations on storage-only half
- // vectors require promoting half vector operands to float vectors and
- // truncating the result, which is either an int or float vector, to a
- // short or half vector.
-
- // Source and destination are both expected to be vectors.
- llvm::Type *SrcElementTy = SrcTy->getVectorElementType();
- llvm::Type *DstElementTy = DstTy->getVectorElementType();
- (void)DstElementTy;
-
- assert(((SrcElementTy->isIntegerTy() &&
- DstElementTy->isIntegerTy()) ||
- (SrcElementTy->isFloatingPointTy() &&
- DstElementTy->isFloatingPointTy())) &&
- "unexpected conversion between a floating-point vector and an "
- "integer vector");
-
- // Truncate an i32 vector to an i16 vector.
- if (SrcElementTy->isIntegerTy())
- return Builder.CreateIntCast(Src, DstTy, false, "conv");
-
- // Truncate a float vector to a half vector.
- if (SrcSize > DstSize)
- return Builder.CreateFPTrunc(Src, DstTy, "conv");
-
- // Promote a half vector to a float vector.
- return Builder.CreateFPExt(Src, DstTy, "conv");
- }
-
- // Finally, we have the arithmetic types: real int/float.
- Value *Res = nullptr;
- llvm::Type *ResTy = DstTy;
-
- // An overflowing conversion has undefined behavior if either the source type
- // or the destination type is a floating-point type.
- if (CGF.SanOpts.has(SanitizerKind::FloatCastOverflow) &&
- (OrigSrcType->isFloatingType() || DstType->isFloatingType()))
- EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy,
- Loc);
-
- // Cast to half through float if half isn't a native type.
- if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
- // Make sure we cast in a single step if from another FP type.
- if (SrcTy->isFloatingPointTy()) {
- // Use the intrinsic if the half type itself isn't supported
- // (as opposed to operations on half, available with NativeHalfType).
- if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics())
- return Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, SrcTy), Src);
- // If the half type is supported, just use an fptrunc.
- return Builder.CreateFPTrunc(Src, DstTy);
- }
- DstTy = CGF.FloatTy;
- }
-
- if (isa<llvm::IntegerType>(SrcTy)) {
- bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
- if (SrcType->isBooleanType() && Opts.TreatBooleanAsSigned) {
- InputSigned = true;
- }
- if (isa<llvm::IntegerType>(DstTy))
- Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
- else if (InputSigned)
- Res = Builder.CreateSIToFP(Src, DstTy, "conv");
- else
- Res = Builder.CreateUIToFP(Src, DstTy, "conv");
- } else if (isa<llvm::IntegerType>(DstTy)) {
- assert(SrcTy->isFloatingPointTy() && "Unknown real conversion");
- if (DstType->isSignedIntegerOrEnumerationType())
- Res = Builder.CreateFPToSI(Src, DstTy, "conv");
- else
- Res = Builder.CreateFPToUI(Src, DstTy, "conv");
- } else {
- assert(SrcTy->isFloatingPointTy() && DstTy->isFloatingPointTy() &&
- "Unknown real conversion");
- if (DstTy->getTypeID() < SrcTy->getTypeID())
- Res = Builder.CreateFPTrunc(Src, DstTy, "conv");
- else
- Res = Builder.CreateFPExt(Src, DstTy, "conv");
- }
-
- if (DstTy != ResTy) {
- if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
- assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
- Res = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy),
- Res);
- } else {
- Res = Builder.CreateFPTrunc(Res, ResTy, "conv");
- }
- }
-
- if (Opts.EmitImplicitIntegerTruncationChecks)
- EmitIntegerTruncationCheck(Src, NoncanonicalSrcType, Res,
- NoncanonicalDstType, Loc);
-
- if (Opts.EmitImplicitIntegerSignChangeChecks)
- EmitIntegerSignChangeCheck(Src, NoncanonicalSrcType, Res,
- NoncanonicalDstType, Loc);
-
- return Res;
-}
-
-Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
- QualType DstTy,
- SourceLocation Loc) {
- using llvm::APInt;
- using llvm::ConstantInt;
- using llvm::Value;
-
- assert(SrcTy->isFixedPointType());
- assert(DstTy->isFixedPointType());
-
- FixedPointSemantics SrcFPSema =
- CGF.getContext().getFixedPointSemantics(SrcTy);
- FixedPointSemantics DstFPSema =
- CGF.getContext().getFixedPointSemantics(DstTy);
- unsigned SrcWidth = SrcFPSema.getWidth();
- unsigned DstWidth = DstFPSema.getWidth();
- unsigned SrcScale = SrcFPSema.getScale();
- unsigned DstScale = DstFPSema.getScale();
- bool SrcIsSigned = SrcFPSema.isSigned();
- bool DstIsSigned = DstFPSema.isSigned();
-
- llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth);
-
- Value *Result = Src;
- unsigned ResultWidth = SrcWidth;
-
- if (!DstFPSema.isSaturated()) {
- // Downscale.
- if (DstScale < SrcScale)
- Result = SrcIsSigned ?
- Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") :
- Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
-
- // Resize.
- Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
-
- // Upscale.
- if (DstScale > SrcScale)
- Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale");
- } else {
- // Adjust the number of fractional bits.
- if (DstScale > SrcScale) {
- ResultWidth = SrcWidth + DstScale - SrcScale;
- llvm::Type *UpscaledTy = Builder.getIntNTy(ResultWidth);
- Result = Builder.CreateIntCast(Result, UpscaledTy, SrcIsSigned, "resize");
- Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale");
- } else if (DstScale < SrcScale) {
- Result = SrcIsSigned ?
- Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") :
- Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
- }
-
- // Handle saturation.
- bool LessIntBits = DstFPSema.getIntegralBits() < SrcFPSema.getIntegralBits();
- if (LessIntBits) {
- Value *Max = ConstantInt::get(
- CGF.getLLVMContext(),
- APFixedPoint::getMax(DstFPSema).getValue().extOrTrunc(ResultWidth));
- Value *TooHigh = SrcIsSigned ? Builder.CreateICmpSGT(Result, Max)
- : Builder.CreateICmpUGT(Result, Max);
- Result = Builder.CreateSelect(TooHigh, Max, Result, "satmax");
- }
- // Cannot overflow min to dest type if src is unsigned since all fixed
- // point types can cover the unsigned min of 0.
- if (SrcIsSigned && (LessIntBits || !DstIsSigned)) {
- Value *Min = ConstantInt::get(
- CGF.getLLVMContext(),
- APFixedPoint::getMin(DstFPSema).getValue().extOrTrunc(ResultWidth));
- Value *TooLow = Builder.CreateICmpSLT(Result, Min);
- Result = Builder.CreateSelect(TooLow, Min, Result, "satmin");
- }
-
- // Resize the integer part to get the final destination size.
- Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
- }
- return Result;
-}
-
-/// Emit a conversion from the specified complex type to the specified
-/// destination type, where the destination type is an LLVM scalar type.
-Value *ScalarExprEmitter::EmitComplexToScalarConversion(
- CodeGenFunction::ComplexPairTy Src, QualType SrcTy, QualType DstTy,
- SourceLocation Loc) {
- // Get the source element type.
- SrcTy = SrcTy->castAs<ComplexType>()->getElementType();
-
- // Handle conversions to bool first, they are special: comparisons against 0.
- if (DstTy->isBooleanType()) {
- // Complex != 0 -> (Real != 0) | (Imag != 0)
- Src.first = EmitScalarConversion(Src.first, SrcTy, DstTy, Loc);
- Src.second = EmitScalarConversion(Src.second, SrcTy, DstTy, Loc);
- return Builder.CreateOr(Src.first, Src.second, "tobool");
- }
-
- // C99 6.3.1.7p2: "When a value of complex type is converted to a real type,
- // the imaginary part of the complex value is discarded and the value of the
- // real part is converted according to the conversion rules for the
- // corresponding real type.
- return EmitScalarConversion(Src.first, SrcTy, DstTy, Loc);
-}
-
-Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
- return CGF.EmitFromMemory(CGF.CGM.EmitNullConstant(Ty), Ty);
-}
-
-/// Emit a sanitization check for the given "binary" operation (which
-/// might actually be a unary increment which has been lowered to a binary
-/// operation). The check passes if all values in \p Checks (which are \c i1),
-/// are \c true.
-void ScalarExprEmitter::EmitBinOpCheck(
- ArrayRef<std::pair<Value *, SanitizerMask>> Checks, const BinOpInfo &Info) {
- assert(CGF.IsSanitizerScope);
- SanitizerHandler Check;
- SmallVector<llvm::Constant *, 4> StaticData;
- SmallVector<llvm::Value *, 2> DynamicData;
-
- BinaryOperatorKind Opcode = Info.Opcode;
- if (BinaryOperator::isCompoundAssignmentOp(Opcode))
- Opcode = BinaryOperator::getOpForCompoundAssignment(Opcode);
-
- StaticData.push_back(CGF.EmitCheckSourceLocation(Info.E->getExprLoc()));
- const UnaryOperator *UO = dyn_cast<UnaryOperator>(Info.E);
- if (UO && UO->getOpcode() == UO_Minus) {
- Check = SanitizerHandler::NegateOverflow;
- StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType()));
- DynamicData.push_back(Info.RHS);
- } else {
- if (BinaryOperator::isShiftOp(Opcode)) {
- // Shift LHS negative or too large, or RHS out of bounds.
- Check = SanitizerHandler::ShiftOutOfBounds;
- const BinaryOperator *BO = cast<BinaryOperator>(Info.E);
- StaticData.push_back(
- CGF.EmitCheckTypeDescriptor(BO->getLHS()->getType()));
- StaticData.push_back(
- CGF.EmitCheckTypeDescriptor(BO->getRHS()->getType()));
- } else if (Opcode == BO_Div || Opcode == BO_Rem) {
- // Divide or modulo by zero, or signed overflow (eg INT_MAX / -1).
- Check = SanitizerHandler::DivremOverflow;
- StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
- } else {
- // Arithmetic overflow (+, -, *).
- switch (Opcode) {
- case BO_Add: Check = SanitizerHandler::AddOverflow; break;
- case BO_Sub: Check = SanitizerHandler::SubOverflow; break;
- case BO_Mul: Check = SanitizerHandler::MulOverflow; break;
- default: llvm_unreachable("unexpected opcode for bin op check");
- }
- StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
- }
- DynamicData.push_back(Info.LHS);
- DynamicData.push_back(Info.RHS);
- }
-
- CGF.EmitCheck(Checks, Check, StaticData, DynamicData);
-}
-
-//===----------------------------------------------------------------------===//
-// Visitor Methods
-//===----------------------------------------------------------------------===//
-
-Value *ScalarExprEmitter::VisitExpr(Expr *E) {
- CGF.ErrorUnsupported(E, "scalar expression");
- if (E->getType()->isVoidType())
- return nullptr;
- return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
-}
-
-Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
- // Vector Mask Case
- if (E->getNumSubExprs() == 2) {
- Value *LHS = CGF.EmitScalarExpr(E->getExpr(0));
- Value *RHS = CGF.EmitScalarExpr(E->getExpr(1));
- Value *Mask;
-
- llvm::VectorType *LTy = cast<llvm::VectorType>(LHS->getType());
- unsigned LHSElts = LTy->getNumElements();
-
- Mask = RHS;
-
- llvm::VectorType *MTy = cast<llvm::VectorType>(Mask->getType());
-
- // Mask off the high bits of each shuffle index.
- Value *MaskBits =
- llvm::ConstantInt::get(MTy, llvm::NextPowerOf2(LHSElts - 1) - 1);
- Mask = Builder.CreateAnd(Mask, MaskBits, "mask");
-
- // newv = undef
- // mask = mask & maskbits
- // for each elt
- // n = extract mask i
- // x = extract val n
- // newv = insert newv, x, i
- llvm::VectorType *RTy = llvm::VectorType::get(LTy->getElementType(),
- MTy->getNumElements());
- Value* NewV = llvm::UndefValue::get(RTy);
- for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) {
- Value *IIndx = llvm::ConstantInt::get(CGF.SizeTy, i);
- Value *Indx = Builder.CreateExtractElement(Mask, IIndx, "shuf_idx");
-
- Value *VExt = Builder.CreateExtractElement(LHS, Indx, "shuf_elt");
- NewV = Builder.CreateInsertElement(NewV, VExt, IIndx, "shuf_ins");
- }
- return NewV;
- }
-
- Value* V1 = CGF.EmitScalarExpr(E->getExpr(0));
- Value* V2 = CGF.EmitScalarExpr(E->getExpr(1));
-
- SmallVector<llvm::Constant*, 32> indices;
- for (unsigned i = 2; i < E->getNumSubExprs(); ++i) {
- llvm::APSInt Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2);
- // Check for -1 and output it as undef in the IR.
- if (Idx.isSigned() && Idx.isAllOnesValue())
- indices.push_back(llvm::UndefValue::get(CGF.Int32Ty));
- else
- indices.push_back(Builder.getInt32(Idx.getZExtValue()));
- }
-
- Value *SV = llvm::ConstantVector::get(indices);
- return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
-}
-
-Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
- QualType SrcType = E->getSrcExpr()->getType(),
- DstType = E->getType();
-
- Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
-
- SrcType = CGF.getContext().getCanonicalType(SrcType);
- DstType = CGF.getContext().getCanonicalType(DstType);
- if (SrcType == DstType) return Src;
-
- assert(SrcType->isVectorType() &&
- "ConvertVector source type must be a vector");
- assert(DstType->isVectorType() &&
- "ConvertVector destination type must be a vector");
-
- llvm::Type *SrcTy = Src->getType();
- llvm::Type *DstTy = ConvertType(DstType);
-
- // Ignore conversions like int -> uint.
- if (SrcTy == DstTy)
- return Src;
-
- QualType SrcEltType = SrcType->getAs<VectorType>()->getElementType(),
- DstEltType = DstType->getAs<VectorType>()->getElementType();
-
- assert(SrcTy->isVectorTy() &&
- "ConvertVector source IR type must be a vector");
- assert(DstTy->isVectorTy() &&
- "ConvertVector destination IR type must be a vector");
-
- llvm::Type *SrcEltTy = SrcTy->getVectorElementType(),
- *DstEltTy = DstTy->getVectorElementType();
-
- if (DstEltType->isBooleanType()) {
- assert((SrcEltTy->isFloatingPointTy() ||
- isa<llvm::IntegerType>(SrcEltTy)) && "Unknown boolean conversion");
-
- llvm::Value *Zero = llvm::Constant::getNullValue(SrcTy);
- if (SrcEltTy->isFloatingPointTy()) {
- return Builder.CreateFCmpUNE(Src, Zero, "tobool");
- } else {
- return Builder.CreateICmpNE(Src, Zero, "tobool");
- }
- }
-
- // We have the arithmetic types: real int/float.
- Value *Res = nullptr;
-
- if (isa<llvm::IntegerType>(SrcEltTy)) {
- bool InputSigned = SrcEltType->isSignedIntegerOrEnumerationType();
- if (isa<llvm::IntegerType>(DstEltTy))
- Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
- else if (InputSigned)
- Res = Builder.CreateSIToFP(Src, DstTy, "conv");
- else
- Res = Builder.CreateUIToFP(Src, DstTy, "conv");
- } else if (isa<llvm::IntegerType>(DstEltTy)) {
- assert(SrcEltTy->isFloatingPointTy() && "Unknown real conversion");
- if (DstEltType->isSignedIntegerOrEnumerationType())
- Res = Builder.CreateFPToSI(Src, DstTy, "conv");
- else
- Res = Builder.CreateFPToUI(Src, DstTy, "conv");
- } else {
- assert(SrcEltTy->isFloatingPointTy() && DstEltTy->isFloatingPointTy() &&
- "Unknown real conversion");
- if (DstEltTy->getTypeID() < SrcEltTy->getTypeID())
- Res = Builder.CreateFPTrunc(Src, DstTy, "conv");
- else
- Res = Builder.CreateFPExt(Src, DstTy, "conv");
- }
-
- return Res;
-}
-
-Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
- if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) {
- CGF.EmitIgnoredExpr(E->getBase());
- return CGF.emitScalarConstant(Constant, E);
- } else {
- Expr::EvalResult Result;
- if (E->EvaluateAsInt(Result, CGF.getContext(), Expr::SE_AllowSideEffects)) {
- llvm::APSInt Value = Result.Val.getInt();
- CGF.EmitIgnoredExpr(E->getBase());
- return Builder.getInt(Value);
- }
- }
-
- return EmitLoadOfLValue(E);
-}
-
-Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
- TestAndClearIgnoreResultAssign();
-
- // Emit subscript expressions in rvalue context's. For most cases, this just
- // loads the lvalue formed by the subscript expr. However, we have to be
- // careful, because the base of a vector subscript is occasionally an rvalue,
- // so we can't get it as an lvalue.
- if (!E->getBase()->getType()->isVectorType())
- return EmitLoadOfLValue(E);
-
- // Handle the vector case. The base must be a vector, the index must be an
- // integer value.
- Value *Base = Visit(E->getBase());
- Value *Idx = Visit(E->getIdx());
- QualType IdxTy = E->getIdx()->getType();
-
- if (CGF.SanOpts.has(SanitizerKind::ArrayBounds))
- CGF.EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, /*Accessed*/true);
-
- return Builder.CreateExtractElement(Base, Idx, "vecext");
-}
-
-static llvm::Constant *getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx,
- unsigned Off, llvm::Type *I32Ty) {
- int MV = SVI->getMaskValue(Idx);
- if (MV == -1)
- return llvm::UndefValue::get(I32Ty);
- return llvm::ConstantInt::get(I32Ty, Off+MV);
-}
-
-static llvm::Constant *getAsInt32(llvm::ConstantInt *C, llvm::Type *I32Ty) {
- if (C->getBitWidth() != 32) {
- assert(llvm::ConstantInt::isValueValidForType(I32Ty,
- C->getZExtValue()) &&
- "Index operand too large for shufflevector mask!");
- return llvm::ConstantInt::get(I32Ty, C->getZExtValue());
- }
- return C;
-}
-
-Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
- bool Ignore = TestAndClearIgnoreResultAssign();
- (void)Ignore;
- assert (Ignore == false && "init list ignored");
- unsigned NumInitElements = E->getNumInits();
-
- if (E->hadArrayRangeDesignator())
- CGF.ErrorUnsupported(E, "GNU array range designator extension");
-
- llvm::VectorType *VType =
- dyn_cast<llvm::VectorType>(ConvertType(E->getType()));
-
- if (!VType) {
- if (NumInitElements == 0) {
- // C++11 value-initialization for the scalar.
- return EmitNullValue(E->getType());
- }
- // We have a scalar in braces. Just use the first element.
- return Visit(E->getInit(0));
- }
-
- unsigned ResElts = VType->getNumElements();
-
- // Loop over initializers collecting the Value for each, and remembering
- // whether the source was swizzle (ExtVectorElementExpr). This will allow
- // us to fold the shuffle for the swizzle into the shuffle for the vector
- // initializer, since LLVM optimizers generally do not want to touch
- // shuffles.
- unsigned CurIdx = 0;
- bool VIsUndefShuffle = false;
- llvm::Value *V = llvm::UndefValue::get(VType);
- for (unsigned i = 0; i != NumInitElements; ++i) {
- Expr *IE = E->getInit(i);
- Value *Init = Visit(IE);
- SmallVector<llvm::Constant*, 16> Args;
-
- llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType());
-
- // Handle scalar elements. If the scalar initializer is actually one
- // element of a different vector of the same width, use shuffle instead of
- // extract+insert.
- if (!VVT) {
- if (isa<ExtVectorElementExpr>(IE)) {
- llvm::ExtractElementInst *EI = cast<llvm::ExtractElementInst>(Init);
-
- if (EI->getVectorOperandType()->getNumElements() == ResElts) {
- llvm::ConstantInt *C = cast<llvm::ConstantInt>(EI->getIndexOperand());
- Value *LHS = nullptr, *RHS = nullptr;
- if (CurIdx == 0) {
- // insert into undef -> shuffle (src, undef)
- // shufflemask must use an i32
- Args.push_back(getAsInt32(C, CGF.Int32Ty));
- Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
-
- LHS = EI->getVectorOperand();
- RHS = V;
- VIsUndefShuffle = true;
- } else if (VIsUndefShuffle) {
- // insert into undefshuffle && size match -> shuffle (v, src)
- llvm::ShuffleVectorInst *SVV = cast<llvm::ShuffleVectorInst>(V);
- for (unsigned j = 0; j != CurIdx; ++j)
- Args.push_back(getMaskElt(SVV, j, 0, CGF.Int32Ty));
- Args.push_back(Builder.getInt32(ResElts + C->getZExtValue()));
- Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
-
- LHS = cast<llvm::ShuffleVectorInst>(V)->getOperand(0);
- RHS = EI->getVectorOperand();
- VIsUndefShuffle = false;
- }
- if (!Args.empty()) {
- llvm::Constant *Mask = llvm::ConstantVector::get(Args);
- V = Builder.CreateShuffleVector(LHS, RHS, Mask);
- ++CurIdx;
- continue;
- }
- }
- }
- V = Builder.CreateInsertElement(V, Init, Builder.getInt32(CurIdx),
- "vecinit");
- VIsUndefShuffle = false;
- ++CurIdx;
- continue;
- }
-
- unsigned InitElts = VVT->getNumElements();
-
- // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's
- // input is the same width as the vector being constructed, generate an
- // optimized shuffle of the swizzle input into the result.
- unsigned Offset = (CurIdx == 0) ? 0 : ResElts;
- if (isa<ExtVectorElementExpr>(IE)) {
- llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init);
- Value *SVOp = SVI->getOperand(0);
- llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType());
-
- if (OpTy->getNumElements() == ResElts) {
- for (unsigned j = 0; j != CurIdx; ++j) {
- // If the current vector initializer is a shuffle with undef, merge
- // this shuffle directly into it.
- if (VIsUndefShuffle) {
- Args.push_back(getMaskElt(cast<llvm::ShuffleVectorInst>(V), j, 0,
- CGF.Int32Ty));
- } else {
- Args.push_back(Builder.getInt32(j));
- }
- }
- for (unsigned j = 0, je = InitElts; j != je; ++j)
- Args.push_back(getMaskElt(SVI, j, Offset, CGF.Int32Ty));
- Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
-
- if (VIsUndefShuffle)
- V = cast<llvm::ShuffleVectorInst>(V)->getOperand(0);
-
- Init = SVOp;
- }
- }
-
- // Extend init to result vector length, and then shuffle its contribution
- // to the vector initializer into V.
- if (Args.empty()) {
- for (unsigned j = 0; j != InitElts; ++j)
- Args.push_back(Builder.getInt32(j));
- Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
- llvm::Constant *Mask = llvm::ConstantVector::get(Args);
- Init = Builder.CreateShuffleVector(Init, llvm::UndefValue::get(VVT),
- Mask, "vext");
-
- Args.clear();
- for (unsigned j = 0; j != CurIdx; ++j)
- Args.push_back(Builder.getInt32(j));
- for (unsigned j = 0; j != InitElts; ++j)
- Args.push_back(Builder.getInt32(j+Offset));
- Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
- }
-
- // If V is undef, make sure it ends up on the RHS of the shuffle to aid
- // merging subsequent shuffles into this one.
- if (CurIdx == 0)
- std::swap(V, Init);
- llvm::Constant *Mask = llvm::ConstantVector::get(Args);
- V = Builder.CreateShuffleVector(V, Init, Mask, "vecinit");
- VIsUndefShuffle = isa<llvm::UndefValue>(Init);
- CurIdx += InitElts;
- }
-
- // FIXME: evaluate codegen vs. shuffling against constant null vector.
- // Emit remaining default initializers.
- llvm::Type *EltTy = VType->getElementType();
-
- // Emit remaining default initializers
- for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) {
- Value *Idx = Builder.getInt32(CurIdx);
- llvm::Value *Init = llvm::Constant::getNullValue(EltTy);
- V = Builder.CreateInsertElement(V, Init, Idx, "vecinit");
- }
- return V;
-}
-
-bool CodeGenFunction::ShouldNullCheckClassCastValue(const CastExpr *CE) {
- const Expr *E = CE->getSubExpr();
-
- if (CE->getCastKind() == CK_UncheckedDerivedToBase)
- return false;
-
- if (isa<CXXThisExpr>(E->IgnoreParens())) {
- // We always assume that 'this' is never null.
- return false;
- }
-
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
- // And that glvalue casts are never null.
- if (ICE->getValueKind() != VK_RValue)
- return false;
- }
-
- return true;
-}
-
-// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
-// have to handle a more broad range of conversions than explicit casts, as they
-// handle things like function to ptr-to-function decay etc.
-Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
- Expr *E = CE->getSubExpr();
- QualType DestTy = CE->getType();
- CastKind Kind = CE->getCastKind();
-
- // These cases are generally not written to ignore the result of
- // evaluating their sub-expressions, so we clear this now.
- bool Ignored = TestAndClearIgnoreResultAssign();
-
- // Since almost all cast kinds apply to scalars, this switch doesn't have
- // a default case, so the compiler will warn on a missing case. The cases
- // are in the same order as in the CastKind enum.
- switch (Kind) {
- case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
- case CK_BuiltinFnToFnPtr:
- llvm_unreachable("builtin functions are handled elsewhere");
-
- case CK_LValueBitCast:
- case CK_ObjCObjectLValueCast: {
- Address Addr = EmitLValue(E).getAddress();
- Addr = Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(DestTy));
- LValue LV = CGF.MakeAddrLValue(Addr, DestTy);
- return EmitLoadOfLValue(LV, CE->getExprLoc());
- }
-
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_BitCast: {
- Value *Src = Visit(const_cast<Expr*>(E));
- llvm::Type *SrcTy = Src->getType();
- llvm::Type *DstTy = ConvertType(DestTy);
- if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isPtrOrPtrVectorTy() &&
- SrcTy->getPointerAddressSpace() != DstTy->getPointerAddressSpace()) {
- llvm_unreachable("wrong cast for pointers in different address spaces"
- "(must be an address space cast)!");
- }
-
- if (CGF.SanOpts.has(SanitizerKind::CFIUnrelatedCast)) {
- if (auto PT = DestTy->getAs<PointerType>())
- CGF.EmitVTablePtrCheckForCast(PT->getPointeeType(), Src,
- /*MayBeNull=*/true,
- CodeGenFunction::CFITCK_UnrelatedCast,
- CE->getBeginLoc());
- }
-
- if (CGF.CGM.getCodeGenOpts().StrictVTablePointers) {
- const QualType SrcType = E->getType();
-
- if (SrcType.mayBeNotDynamicClass() && DestTy.mayBeDynamicClass()) {
- // Casting to pointer that could carry dynamic information (provided by
- // invariant.group) requires launder.
- Src = Builder.CreateLaunderInvariantGroup(Src);
- } else if (SrcType.mayBeDynamicClass() && DestTy.mayBeNotDynamicClass()) {
- // Casting to pointer that does not carry dynamic information (provided
- // by invariant.group) requires stripping it. Note that we don't do it
- // if the source could not be dynamic type and destination could be
- // dynamic because dynamic information is already laundered. It is
- // because launder(strip(src)) == launder(src), so there is no need to
- // add extra strip before launder.
- Src = Builder.CreateStripInvariantGroup(Src);
- }
- }
-
- return Builder.CreateBitCast(Src, DstTy);
- }
- case CK_AddressSpaceConversion: {
- Expr::EvalResult Result;
- if (E->EvaluateAsRValue(Result, CGF.getContext()) &&
- Result.Val.isNullPointer()) {
- // If E has side effect, it is emitted even if its final result is a
- // null pointer. In that case, a DCE pass should be able to
- // eliminate the useless instructions emitted during translating E.
- if (Result.HasSideEffects)
- Visit(E);
- return CGF.CGM.getNullPointer(cast<llvm::PointerType>(
- ConvertType(DestTy)), DestTy);
- }
- // Since target may map different address spaces in AST to the same address
- // space, an address space conversion may end up as a bitcast.
- return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(
- CGF, Visit(E), E->getType()->getPointeeType().getAddressSpace(),
- DestTy->getPointeeType().getAddressSpace(), ConvertType(DestTy));
- }
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
- case CK_NoOp:
- case CK_UserDefinedConversion:
- return Visit(const_cast<Expr*>(E));
-
- case CK_BaseToDerived: {
- const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl();
- assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
-
- Address Base = CGF.EmitPointerWithAlignment(E);
- Address Derived =
- CGF.GetAddressOfDerivedClass(Base, DerivedClassDecl,
- CE->path_begin(), CE->path_end(),
- CGF.ShouldNullCheckClassCastValue(CE));
-
- // C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
- // performed and the object is not of the derived type.
- if (CGF.sanitizePerformTypeCheck())
- CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
- Derived.getPointer(), DestTy->getPointeeType());
-
- if (CGF.SanOpts.has(SanitizerKind::CFIDerivedCast))
- CGF.EmitVTablePtrCheckForCast(
- DestTy->getPointeeType(), Derived.getPointer(),
- /*MayBeNull=*/true, CodeGenFunction::CFITCK_DerivedCast,
- CE->getBeginLoc());
-
- return Derived.getPointer();
- }
- case CK_UncheckedDerivedToBase:
- case CK_DerivedToBase: {
- // The EmitPointerWithAlignment path does this fine; just discard
- // the alignment.
- return CGF.EmitPointerWithAlignment(CE).getPointer();
- }
-
- case CK_Dynamic: {
- Address V = CGF.EmitPointerWithAlignment(E);
- const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(CE);
- return CGF.EmitDynamicCast(V, DCE);
- }
-
- case CK_ArrayToPointerDecay:
- return CGF.EmitArrayToPointerDecay(E).getPointer();
- case CK_FunctionToPointerDecay:
- return EmitLValue(E).getPointer();
-
- case CK_NullToPointer:
- if (MustVisitNullValue(E))
- (void) Visit(E);
-
- return CGF.CGM.getNullPointer(cast<llvm::PointerType>(ConvertType(DestTy)),
- DestTy);
-
- case CK_NullToMemberPointer: {
- if (MustVisitNullValue(E))
- (void) Visit(E);
-
- const MemberPointerType *MPT = CE->getType()->getAs<MemberPointerType>();
- return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
- }
-
- case CK_ReinterpretMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer: {
- Value *Src = Visit(E);
-
- // Note that the AST doesn't distinguish between checked and
- // unchecked member pointer conversions, so we always have to
- // implement checked conversions here. This is inefficient when
- // actual control flow may be required in order to perform the
- // check, which it is for data member pointers (but not member
- // function pointers on Itanium and ARM).
- return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src);
- }
-
- case CK_ARCProduceObject:
- return CGF.EmitARCRetainScalarExpr(E);
- case CK_ARCConsumeObject:
- return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
- case CK_ARCReclaimReturnedObject:
- return CGF.EmitARCReclaimReturnedObject(E, /*allowUnsafe*/ Ignored);
- case CK_ARCExtendBlockObject:
- return CGF.EmitARCExtendBlockObject(E);
-
- case CK_CopyAndAutoreleaseBlockObject:
- return CGF.EmitBlockCopyAndAutorelease(Visit(E), E->getType());
-
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexCast:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_FloatingComplexToIntegralComplex:
- case CK_ConstructorConversion:
- case CK_ToUnion:
- llvm_unreachable("scalar cast to non-scalar value");
-
- case CK_LValueToRValue:
- assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
- assert(E->isGLValue() && "lvalue-to-rvalue applied to r-value!");
- return Visit(const_cast<Expr*>(E));
-
- case CK_IntegralToPointer: {
- Value *Src = Visit(const_cast<Expr*>(E));
-
- // First, convert to the correct width so that we control the kind of
- // extension.
- auto DestLLVMTy = ConvertType(DestTy);
- llvm::Type *MiddleTy = CGF.CGM.getDataLayout().getIntPtrType(DestLLVMTy);
- bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType();
- llvm::Value* IntResult =
- Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
-
- auto *IntToPtr = Builder.CreateIntToPtr(IntResult, DestLLVMTy);
-
- if (CGF.CGM.getCodeGenOpts().StrictVTablePointers) {
- // Going from integer to pointer that could be dynamic requires reloading
- // dynamic information from invariant.group.
- if (DestTy.mayBeDynamicClass())
- IntToPtr = Builder.CreateLaunderInvariantGroup(IntToPtr);
- }
- return IntToPtr;
- }
- case CK_PointerToIntegral: {
- assert(!DestTy->isBooleanType() && "bool should use PointerToBool");
- auto *PtrExpr = Visit(E);
-
- if (CGF.CGM.getCodeGenOpts().StrictVTablePointers) {
- const QualType SrcType = E->getType();
-
- // Casting to integer requires stripping dynamic information as it does
- // not carries it.
- if (SrcType.mayBeDynamicClass())
- PtrExpr = Builder.CreateStripInvariantGroup(PtrExpr);
- }
-
- return Builder.CreatePtrToInt(PtrExpr, ConvertType(DestTy));
- }
- case CK_ToVoid: {
- CGF.EmitIgnoredExpr(E);
- return nullptr;
- }
- case CK_VectorSplat: {
- llvm::Type *DstTy = ConvertType(DestTy);
- Value *Elt = Visit(const_cast<Expr*>(E));
- // Splat the element across to all elements
- unsigned NumElements = DstTy->getVectorNumElements();
- return Builder.CreateVectorSplat(NumElements, Elt, "splat");
- }
-
- case CK_FixedPointCast:
- return EmitScalarConversion(Visit(E), E->getType(), DestTy,
- CE->getExprLoc());
-
- case CK_FixedPointToBoolean:
- assert(E->getType()->isFixedPointType() &&
- "Expected src type to be fixed point type");
- assert(DestTy->isBooleanType() && "Expected dest type to be boolean type");
- return EmitScalarConversion(Visit(E), E->getType(), DestTy,
- CE->getExprLoc());
-
- case CK_IntegralCast: {
- ScalarConversionOpts Opts;
- if (auto *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
- if (!ICE->isPartOfExplicitCast())
- Opts = ScalarConversionOpts(CGF.SanOpts);
- }
- return EmitScalarConversion(Visit(E), E->getType(), DestTy,
- CE->getExprLoc(), Opts);
- }
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingCast:
- return EmitScalarConversion(Visit(E), E->getType(), DestTy,
- CE->getExprLoc());
- case CK_BooleanToSignedIntegral: {
- ScalarConversionOpts Opts;
- Opts.TreatBooleanAsSigned = true;
- return EmitScalarConversion(Visit(E), E->getType(), DestTy,
- CE->getExprLoc(), Opts);
- }
- case CK_IntegralToBoolean:
- return EmitIntToBoolConversion(Visit(E));
- case CK_PointerToBoolean:
- return EmitPointerToBoolConversion(Visit(E), E->getType());
- case CK_FloatingToBoolean:
- return EmitFloatToBoolConversion(Visit(E));
- case CK_MemberPointerToBoolean: {
- llvm::Value *MemPtr = Visit(E);
- const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
- return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, MemPtr, MPT);
- }
-
- case CK_FloatingComplexToReal:
- case CK_IntegralComplexToReal:
- return CGF.EmitComplexExpr(E, false, true).first;
-
- case CK_FloatingComplexToBoolean:
- case CK_IntegralComplexToBoolean: {
- CodeGenFunction::ComplexPairTy V = CGF.EmitComplexExpr(E);
-
- // TODO: kill this function off, inline appropriate case here
- return EmitComplexToScalarConversion(V, E->getType(), DestTy,
- CE->getExprLoc());
- }
-
- case CK_ZeroToOCLOpaqueType: {
- assert((DestTy->isEventT() || DestTy->isQueueT() ||
- DestTy->isOCLIntelSubgroupAVCType()) &&
- "CK_ZeroToOCLEvent cast on non-event type");
- return llvm::Constant::getNullValue(ConvertType(DestTy));
- }
-
- case CK_IntToOCLSampler:
- return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
-
- } // end of switch
-
- llvm_unreachable("unknown scalar cast");
-}
-
-Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
- CodeGenFunction::StmtExprEvaluation eval(CGF);
- Address RetAlloca = CGF.EmitCompoundStmt(*E->getSubStmt(),
- !E->getType()->isVoidType());
- if (!RetAlloca.isValid())
- return nullptr;
- return CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(RetAlloca, E->getType()),
- E->getExprLoc());
-}
-
-Value *ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
- CGF.enterFullExpression(E);
- CodeGenFunction::RunCleanupsScope Scope(CGF);
- Value *V = Visit(E->getSubExpr());
- // Defend against dominance problems caused by jumps out of expression
- // evaluation through the shared cleanup block.
- Scope.ForceCleanup({&V});
- return V;
-}
-
-//===----------------------------------------------------------------------===//
-// Unary Operators
-//===----------------------------------------------------------------------===//
-
-static BinOpInfo createBinOpInfoFromIncDec(const UnaryOperator *E,
- llvm::Value *InVal, bool IsInc) {
- BinOpInfo BinOp;
- BinOp.LHS = InVal;
- BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false);
- BinOp.Ty = E->getType();
- BinOp.Opcode = IsInc ? BO_Add : BO_Sub;
- // FIXME: once UnaryOperator carries FPFeatures, copy it here.
- BinOp.E = E;
- return BinOp;
-}
-
-llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
- const UnaryOperator *E, llvm::Value *InVal, bool IsInc) {
- llvm::Value *Amount =
- llvm::ConstantInt::get(InVal->getType(), IsInc ? 1 : -1, true);
- StringRef Name = IsInc ? "inc" : "dec";
- switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Defined:
- return Builder.CreateAdd(InVal, Amount, Name);
- case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
- return Builder.CreateNSWAdd(InVal, Amount, Name);
- LLVM_FALLTHROUGH;
- case LangOptions::SOB_Trapping:
- if (!E->canOverflow())
- return Builder.CreateNSWAdd(InVal, Amount, Name);
- return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc));
- }
- llvm_unreachable("Unknown SignedOverflowBehaviorTy");
-}
-
-llvm::Value *
-ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
- bool isInc, bool isPre) {
-
- QualType type = E->getSubExpr()->getType();
- llvm::PHINode *atomicPHI = nullptr;
- llvm::Value *value;
- llvm::Value *input;
-
- int amount = (isInc ? 1 : -1);
- bool isSubtraction = !isInc;
-
- if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
- type = atomicTy->getValueType();
- if (isInc && type->isBooleanType()) {
- llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type);
- if (isPre) {
- Builder.CreateStore(True, LV.getAddress(), LV.isVolatileQualified())
- ->setAtomic(llvm::AtomicOrdering::SequentiallyConsistent);
- return Builder.getTrue();
- }
- // For atomic bool increment, we just store true and return it for
- // preincrement, do an atomic swap with true for postincrement
- return Builder.CreateAtomicRMW(
- llvm::AtomicRMWInst::Xchg, LV.getPointer(), True,
- llvm::AtomicOrdering::SequentiallyConsistent);
- }
- // Special case for atomic increment / decrement on integers, emit
- // atomicrmw instructions. We skip this if we want to be doing overflow
- // checking, and fall into the slow path with the atomic cmpxchg loop.
- if (!type->isBooleanType() && type->isIntegerType() &&
- !(type->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
- CGF.getLangOpts().getSignedOverflowBehavior() !=
- LangOptions::SOB_Trapping) {
- llvm::AtomicRMWInst::BinOp aop = isInc ? llvm::AtomicRMWInst::Add :
- llvm::AtomicRMWInst::Sub;
- llvm::Instruction::BinaryOps op = isInc ? llvm::Instruction::Add :
- llvm::Instruction::Sub;
- llvm::Value *amt = CGF.EmitToMemory(
- llvm::ConstantInt::get(ConvertType(type), 1, true), type);
- llvm::Value *old = Builder.CreateAtomicRMW(aop,
- LV.getPointer(), amt, llvm::AtomicOrdering::SequentiallyConsistent);
- return isPre ? Builder.CreateBinOp(op, old, amt) : old;
- }
- value = EmitLoadOfLValue(LV, E->getExprLoc());
- input = value;
- // For every other atomic operation, we need to emit a load-op-cmpxchg loop
- llvm::BasicBlock *startBB = Builder.GetInsertBlock();
- llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
- value = CGF.EmitToMemory(value, type);
- Builder.CreateBr(opBB);
- Builder.SetInsertPoint(opBB);
- atomicPHI = Builder.CreatePHI(value->getType(), 2);
- atomicPHI->addIncoming(value, startBB);
- value = atomicPHI;
- } else {
- value = EmitLoadOfLValue(LV, E->getExprLoc());
- input = value;
- }
-
- // Special case of integer increment that we have to check first: bool++.
- // Due to promotion rules, we get:
- // bool++ -> bool = bool + 1
- // -> bool = (int)bool + 1
- // -> bool = ((int)bool + 1 != 0)
- // An interesting aspect of this is that increment is always true.
- // Decrement does not have this property.
- if (isInc && type->isBooleanType()) {
- value = Builder.getTrue();
-
- // Most common case by far: integer increment.
- } else if (type->isIntegerType()) {
- // Note that signed integer inc/dec with width less than int can't
- // overflow because of promotion rules; we're just eliding a few steps here.
- if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
- value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
- } else if (E->canOverflow() && type->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
- value =
- EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc));
- } else {
- llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
- value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
- }
-
- // Next most common: pointer increment.
- } else if (const PointerType *ptr = type->getAs<PointerType>()) {
- QualType type = ptr->getPointeeType();
-
- // VLA types don't have constant size.
- if (const VariableArrayType *vla
- = CGF.getContext().getAsVariableArrayType(type)) {
- llvm::Value *numElts = CGF.getVLASize(vla).NumElts;
- if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize");
- if (CGF.getLangOpts().isSignedOverflowDefined())
- value = Builder.CreateGEP(value, numElts, "vla.inc");
- else
- value = CGF.EmitCheckedInBoundsGEP(
- value, numElts, /*SignedIndices=*/false, isSubtraction,
- E->getExprLoc(), "vla.inc");
-
- // Arithmetic on function pointers (!) is just +-1.
- } else if (type->isFunctionType()) {
- llvm::Value *amt = Builder.getInt32(amount);
-
- value = CGF.EmitCastToVoidPtr(value);
- if (CGF.getLangOpts().isSignedOverflowDefined())
- value = Builder.CreateGEP(value, amt, "incdec.funcptr");
- else
- value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false,
- isSubtraction, E->getExprLoc(),
- "incdec.funcptr");
- value = Builder.CreateBitCast(value, input->getType());
-
- // For everything else, we can just do a simple increment.
- } else {
- llvm::Value *amt = Builder.getInt32(amount);
- if (CGF.getLangOpts().isSignedOverflowDefined())
- value = Builder.CreateGEP(value, amt, "incdec.ptr");
- else
- value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false,
- isSubtraction, E->getExprLoc(),
- "incdec.ptr");
- }
-
- // Vector increment/decrement.
- } else if (type->isVectorType()) {
- if (type->hasIntegerRepresentation()) {
- llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount);
-
- value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
- } else {
- value = Builder.CreateFAdd(
- value,
- llvm::ConstantFP::get(value->getType(), amount),
- isInc ? "inc" : "dec");
- }
-
- // Floating point.
- } else if (type->isRealFloatingType()) {
- // Add the inc/dec to the real part.
- llvm::Value *amt;
-
- if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
- // Another special case: half FP increment should be done via float
- if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
- value = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
- CGF.CGM.FloatTy),
- input, "incdec.conv");
- } else {
- value = Builder.CreateFPExt(input, CGF.CGM.FloatTy, "incdec.conv");
- }
- }
-
- if (value->getType()->isFloatTy())
- amt = llvm::ConstantFP::get(VMContext,
- llvm::APFloat(static_cast<float>(amount)));
- else if (value->getType()->isDoubleTy())
- amt = llvm::ConstantFP::get(VMContext,
- llvm::APFloat(static_cast<double>(amount)));
- else {
- // Remaining types are Half, LongDouble or __float128. Convert from float.
- llvm::APFloat F(static_cast<float>(amount));
- bool ignored;
- const llvm::fltSemantics *FS;
- // Don't use getFloatTypeSemantics because Half isn't
- // necessarily represented using the "half" LLVM type.
- if (value->getType()->isFP128Ty())
- FS = &CGF.getTarget().getFloat128Format();
- else if (value->getType()->isHalfTy())
- FS = &CGF.getTarget().getHalfFormat();
- else
- FS = &CGF.getTarget().getLongDoubleFormat();
- F.convert(*FS, llvm::APFloat::rmTowardZero, &ignored);
- amt = llvm::ConstantFP::get(VMContext, F);
- }
- value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
-
- if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
- if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
- value = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16,
- CGF.CGM.FloatTy),
- value, "incdec.conv");
- } else {
- value = Builder.CreateFPTrunc(value, input->getType(), "incdec.conv");
- }
- }
-
- // Objective-C pointer types.
- } else {
- const ObjCObjectPointerType *OPT = type->castAs<ObjCObjectPointerType>();
- value = CGF.EmitCastToVoidPtr(value);
-
- CharUnits size = CGF.getContext().getTypeSizeInChars(OPT->getObjectType());
- if (!isInc) size = -size;
- llvm::Value *sizeValue =
- llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity());
-
- if (CGF.getLangOpts().isSignedOverflowDefined())
- value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
- else
- value = CGF.EmitCheckedInBoundsGEP(value, sizeValue,
- /*SignedIndices=*/false, isSubtraction,
- E->getExprLoc(), "incdec.objptr");
- value = Builder.CreateBitCast(value, input->getType());
- }
-
- if (atomicPHI) {
- llvm::BasicBlock *opBB = Builder.GetInsertBlock();
- llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- auto Pair = CGF.EmitAtomicCompareExchange(
- LV, RValue::get(atomicPHI), RValue::get(value), E->getExprLoc());
- llvm::Value *old = CGF.EmitToMemory(Pair.first.getScalarVal(), type);
- llvm::Value *success = Pair.second;
- atomicPHI->addIncoming(old, opBB);
- Builder.CreateCondBr(success, contBB, opBB);
- Builder.SetInsertPoint(contBB);
- return isPre ? value : input;
- }
-
- // Store the updated result through the lvalue.
- if (LV.isBitField())
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value);
- else
- CGF.EmitStoreThroughLValue(RValue::get(value), LV);
-
- // If this is a postinc, return the value read from memory, otherwise use the
- // updated value.
- return isPre ? value : input;
-}
-
-
-
-Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
- TestAndClearIgnoreResultAssign();
- // Emit unary minus with EmitSub so we handle overflow cases etc.
- BinOpInfo BinOp;
- BinOp.RHS = Visit(E->getSubExpr());
-
- if (BinOp.RHS->getType()->isFPOrFPVectorTy())
- BinOp.LHS = llvm::ConstantFP::getZeroValueForNegation(BinOp.RHS->getType());
- else
- BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
- BinOp.Ty = E->getType();
- BinOp.Opcode = BO_Sub;
- // FIXME: once UnaryOperator carries FPFeatures, copy it here.
- BinOp.E = E;
- return EmitSub(BinOp);
-}
-
-Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
- TestAndClearIgnoreResultAssign();
- Value *Op = Visit(E->getSubExpr());
- return Builder.CreateNot(Op, "neg");
-}
-
-Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
- // Perform vector logical not on comparison with zero vector.
- if (E->getType()->isExtVectorType()) {
- Value *Oper = Visit(E->getSubExpr());
- Value *Zero = llvm::Constant::getNullValue(Oper->getType());
- Value *Result;
- if (Oper->getType()->isFPOrFPVectorTy())
- Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp");
- else
- Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
- return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
- }
-
- // Compare operand to zero.
- Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr());
-
- // Invert value.
- // TODO: Could dynamically modify easy computations here. For example, if
- // the operand is an icmp ne, turn into icmp eq.
- BoolVal = Builder.CreateNot(BoolVal, "lnot");
-
- // ZExt result to the expr type.
- return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext");
-}
-
-Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
- // Try folding the offsetof to a constant.
- Expr::EvalResult EVResult;
- if (E->EvaluateAsInt(EVResult, CGF.getContext())) {
- llvm::APSInt Value = EVResult.Val.getInt();
- return Builder.getInt(Value);
- }
-
- // Loop over the components of the offsetof to compute the value.
- unsigned n = E->getNumComponents();
- llvm::Type* ResultType = ConvertType(E->getType());
- llvm::Value* Result = llvm::Constant::getNullValue(ResultType);
- QualType CurrentType = E->getTypeSourceInfo()->getType();
- for (unsigned i = 0; i != n; ++i) {
- OffsetOfNode ON = E->getComponent(i);
- llvm::Value *Offset = nullptr;
- switch (ON.getKind()) {
- case OffsetOfNode::Array: {
- // Compute the index
- Expr *IdxExpr = E->getIndexExpr(ON.getArrayExprIndex());
- llvm::Value* Idx = CGF.EmitScalarExpr(IdxExpr);
- bool IdxSigned = IdxExpr->getType()->isSignedIntegerOrEnumerationType();
- Idx = Builder.CreateIntCast(Idx, ResultType, IdxSigned, "conv");
-
- // Save the element type
- CurrentType =
- CGF.getContext().getAsArrayType(CurrentType)->getElementType();
-
- // Compute the element size
- llvm::Value* ElemSize = llvm::ConstantInt::get(ResultType,
- CGF.getContext().getTypeSizeInChars(CurrentType).getQuantity());
-
- // Multiply out to compute the result
- Offset = Builder.CreateMul(Idx, ElemSize);
- break;
- }
-
- case OffsetOfNode::Field: {
- FieldDecl *MemberDecl = ON.getField();
- RecordDecl *RD = CurrentType->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
-
- // Compute the index of the field in its parent.
- unsigned i = 0;
- // FIXME: It would be nice if we didn't have to loop here!
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field, ++i) {
- if (*Field == MemberDecl)
- break;
- }
- assert(i < RL.getFieldCount() && "offsetof field in wrong type");
-
- // Compute the offset to the field
- int64_t OffsetInt = RL.getFieldOffset(i) /
- CGF.getContext().getCharWidth();
- Offset = llvm::ConstantInt::get(ResultType, OffsetInt);
-
- // Save the element type.
- CurrentType = MemberDecl->getType();
- break;
- }
-
- case OffsetOfNode::Identifier:
- llvm_unreachable("dependent __builtin_offsetof");
-
- case OffsetOfNode::Base: {
- if (ON.getBase()->isVirtual()) {
- CGF.ErrorUnsupported(E, "virtual base in offsetof");
- continue;
- }
-
- RecordDecl *RD = CurrentType->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
-
- // Save the element type.
- CurrentType = ON.getBase()->getType();
-
- // Compute the offset to the base.
- const RecordType *BaseRT = CurrentType->getAs<RecordType>();
- CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
- CharUnits OffsetInt = RL.getBaseClassOffset(BaseRD);
- Offset = llvm::ConstantInt::get(ResultType, OffsetInt.getQuantity());
- break;
- }
- }
- Result = Builder.CreateAdd(Result, Offset);
- }
- return Result;
-}
-
-/// VisitUnaryExprOrTypeTraitExpr - Return the size or alignment of the type of
-/// argument of the sizeof expression as an integer.
-Value *
-ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
- const UnaryExprOrTypeTraitExpr *E) {
- QualType TypeToSize = E->getTypeOfArgument();
- if (E->getKind() == UETT_SizeOf) {
- if (const VariableArrayType *VAT =
- CGF.getContext().getAsVariableArrayType(TypeToSize)) {
- if (E->isArgumentType()) {
- // sizeof(type) - make sure to emit the VLA size.
- CGF.EmitVariablyModifiedType(TypeToSize);
- } else {
- // C99 6.5.3.4p2: If the argument is an expression of type
- // VLA, it is evaluated.
- CGF.EmitIgnoredExpr(E->getArgumentExpr());
- }
-
- auto VlaSize = CGF.getVLASize(VAT);
- llvm::Value *size = VlaSize.NumElts;
-
- // Scale the number of non-VLA elements by the non-VLA element size.
- CharUnits eltSize = CGF.getContext().getTypeSizeInChars(VlaSize.Type);
- if (!eltSize.isOne())
- size = CGF.Builder.CreateNUWMul(CGF.CGM.getSize(eltSize), size);
-
- return size;
- }
- } else if (E->getKind() == UETT_OpenMPRequiredSimdAlign) {
- auto Alignment =
- CGF.getContext()
- .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign(
- E->getTypeOfArgument()->getPointeeType()))
- .getQuantity();
- return llvm::ConstantInt::get(CGF.SizeTy, Alignment);
- }
-
- // If this isn't sizeof(vla), the result must be constant; use the constant
- // folding logic so we don't have to duplicate it here.
- return Builder.getInt(E->EvaluateKnownConstInt(CGF.getContext()));
-}
-
-Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
- Expr *Op = E->getSubExpr();
- if (Op->getType()->isAnyComplexType()) {
- // If it's an l-value, load through the appropriate subobject l-value.
- // Note that we have to ask E because Op might be an l-value that
- // this won't work for, e.g. an Obj-C property.
- if (E->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E),
- E->getExprLoc()).getScalarVal();
-
- // Otherwise, calculate and project.
- return CGF.EmitComplexExpr(Op, false, true).first;
- }
-
- return Visit(Op);
-}
-
-Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
- Expr *Op = E->getSubExpr();
- if (Op->getType()->isAnyComplexType()) {
- // If it's an l-value, load through the appropriate subobject l-value.
- // Note that we have to ask E because Op might be an l-value that
- // this won't work for, e.g. an Obj-C property.
- if (Op->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E),
- E->getExprLoc()).getScalarVal();
-
- // Otherwise, calculate and project.
- return CGF.EmitComplexExpr(Op, true, false).second;
- }
-
- // __imag on a scalar returns zero. Emit the subexpr to ensure side
- // effects are evaluated, but not the actual value.
- if (Op->isGLValue())
- CGF.EmitLValue(Op);
- else
- CGF.EmitScalarExpr(Op, true);
- return llvm::Constant::getNullValue(ConvertType(E->getType()));
-}
-
-//===----------------------------------------------------------------------===//
-// Binary Operators
-//===----------------------------------------------------------------------===//
-
-BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
- TestAndClearIgnoreResultAssign();
- BinOpInfo Result;
- Result.LHS = Visit(E->getLHS());
- Result.RHS = Visit(E->getRHS());
- Result.Ty = E->getType();
- Result.Opcode = E->getOpcode();
- Result.FPFeatures = E->getFPFeatures();
- Result.E = E;
- return Result;
-}
-
-LValue ScalarExprEmitter::EmitCompoundAssignLValue(
- const CompoundAssignOperator *E,
- Value *(ScalarExprEmitter::*Func)(const BinOpInfo &),
- Value *&Result) {
- QualType LHSTy = E->getLHS()->getType();
- BinOpInfo OpInfo;
-
- if (E->getComputationResultType()->isAnyComplexType())
- return CGF.EmitScalarCompoundAssignWithComplex(E, Result);
-
- // Emit the RHS first. __block variables need to have the rhs evaluated
- // first, plus this should improve codegen a little.
- OpInfo.RHS = Visit(E->getRHS());
- OpInfo.Ty = E->getComputationResultType();
- OpInfo.Opcode = E->getOpcode();
- OpInfo.FPFeatures = E->getFPFeatures();
- OpInfo.E = E;
- // Load/convert the LHS.
- LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
-
- llvm::PHINode *atomicPHI = nullptr;
- if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
- QualType type = atomicTy->getValueType();
- if (!type->isBooleanType() && type->isIntegerType() &&
- !(type->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
- CGF.getLangOpts().getSignedOverflowBehavior() !=
- LangOptions::SOB_Trapping) {
- llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP;
- switch (OpInfo.Opcode) {
- // We don't have atomicrmw operands for *, %, /, <<, >>
- case BO_MulAssign: case BO_DivAssign:
- case BO_RemAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- break;
- case BO_AddAssign:
- aop = llvm::AtomicRMWInst::Add;
- break;
- case BO_SubAssign:
- aop = llvm::AtomicRMWInst::Sub;
- break;
- case BO_AndAssign:
- aop = llvm::AtomicRMWInst::And;
- break;
- case BO_XorAssign:
- aop = llvm::AtomicRMWInst::Xor;
- break;
- case BO_OrAssign:
- aop = llvm::AtomicRMWInst::Or;
- break;
- default:
- llvm_unreachable("Invalid compound assignment type");
- }
- if (aop != llvm::AtomicRMWInst::BAD_BINOP) {
- llvm::Value *amt = CGF.EmitToMemory(
- EmitScalarConversion(OpInfo.RHS, E->getRHS()->getType(), LHSTy,
- E->getExprLoc()),
- LHSTy);
- Builder.CreateAtomicRMW(aop, LHSLV.getPointer(), amt,
- llvm::AtomicOrdering::SequentiallyConsistent);
- return LHSLV;
- }
- }
- // FIXME: For floating point types, we should be saving and restoring the
- // floating point environment in the loop.
- llvm::BasicBlock *startBB = Builder.GetInsertBlock();
- llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
- OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc());
- OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, type);
- Builder.CreateBr(opBB);
- Builder.SetInsertPoint(opBB);
- atomicPHI = Builder.CreatePHI(OpInfo.LHS->getType(), 2);
- atomicPHI->addIncoming(OpInfo.LHS, startBB);
- OpInfo.LHS = atomicPHI;
- }
- else
- OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc());
-
- SourceLocation Loc = E->getExprLoc();
- OpInfo.LHS =
- EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType(), Loc);
-
- // Expand the binary operator.
- Result = (this->*Func)(OpInfo);
-
- // Convert the result back to the LHS type,
- // potentially with Implicit Conversion sanitizer check.
- Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy,
- Loc, ScalarConversionOpts(CGF.SanOpts));
-
- if (atomicPHI) {
- llvm::BasicBlock *opBB = Builder.GetInsertBlock();
- llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- auto Pair = CGF.EmitAtomicCompareExchange(
- LHSLV, RValue::get(atomicPHI), RValue::get(Result), E->getExprLoc());
- llvm::Value *old = CGF.EmitToMemory(Pair.first.getScalarVal(), LHSTy);
- llvm::Value *success = Pair.second;
- atomicPHI->addIncoming(old, opBB);
- Builder.CreateCondBr(success, contBB, opBB);
- Builder.SetInsertPoint(contBB);
- return LHSLV;
- }
-
- // Store the result value into the LHS lvalue. Bit-fields are handled
- // specially because the result is altered by the store, i.e., [C99 6.5.16p1]
- // 'An assignment expression has the value of the left operand after the
- // assignment...'.
- if (LHSLV.isBitField())
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, &Result);
- else
- CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV);
-
- return LHSLV;
-}
-
-Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
- Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
- bool Ignore = TestAndClearIgnoreResultAssign();
- Value *RHS;
- LValue LHS = EmitCompoundAssignLValue(E, Func, RHS);
-
- // If the result is clearly ignored, return now.
- if (Ignore)
- return nullptr;
-
- // The result of an assignment in C is the assigned r-value.
- if (!CGF.getLangOpts().CPlusPlus)
- return RHS;
-
- // If the lvalue is non-volatile, return the computed value of the assignment.
- if (!LHS.isVolatileQualified())
- return RHS;
-
- // Otherwise, reload the value.
- return EmitLoadOfLValue(LHS, E->getExprLoc());
-}
-
-void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
- const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
- SmallVector<std::pair<llvm::Value *, SanitizerMask>, 2> Checks;
-
- if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) {
- Checks.push_back(std::make_pair(Builder.CreateICmpNE(Ops.RHS, Zero),
- SanitizerKind::IntegerDivideByZero));
- }
-
- const auto *BO = cast<BinaryOperator>(Ops.E);
- if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) &&
- Ops.Ty->hasSignedIntegerRepresentation() &&
- !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS()) &&
- Ops.mayHaveIntegerOverflow()) {
- llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
-
- llvm::Value *IntMin =
- Builder.getInt(llvm::APInt::getSignedMinValue(Ty->getBitWidth()));
- llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL);
-
- llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin);
- llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne);
- llvm::Value *NotOverflow = Builder.CreateOr(LHSCmp, RHSCmp, "or");
- Checks.push_back(
- std::make_pair(NotOverflow, SanitizerKind::SignedIntegerOverflow));
- }
-
- if (Checks.size() > 0)
- EmitBinOpCheck(Checks, Ops);
-}
-
-Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
- if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) ||
- CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
- Ops.Ty->isIntegerType() &&
- (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) {
- llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- } else if (CGF.SanOpts.has(SanitizerKind::FloatDivideByZero) &&
- Ops.Ty->isRealFloatingType() &&
- Ops.mayHaveFloatDivisionByZero()) {
- llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- llvm::Value *NonZero = Builder.CreateFCmpUNE(Ops.RHS, Zero);
- EmitBinOpCheck(std::make_pair(NonZero, SanitizerKind::FloatDivideByZero),
- Ops);
- }
- }
-
- if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
- llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
- if (CGF.getLangOpts().OpenCL &&
- !CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) {
- // OpenCL v1.1 s7.4: minimum accuracy of single precision / is 2.5ulp
- // OpenCL v1.2 s5.6.4.2: The -cl-fp32-correctly-rounded-divide-sqrt
- // build option allows an application to specify that single precision
- // floating-point divide (x/y and 1/x) and sqrt used in the program
- // source are correctly rounded.
- llvm::Type *ValTy = Val->getType();
- if (ValTy->isFloatTy() ||
- (isa<llvm::VectorType>(ValTy) &&
- cast<llvm::VectorType>(ValTy)->getElementType()->isFloatTy()))
- CGF.SetFPAccuracy(Val, 2.5);
- }
- return Val;
- }
- else if (Ops.Ty->hasUnsignedIntegerRepresentation())
- return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div");
- else
- return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div");
-}
-
-Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
- // Rem in C can't be a floating point type: C99 6.5.5p2.
- if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) ||
- CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
- Ops.Ty->isIntegerType() &&
- (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
- llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
- }
-
- if (Ops.Ty->hasUnsignedIntegerRepresentation())
- return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem");
- else
- return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem");
-}
-
-Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
- unsigned IID;
- unsigned OpID = 0;
-
- bool isSigned = Ops.Ty->isSignedIntegerOrEnumerationType();
- switch (Ops.Opcode) {
- case BO_Add:
- case BO_AddAssign:
- OpID = 1;
- IID = isSigned ? llvm::Intrinsic::sadd_with_overflow :
- llvm::Intrinsic::uadd_with_overflow;
- break;
- case BO_Sub:
- case BO_SubAssign:
- OpID = 2;
- IID = isSigned ? llvm::Intrinsic::ssub_with_overflow :
- llvm::Intrinsic::usub_with_overflow;
- break;
- case BO_Mul:
- case BO_MulAssign:
- OpID = 3;
- IID = isSigned ? llvm::Intrinsic::smul_with_overflow :
- llvm::Intrinsic::umul_with_overflow;
- break;
- default:
- llvm_unreachable("Unsupported operation for overflow detection");
- }
- OpID <<= 1;
- if (isSigned)
- OpID |= 1;
-
- CodeGenFunction::SanitizerScope SanScope(&CGF);
- llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
-
- llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, opTy);
-
- Value *resultAndOverflow = Builder.CreateCall(intrinsic, {Ops.LHS, Ops.RHS});
- Value *result = Builder.CreateExtractValue(resultAndOverflow, 0);
- Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1);
-
- // Handle overflow with llvm.trap if no custom handler has been specified.
- const std::string *handlerName =
- &CGF.getLangOpts().OverflowHandler;
- if (handlerName->empty()) {
- // If the signed-integer-overflow sanitizer is enabled, emit a call to its
- // runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
- if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) {
- llvm::Value *NotOverflow = Builder.CreateNot(overflow);
- SanitizerMask Kind = isSigned ? SanitizerKind::SignedIntegerOverflow
- : SanitizerKind::UnsignedIntegerOverflow;
- EmitBinOpCheck(std::make_pair(NotOverflow, Kind), Ops);
- } else
- CGF.EmitTrapCheck(Builder.CreateNot(overflow));
- return result;
- }
-
- // Branch in case of overflow.
- llvm::BasicBlock *initialBB = Builder.GetInsertBlock();
- llvm::BasicBlock *continueBB =
- CGF.createBasicBlock("nooverflow", CGF.CurFn, initialBB->getNextNode());
- llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
-
- Builder.CreateCondBr(overflow, overflowBB, continueBB);
-
- // If an overflow handler is set, then we want to call it and then use its
- // result, if it returns.
- Builder.SetInsertPoint(overflowBB);
-
- // Get the overflow handler.
- llvm::Type *Int8Ty = CGF.Int8Ty;
- llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty };
- llvm::FunctionType *handlerTy =
- llvm::FunctionType::get(CGF.Int64Ty, argTypes, true);
- llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName);
-
- // Sign extend the args to 64-bit, so that we can use the same handler for
- // all types of overflow.
- llvm::Value *lhs = Builder.CreateSExt(Ops.LHS, CGF.Int64Ty);
- llvm::Value *rhs = Builder.CreateSExt(Ops.RHS, CGF.Int64Ty);
-
- // Call the handler with the two arguments, the operation, and the size of
- // the result.
- llvm::Value *handlerArgs[] = {
- lhs,
- rhs,
- Builder.getInt8(OpID),
- Builder.getInt8(cast<llvm::IntegerType>(opTy)->getBitWidth())
- };
- llvm::Value *handlerResult =
- CGF.EmitNounwindRuntimeCall(handler, handlerArgs);
-
- // Truncate the result back to the desired size.
- handlerResult = Builder.CreateTrunc(handlerResult, opTy);
- Builder.CreateBr(continueBB);
-
- Builder.SetInsertPoint(continueBB);
- llvm::PHINode *phi = Builder.CreatePHI(opTy, 2);
- phi->addIncoming(result, initialBB);
- phi->addIncoming(handlerResult, overflowBB);
-
- return phi;
-}
-
-/// Emit pointer + index arithmetic.
-static Value *emitPointerArithmetic(CodeGenFunction &CGF,
- const BinOpInfo &op,
- bool isSubtraction) {
- // Must have binary (not unary) expr here. Unary pointer
- // increment/decrement doesn't use this path.
- const BinaryOperator *expr = cast<BinaryOperator>(op.E);
-
- Value *pointer = op.LHS;
- Expr *pointerOperand = expr->getLHS();
- Value *index = op.RHS;
- Expr *indexOperand = expr->getRHS();
-
- // In a subtraction, the LHS is always the pointer.
- if (!isSubtraction && !pointer->getType()->isPointerTy()) {
- std::swap(pointer, index);
- std::swap(pointerOperand, indexOperand);
- }
-
- bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
-
- unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
- auto &DL = CGF.CGM.getDataLayout();
- auto PtrTy = cast<llvm::PointerType>(pointer->getType());
-
- // Some versions of glibc and gcc use idioms (particularly in their malloc
- // routines) that add a pointer-sized integer (known to be a pointer value)
- // to a null pointer in order to cast the value back to an integer or as
- // part of a pointer alignment algorithm. This is undefined behavior, but
- // we'd like to be able to compile programs that use it.
- //
- // Normally, we'd generate a GEP with a null-pointer base here in response
- // to that code, but it's also UB to dereference a pointer created that
- // way. Instead (as an acknowledged hack to tolerate the idiom) we will
- // generate a direct cast of the integer value to a pointer.
- //
- // The idiom (p = nullptr + N) is not met if any of the following are true:
- //
- // The operation is subtraction.
- // The index is not pointer-sized.
- // The pointer type is not byte-sized.
- //
- if (BinaryOperator::isNullPointerArithmeticExtension(CGF.getContext(),
- op.Opcode,
- expr->getLHS(),
- expr->getRHS()))
- return CGF.Builder.CreateIntToPtr(index, pointer->getType());
-
- if (width != DL.getTypeSizeInBits(PtrTy)) {
- // Zero-extend or sign-extend the pointer value according to
- // whether the index is signed or not.
- index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned,
- "idx.ext");
- }
-
- // If this is subtraction, negate the index.
- if (isSubtraction)
- index = CGF.Builder.CreateNeg(index, "idx.neg");
-
- if (CGF.SanOpts.has(SanitizerKind::ArrayBounds))
- CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
- /*Accessed*/ false);
-
- const PointerType *pointerType
- = pointerOperand->getType()->getAs<PointerType>();
- if (!pointerType) {
- QualType objectType = pointerOperand->getType()
- ->castAs<ObjCObjectPointerType>()
- ->getPointeeType();
- llvm::Value *objectSize
- = CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(objectType));
-
- index = CGF.Builder.CreateMul(index, objectSize);
-
- Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy);
- result = CGF.Builder.CreateGEP(result, index, "add.ptr");
- return CGF.Builder.CreateBitCast(result, pointer->getType());
- }
-
- QualType elementType = pointerType->getPointeeType();
- if (const VariableArrayType *vla
- = CGF.getContext().getAsVariableArrayType(elementType)) {
- // The element count here is the total number of non-VLA elements.
- llvm::Value *numElements = CGF.getVLASize(vla).NumElts;
-
- // Effectively, the multiply by the VLA size is part of the GEP.
- // GEP indexes are signed, and scaling an index isn't permitted to
- // signed-overflow, so we use the same semantics for our explicit
- // multiply. We suppress this if overflow is not undefined behavior.
- if (CGF.getLangOpts().isSignedOverflowDefined()) {
- index = CGF.Builder.CreateMul(index, numElements, "vla.index");
- pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");
- } else {
- index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
- pointer =
- CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction,
- op.E->getExprLoc(), "add.ptr");
- }
- return pointer;
- }
-
- // Explicitly handle GNU void* and function pointer arithmetic extensions. The
- // GNU void* casts amount to no-ops since our void* type is i8*, but this is
- // future proof.
- if (elementType->isVoidType() || elementType->isFunctionType()) {
- Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy);
- result = CGF.Builder.CreateGEP(result, index, "add.ptr");
- return CGF.Builder.CreateBitCast(result, pointer->getType());
- }
-
- if (CGF.getLangOpts().isSignedOverflowDefined())
- return CGF.Builder.CreateGEP(pointer, index, "add.ptr");
-
- return CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction,
- op.E->getExprLoc(), "add.ptr");
-}
-
-// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and
-// Addend. Use negMul and negAdd to negate the first operand of the Mul or
-// the add operand respectively. This allows fmuladd to represent a*b-c, or
-// c-a*b. Patterns in LLVM should catch the negated forms and translate them to
-// efficient operations.
-static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend,
- const CodeGenFunction &CGF, CGBuilderTy &Builder,
- bool negMul, bool negAdd) {
- assert(!(negMul && negAdd) && "Only one of negMul and negAdd should be set.");
-
- Value *MulOp0 = MulOp->getOperand(0);
- Value *MulOp1 = MulOp->getOperand(1);
- if (negMul) {
- MulOp0 =
- Builder.CreateFSub(
- llvm::ConstantFP::getZeroValueForNegation(MulOp0->getType()), MulOp0,
- "neg");
- } else if (negAdd) {
- Addend =
- Builder.CreateFSub(
- llvm::ConstantFP::getZeroValueForNegation(Addend->getType()), Addend,
- "neg");
- }
-
- Value *FMulAdd = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, Addend->getType()),
- {MulOp0, MulOp1, Addend});
- MulOp->eraseFromParent();
-
- return FMulAdd;
-}
-
-// Check whether it would be legal to emit an fmuladd intrinsic call to
-// represent op and if so, build the fmuladd.
-//
-// Checks that (a) the operation is fusable, and (b) -ffp-contract=on.
-// Does NOT check the type of the operation - it's assumed that this function
-// will be called from contexts where it's known that the type is contractable.
-static Value* tryEmitFMulAdd(const BinOpInfo &op,
- const CodeGenFunction &CGF, CGBuilderTy &Builder,
- bool isSub=false) {
-
- assert((op.Opcode == BO_Add || op.Opcode == BO_AddAssign ||
- op.Opcode == BO_Sub || op.Opcode == BO_SubAssign) &&
- "Only fadd/fsub can be the root of an fmuladd.");
-
- // Check whether this op is marked as fusable.
- if (!op.FPFeatures.allowFPContractWithinStatement())
- return nullptr;
-
- // We have a potentially fusable op. Look for a mul on one of the operands.
- // Also, make sure that the mul result isn't used directly. In that case,
- // there's no point creating a muladd operation.
- if (auto *LHSBinOp = dyn_cast<llvm::BinaryOperator>(op.LHS)) {
- if (LHSBinOp->getOpcode() == llvm::Instruction::FMul &&
- LHSBinOp->use_empty())
- return buildFMulAdd(LHSBinOp, op.RHS, CGF, Builder, false, isSub);
- }
- if (auto *RHSBinOp = dyn_cast<llvm::BinaryOperator>(op.RHS)) {
- if (RHSBinOp->getOpcode() == llvm::Instruction::FMul &&
- RHSBinOp->use_empty())
- return buildFMulAdd(RHSBinOp, op.LHS, CGF, Builder, isSub, false);
- }
-
- return nullptr;
-}
-
-Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
- if (op.LHS->getType()->isPointerTy() ||
- op.RHS->getType()->isPointerTy())
- return emitPointerArithmetic(CGF, op, CodeGenFunction::NotSubtraction);
-
- if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Defined:
- return Builder.CreateAdd(op.LHS, op.RHS, "add");
- case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
- return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
- LLVM_FALLTHROUGH;
- case LangOptions::SOB_Trapping:
- if (CanElideOverflowCheck(CGF.getContext(), op))
- return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
- return EmitOverflowCheckedBinOp(op);
- }
- }
-
- if (op.Ty->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
- !CanElideOverflowCheck(CGF.getContext(), op))
- return EmitOverflowCheckedBinOp(op);
-
- if (op.LHS->getType()->isFPOrFPVectorTy()) {
- // Try to form an fmuladd.
- if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
- return FMulAdd;
-
- Value *V = Builder.CreateFAdd(op.LHS, op.RHS, "add");
- return propagateFMFlags(V, op);
- }
-
- return Builder.CreateAdd(op.LHS, op.RHS, "add");
-}
-
-Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
- // The LHS is always a pointer if either side is.
- if (!op.LHS->getType()->isPointerTy()) {
- if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Defined:
- return Builder.CreateSub(op.LHS, op.RHS, "sub");
- case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
- return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
- LLVM_FALLTHROUGH;
- case LangOptions::SOB_Trapping:
- if (CanElideOverflowCheck(CGF.getContext(), op))
- return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
- return EmitOverflowCheckedBinOp(op);
- }
- }
-
- if (op.Ty->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
- !CanElideOverflowCheck(CGF.getContext(), op))
- return EmitOverflowCheckedBinOp(op);
-
- if (op.LHS->getType()->isFPOrFPVectorTy()) {
- // Try to form an fmuladd.
- if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
- return FMulAdd;
- Value *V = Builder.CreateFSub(op.LHS, op.RHS, "sub");
- return propagateFMFlags(V, op);
- }
-
- return Builder.CreateSub(op.LHS, op.RHS, "sub");
- }
-
- // If the RHS is not a pointer, then we have normal pointer
- // arithmetic.
- if (!op.RHS->getType()->isPointerTy())
- return emitPointerArithmetic(CGF, op, CodeGenFunction::IsSubtraction);
-
- // Otherwise, this is a pointer subtraction.
-
- // Do the raw subtraction part.
- llvm::Value *LHS
- = Builder.CreatePtrToInt(op.LHS, CGF.PtrDiffTy, "sub.ptr.lhs.cast");
- llvm::Value *RHS
- = Builder.CreatePtrToInt(op.RHS, CGF.PtrDiffTy, "sub.ptr.rhs.cast");
- Value *diffInChars = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
-
- // Okay, figure out the element size.
- const BinaryOperator *expr = cast<BinaryOperator>(op.E);
- QualType elementType = expr->getLHS()->getType()->getPointeeType();
-
- llvm::Value *divisor = nullptr;
-
- // For a variable-length array, this is going to be non-constant.
- if (const VariableArrayType *vla
- = CGF.getContext().getAsVariableArrayType(elementType)) {
- auto VlaSize = CGF.getVLASize(vla);
- elementType = VlaSize.Type;
- divisor = VlaSize.NumElts;
-
- // Scale the number of non-VLA elements by the non-VLA element size.
- CharUnits eltSize = CGF.getContext().getTypeSizeInChars(elementType);
- if (!eltSize.isOne())
- divisor = CGF.Builder.CreateNUWMul(CGF.CGM.getSize(eltSize), divisor);
-
- // For everything elese, we can just compute it, safe in the
- // assumption that Sema won't let anything through that we can't
- // safely compute the size of.
- } else {
- CharUnits elementSize;
- // Handle GCC extension for pointer arithmetic on void* and
- // function pointer types.
- if (elementType->isVoidType() || elementType->isFunctionType())
- elementSize = CharUnits::One();
- else
- elementSize = CGF.getContext().getTypeSizeInChars(elementType);
-
- // Don't even emit the divide for element size of 1.
- if (elementSize.isOne())
- return diffInChars;
-
- divisor = CGF.CGM.getSize(elementSize);
- }
-
- // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
- // pointer difference in C is only defined in the case where both operands
- // are pointing to elements of an array.
- return Builder.CreateExactSDiv(diffInChars, divisor, "sub.ptr.div");
-}
-
-Value *ScalarExprEmitter::GetWidthMinusOneValue(Value* LHS,Value* RHS) {
- llvm::IntegerType *Ty;
- if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(LHS->getType()))
- Ty = cast<llvm::IntegerType>(VT->getElementType());
- else
- Ty = cast<llvm::IntegerType>(LHS->getType());
- return llvm::ConstantInt::get(RHS->getType(), Ty->getBitWidth() - 1);
-}
-
-Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
- // LLVM requires the LHS and RHS to be the same type: promote or truncate the
- // RHS to the same size as the LHS.
- Value *RHS = Ops.RHS;
- if (Ops.LHS->getType() != RHS->getType())
- RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
-
- bool SanitizeBase = CGF.SanOpts.has(SanitizerKind::ShiftBase) &&
- Ops.Ty->hasSignedIntegerRepresentation() &&
- !CGF.getLangOpts().isSignedOverflowDefined();
- bool SanitizeExponent = CGF.SanOpts.has(SanitizerKind::ShiftExponent);
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- if (CGF.getLangOpts().OpenCL)
- RHS =
- Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shl.mask");
- else if ((SanitizeBase || SanitizeExponent) &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
- SmallVector<std::pair<Value *, SanitizerMask>, 2> Checks;
- llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, Ops.RHS);
- llvm::Value *ValidExponent = Builder.CreateICmpULE(Ops.RHS, WidthMinusOne);
-
- if (SanitizeExponent) {
- Checks.push_back(
- std::make_pair(ValidExponent, SanitizerKind::ShiftExponent));
- }
-
- if (SanitizeBase) {
- // Check whether we are shifting any non-zero bits off the top of the
- // integer. We only emit this check if exponent is valid - otherwise
- // instructions below will have undefined behavior themselves.
- llvm::BasicBlock *Orig = Builder.GetInsertBlock();
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- llvm::BasicBlock *CheckShiftBase = CGF.createBasicBlock("check");
- Builder.CreateCondBr(ValidExponent, CheckShiftBase, Cont);
- llvm::Value *PromotedWidthMinusOne =
- (RHS == Ops.RHS) ? WidthMinusOne
- : GetWidthMinusOneValue(Ops.LHS, RHS);
- CGF.EmitBlock(CheckShiftBase);
- llvm::Value *BitsShiftedOff = Builder.CreateLShr(
- Ops.LHS, Builder.CreateSub(PromotedWidthMinusOne, RHS, "shl.zeros",
- /*NUW*/ true, /*NSW*/ true),
- "shl.check");
- if (CGF.getLangOpts().CPlusPlus) {
- // In C99, we are not permitted to shift a 1 bit into the sign bit.
- // Under C++11's rules, shifting a 1 bit into the sign bit is
- // OK, but shifting a 1 bit out of it is not. (C89 and C++03 don't
- // define signed left shifts, so we use the C99 and C++11 rules there).
- llvm::Value *One = llvm::ConstantInt::get(BitsShiftedOff->getType(), 1);
- BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One);
- }
- llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0);
- llvm::Value *ValidBase = Builder.CreateICmpEQ(BitsShiftedOff, Zero);
- CGF.EmitBlock(Cont);
- llvm::PHINode *BaseCheck = Builder.CreatePHI(ValidBase->getType(), 2);
- BaseCheck->addIncoming(Builder.getTrue(), Orig);
- BaseCheck->addIncoming(ValidBase, CheckShiftBase);
- Checks.push_back(std::make_pair(BaseCheck, SanitizerKind::ShiftBase));
- }
-
- assert(!Checks.empty());
- EmitBinOpCheck(Checks, Ops);
- }
-
- return Builder.CreateShl(Ops.LHS, RHS, "shl");
-}
-
-Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
- // LLVM requires the LHS and RHS to be the same type: promote or truncate the
- // RHS to the same size as the LHS.
- Value *RHS = Ops.RHS;
- if (Ops.LHS->getType() != RHS->getType())
- RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
-
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- if (CGF.getLangOpts().OpenCL)
- RHS =
- Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shr.mask");
- else if (CGF.SanOpts.has(SanitizerKind::ShiftExponent) &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
- llvm::Value *Valid =
- Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS));
- EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::ShiftExponent), Ops);
- }
-
- if (Ops.Ty->hasUnsignedIntegerRepresentation())
- return Builder.CreateLShr(Ops.LHS, RHS, "shr");
- return Builder.CreateAShr(Ops.LHS, RHS, "shr");
-}
-
-enum IntrinsicType { VCMPEQ, VCMPGT };
-// return corresponding comparison intrinsic for given vector type
-static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT,
- BuiltinType::Kind ElemKind) {
- switch (ElemKind) {
- default: llvm_unreachable("unexpected element type");
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtub_p;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtsb_p;
- case BuiltinType::UShort:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtuh_p;
- case BuiltinType::Short:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtsh_p;
- case BuiltinType::UInt:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtuw_p;
- case BuiltinType::Int:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtsw_p;
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequd_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtud_p;
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequd_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtsd_p;
- case BuiltinType::Float:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpeqfp_p :
- llvm::Intrinsic::ppc_altivec_vcmpgtfp_p;
- case BuiltinType::Double:
- return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_vsx_xvcmpeqdp_p :
- llvm::Intrinsic::ppc_vsx_xvcmpgtdp_p;
- }
-}
-
-Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
- llvm::CmpInst::Predicate UICmpOpc,
- llvm::CmpInst::Predicate SICmpOpc,
- llvm::CmpInst::Predicate FCmpOpc) {
- TestAndClearIgnoreResultAssign();
- Value *Result;
- QualType LHSTy = E->getLHS()->getType();
- QualType RHSTy = E->getRHS()->getType();
- if (const MemberPointerType *MPT = LHSTy->getAs<MemberPointerType>()) {
- assert(E->getOpcode() == BO_EQ ||
- E->getOpcode() == BO_NE);
- Value *LHS = CGF.EmitScalarExpr(E->getLHS());
- Value *RHS = CGF.EmitScalarExpr(E->getRHS());
- Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison(
- CGF, LHS, RHS, MPT, E->getOpcode() == BO_NE);
- } else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) {
- Value *LHS = Visit(E->getLHS());
- Value *RHS = Visit(E->getRHS());
-
- // If AltiVec, the comparison results in a numeric type, so we use
- // intrinsics comparing vectors and giving 0 or 1 as a result
- if (LHSTy->isVectorType() && !E->getType()->isVectorType()) {
- // constants for mapping CR6 register bits to predicate result
- enum { CR6_EQ=0, CR6_EQ_REV, CR6_LT, CR6_LT_REV } CR6;
-
- llvm::Intrinsic::ID ID = llvm::Intrinsic::not_intrinsic;
-
- // in several cases vector arguments order will be reversed
- Value *FirstVecArg = LHS,
- *SecondVecArg = RHS;
-
- QualType ElTy = LHSTy->getAs<VectorType>()->getElementType();
- const BuiltinType *BTy = ElTy->getAs<BuiltinType>();
- BuiltinType::Kind ElementKind = BTy->getKind();
-
- switch(E->getOpcode()) {
- default: llvm_unreachable("is not a comparison operation");
- case BO_EQ:
- CR6 = CR6_LT;
- ID = GetIntrinsic(VCMPEQ, ElementKind);
- break;
- case BO_NE:
- CR6 = CR6_EQ;
- ID = GetIntrinsic(VCMPEQ, ElementKind);
- break;
- case BO_LT:
- CR6 = CR6_LT;
- ID = GetIntrinsic(VCMPGT, ElementKind);
- std::swap(FirstVecArg, SecondVecArg);
- break;
- case BO_GT:
- CR6 = CR6_LT;
- ID = GetIntrinsic(VCMPGT, ElementKind);
- break;
- case BO_LE:
- if (ElementKind == BuiltinType::Float) {
- CR6 = CR6_LT;
- ID = llvm::Intrinsic::ppc_altivec_vcmpgefp_p;
- std::swap(FirstVecArg, SecondVecArg);
- }
- else {
- CR6 = CR6_EQ;
- ID = GetIntrinsic(VCMPGT, ElementKind);
- }
- break;
- case BO_GE:
- if (ElementKind == BuiltinType::Float) {
- CR6 = CR6_LT;
- ID = llvm::Intrinsic::ppc_altivec_vcmpgefp_p;
- }
- else {
- CR6 = CR6_EQ;
- ID = GetIntrinsic(VCMPGT, ElementKind);
- std::swap(FirstVecArg, SecondVecArg);
- }
- break;
- }
-
- Value *CR6Param = Builder.getInt32(CR6);
- llvm::Function *F = CGF.CGM.getIntrinsic(ID);
- Result = Builder.CreateCall(F, {CR6Param, FirstVecArg, SecondVecArg});
-
- // The result type of intrinsic may not be same as E->getType().
- // If E->getType() is not BoolTy, EmitScalarConversion will do the
- // conversion work. If E->getType() is BoolTy, EmitScalarConversion will
- // do nothing, if ResultTy is not i1 at the same time, it will cause
- // crash later.
- llvm::IntegerType *ResultTy = cast<llvm::IntegerType>(Result->getType());
- if (ResultTy->getBitWidth() > 1 &&
- E->getType() == CGF.getContext().BoolTy)
- Result = Builder.CreateTrunc(Result, Builder.getInt1Ty());
- return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType(),
- E->getExprLoc());
- }
-
- if (LHS->getType()->isFPOrFPVectorTy()) {
- Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
- } else if (LHSTy->hasSignedIntegerRepresentation()) {
- Result = Builder.CreateICmp(SICmpOpc, LHS, RHS, "cmp");
- } else {
- // Unsigned integers and pointers.
-
- if (CGF.CGM.getCodeGenOpts().StrictVTablePointers &&
- !isa<llvm::ConstantPointerNull>(LHS) &&
- !isa<llvm::ConstantPointerNull>(RHS)) {
-
- // Dynamic information is required to be stripped for comparisons,
- // because it could leak the dynamic information. Based on comparisons
- // of pointers to dynamic objects, the optimizer can replace one pointer
- // with another, which might be incorrect in presence of invariant
- // groups. Comparison with null is safe because null does not carry any
- // dynamic information.
- if (LHSTy.mayBeDynamicClass())
- LHS = Builder.CreateStripInvariantGroup(LHS);
- if (RHSTy.mayBeDynamicClass())
- RHS = Builder.CreateStripInvariantGroup(RHS);
- }
-
- Result = Builder.CreateICmp(UICmpOpc, LHS, RHS, "cmp");
- }
-
- // If this is a vector comparison, sign extend the result to the appropriate
- // vector integer type and return it (don't convert to bool).
- if (LHSTy->isVectorType())
- return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
-
- } else {
- // Complex Comparison: can only be an equality comparison.
- CodeGenFunction::ComplexPairTy LHS, RHS;
- QualType CETy;
- if (auto *CTy = LHSTy->getAs<ComplexType>()) {
- LHS = CGF.EmitComplexExpr(E->getLHS());
- CETy = CTy->getElementType();
- } else {
- LHS.first = Visit(E->getLHS());
- LHS.second = llvm::Constant::getNullValue(LHS.first->getType());
- CETy = LHSTy;
- }
- if (auto *CTy = RHSTy->getAs<ComplexType>()) {
- RHS = CGF.EmitComplexExpr(E->getRHS());
- assert(CGF.getContext().hasSameUnqualifiedType(CETy,
- CTy->getElementType()) &&
- "The element types must always match.");
- (void)CTy;
- } else {
- RHS.first = Visit(E->getRHS());
- RHS.second = llvm::Constant::getNullValue(RHS.first->getType());
- assert(CGF.getContext().hasSameUnqualifiedType(CETy, RHSTy) &&
- "The element types must always match.");
- }
-
- Value *ResultR, *ResultI;
- if (CETy->isRealFloatingType()) {
- ResultR = Builder.CreateFCmp(FCmpOpc, LHS.first, RHS.first, "cmp.r");
- ResultI = Builder.CreateFCmp(FCmpOpc, LHS.second, RHS.second, "cmp.i");
- } else {
- // Complex comparisons can only be equality comparisons. As such, signed
- // and unsigned opcodes are the same.
- ResultR = Builder.CreateICmp(UICmpOpc, LHS.first, RHS.first, "cmp.r");
- ResultI = Builder.CreateICmp(UICmpOpc, LHS.second, RHS.second, "cmp.i");
- }
-
- if (E->getOpcode() == BO_EQ) {
- Result = Builder.CreateAnd(ResultR, ResultI, "and.ri");
- } else {
- assert(E->getOpcode() == BO_NE &&
- "Complex comparison other than == or != ?");
- Result = Builder.CreateOr(ResultR, ResultI, "or.ri");
- }
- }
-
- return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType(),
- E->getExprLoc());
-}
-
-Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
- bool Ignore = TestAndClearIgnoreResultAssign();
-
- Value *RHS;
- LValue LHS;
-
- switch (E->getLHS()->getType().getObjCLifetime()) {
- case Qualifiers::OCL_Strong:
- std::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore);
- break;
-
- case Qualifiers::OCL_Autoreleasing:
- std::tie(LHS, RHS) = CGF.EmitARCStoreAutoreleasing(E);
- break;
-
- case Qualifiers::OCL_ExplicitNone:
- std::tie(LHS, RHS) = CGF.EmitARCStoreUnsafeUnretained(E, Ignore);
- break;
-
- case Qualifiers::OCL_Weak:
- RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
- break;
-
- case Qualifiers::OCL_None:
- // __block variables need to have the rhs evaluated first, plus
- // this should improve codegen just a little.
- RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
-
- // Store the value into the LHS. Bit-fields are handled specially
- // because the result is altered by the store, i.e., [C99 6.5.16p1]
- // 'An assignment expression has the value of the left operand after
- // the assignment...'.
- if (LHS.isBitField()) {
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, &RHS);
- } else {
- CGF.EmitNullabilityCheck(LHS, RHS, E->getExprLoc());
- CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS);
- }
- }
-
- // If the result is clearly ignored, return now.
- if (Ignore)
- return nullptr;
-
- // The result of an assignment in C is the assigned r-value.
- if (!CGF.getLangOpts().CPlusPlus)
- return RHS;
-
- // If the lvalue is non-volatile, return the computed value of the assignment.
- if (!LHS.isVolatileQualified())
- return RHS;
-
- // Otherwise, reload the value.
- return EmitLoadOfLValue(LHS, E->getExprLoc());
-}
-
-Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
- // Perform vector logical and on comparisons with zero vectors.
- if (E->getType()->isVectorType()) {
- CGF.incrementProfileCounter(E);
-
- Value *LHS = Visit(E->getLHS());
- Value *RHS = Visit(E->getRHS());
- Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
- if (LHS->getType()->isFPOrFPVectorTy()) {
- LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
- RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
- } else {
- LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
- RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
- }
- Value *And = Builder.CreateAnd(LHS, RHS);
- return Builder.CreateSExt(And, ConvertType(E->getType()), "sext");
- }
-
- llvm::Type *ResTy = ConvertType(E->getType());
-
- // If we have 0 && RHS, see if we can elide RHS, if so, just return 0.
- // If we have 1 && X, just emit X without inserting the control flow.
- bool LHSCondVal;
- if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) {
- if (LHSCondVal) { // If we have 1 && X, just emit X.
- CGF.incrementProfileCounter(E);
-
- Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- // ZExt result to int or bool.
- return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext");
- }
-
- // 0 && RHS: If it is safe, just elide the RHS, and return 0/false.
- if (!CGF.ContainsLabel(E->getRHS()))
- return llvm::Constant::getNullValue(ResTy);
- }
-
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end");
- llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("land.rhs");
-
- CodeGenFunction::ConditionalEvaluation eval(CGF);
-
- // Branch on the LHS first. If it is false, go to the failure (cont) block.
- CGF.EmitBranchOnBoolExpr(E->getLHS(), RHSBlock, ContBlock,
- CGF.getProfileCount(E->getRHS()));
-
- // Any edges into the ContBlock are now from an (indeterminate number of)
- // edges from this first condition. All of these values will be false. Start
- // setting up the PHI node in the Cont Block for this.
- llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2,
- "", ContBlock);
- for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock);
- PI != PE; ++PI)
- PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
-
- eval.begin(CGF);
- CGF.EmitBlock(RHSBlock);
- CGF.incrementProfileCounter(E);
- Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- eval.end(CGF);
-
- // Reaquire the RHS block, as there may be subblocks inserted.
- RHSBlock = Builder.GetInsertBlock();
-
- // Emit an unconditional branch from this block to ContBlock.
- {
- // There is no need to emit line number for unconditional branch.
- auto NL = ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(ContBlock);
- }
- // Insert an entry into the phi node for the edge with the value of RHSCond.
- PN->addIncoming(RHSCond, RHSBlock);
-
- // Artificial location to preserve the scope information
- {
- auto NL = ApplyDebugLocation::CreateArtificial(CGF);
- PN->setDebugLoc(Builder.getCurrentDebugLocation());
- }
-
- // ZExt result to int.
- return Builder.CreateZExtOrBitCast(PN, ResTy, "land.ext");
-}
-
-Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
- // Perform vector logical or on comparisons with zero vectors.
- if (E->getType()->isVectorType()) {
- CGF.incrementProfileCounter(E);
-
- Value *LHS = Visit(E->getLHS());
- Value *RHS = Visit(E->getRHS());
- Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
- if (LHS->getType()->isFPOrFPVectorTy()) {
- LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
- RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
- } else {
- LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
- RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
- }
- Value *Or = Builder.CreateOr(LHS, RHS);
- return Builder.CreateSExt(Or, ConvertType(E->getType()), "sext");
- }
-
- llvm::Type *ResTy = ConvertType(E->getType());
-
- // If we have 1 || RHS, see if we can elide RHS, if so, just return 1.
- // If we have 0 || X, just emit X without inserting the control flow.
- bool LHSCondVal;
- if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) {
- if (!LHSCondVal) { // If we have 0 || X, just emit X.
- CGF.incrementProfileCounter(E);
-
- Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- // ZExt result to int or bool.
- return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext");
- }
-
- // 1 || RHS: If it is safe, just elide the RHS, and return 1/true.
- if (!CGF.ContainsLabel(E->getRHS()))
- return llvm::ConstantInt::get(ResTy, 1);
- }
-
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end");
- llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs");
-
- CodeGenFunction::ConditionalEvaluation eval(CGF);
-
- // Branch on the LHS first. If it is true, go to the success (cont) block.
- CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock,
- CGF.getCurrentProfileCount() -
- CGF.getProfileCount(E->getRHS()));
-
- // Any edges into the ContBlock are now from an (indeterminate number of)
- // edges from this first condition. All of these values will be true. Start
- // setting up the PHI node in the Cont Block for this.
- llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2,
- "", ContBlock);
- for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock);
- PI != PE; ++PI)
- PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
-
- eval.begin(CGF);
-
- // Emit the RHS condition as a bool value.
- CGF.EmitBlock(RHSBlock);
- CGF.incrementProfileCounter(E);
- Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
-
- eval.end(CGF);
-
- // Reaquire the RHS block, as there may be subblocks inserted.
- RHSBlock = Builder.GetInsertBlock();
-
- // Emit an unconditional branch from this block to ContBlock. Insert an entry
- // into the phi node for the edge with the value of RHSCond.
- CGF.EmitBlock(ContBlock);
- PN->addIncoming(RHSCond, RHSBlock);
-
- // ZExt result to int.
- return Builder.CreateZExtOrBitCast(PN, ResTy, "lor.ext");
-}
-
-Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
- CGF.EmitIgnoredExpr(E->getLHS());
- CGF.EnsureInsertPoint();
- return Visit(E->getRHS());
-}
-
-//===----------------------------------------------------------------------===//
-// Other Operators
-//===----------------------------------------------------------------------===//
-
-/// isCheapEnoughToEvaluateUnconditionally - Return true if the specified
-/// expression is cheap enough and side-effect-free enough to evaluate
-/// unconditionally instead of conditionally. This is used to convert control
-/// flow into selects in some cases.
-static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
- CodeGenFunction &CGF) {
- // Anything that is an integer or floating point constant is fine.
- return E->IgnoreParens()->isEvaluatable(CGF.getContext());
-
- // Even non-volatile automatic variables can't be evaluated unconditionally.
- // Referencing a thread_local may cause non-trivial initialization work to
- // occur. If we're inside a lambda and one of the variables is from the scope
- // outside the lambda, that function may have returned already. Reading its
- // locals is a bad idea. Also, these reads may introduce races there didn't
- // exist in the source-level program.
-}
-
-
-Value *ScalarExprEmitter::
-VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
- TestAndClearIgnoreResultAssign();
-
- // Bind the common expression if necessary.
- CodeGenFunction::OpaqueValueMapping binding(CGF, E);
-
- Expr *condExpr = E->getCond();
- Expr *lhsExpr = E->getTrueExpr();
- Expr *rhsExpr = E->getFalseExpr();
-
- // If the condition constant folds and can be elided, try to avoid emitting
- // the condition and the dead arm.
- bool CondExprBool;
- if (CGF.ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) {
- Expr *live = lhsExpr, *dead = rhsExpr;
- if (!CondExprBool) std::swap(live, dead);
-
- // If the dead side doesn't have labels we need, just emit the Live part.
- if (!CGF.ContainsLabel(dead)) {
- if (CondExprBool)
- CGF.incrementProfileCounter(E);
- Value *Result = Visit(live);
-
- // If the live part is a throw expression, it acts like it has a void
- // type, so evaluating it returns a null Value*. However, a conditional
- // with non-void type must return a non-null Value*.
- if (!Result && !E->getType()->isVoidType())
- Result = llvm::UndefValue::get(CGF.ConvertType(E->getType()));
-
- return Result;
- }
- }
-
- // OpenCL: If the condition is a vector, we can treat this condition like
- // the select function.
- if (CGF.getLangOpts().OpenCL
- && condExpr->getType()->isVectorType()) {
- CGF.incrementProfileCounter(E);
-
- llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
- llvm::Value *LHS = Visit(lhsExpr);
- llvm::Value *RHS = Visit(rhsExpr);
-
- llvm::Type *condType = ConvertType(condExpr->getType());
- llvm::VectorType *vecTy = cast<llvm::VectorType>(condType);
-
- unsigned numElem = vecTy->getNumElements();
- llvm::Type *elemType = vecTy->getElementType();
-
- llvm::Value *zeroVec = llvm::Constant::getNullValue(vecTy);
- llvm::Value *TestMSB = Builder.CreateICmpSLT(CondV, zeroVec);
- llvm::Value *tmp = Builder.CreateSExt(TestMSB,
- llvm::VectorType::get(elemType,
- numElem),
- "sext");
- llvm::Value *tmp2 = Builder.CreateNot(tmp);
-
- // Cast float to int to perform ANDs if necessary.
- llvm::Value *RHSTmp = RHS;
- llvm::Value *LHSTmp = LHS;
- bool wasCast = false;
- llvm::VectorType *rhsVTy = cast<llvm::VectorType>(RHS->getType());
- if (rhsVTy->getElementType()->isFloatingPointTy()) {
- RHSTmp = Builder.CreateBitCast(RHS, tmp2->getType());
- LHSTmp = Builder.CreateBitCast(LHS, tmp->getType());
- wasCast = true;
- }
-
- llvm::Value *tmp3 = Builder.CreateAnd(RHSTmp, tmp2);
- llvm::Value *tmp4 = Builder.CreateAnd(LHSTmp, tmp);
- llvm::Value *tmp5 = Builder.CreateOr(tmp3, tmp4, "cond");
- if (wasCast)
- tmp5 = Builder.CreateBitCast(tmp5, RHS->getType());
-
- return tmp5;
- }
-
- // If this is a really simple expression (like x ? 4 : 5), emit this as a
- // select instead of as control flow. We can only do this if it is cheap and
- // safe to evaluate the LHS and RHS unconditionally.
- if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, CGF) &&
- isCheapEnoughToEvaluateUnconditionally(rhsExpr, CGF)) {
- llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr);
- llvm::Value *StepV = Builder.CreateZExtOrBitCast(CondV, CGF.Int64Ty);
-
- CGF.incrementProfileCounter(E, StepV);
-
- llvm::Value *LHS = Visit(lhsExpr);
- llvm::Value *RHS = Visit(rhsExpr);
- if (!LHS) {
- // If the conditional has void type, make sure we return a null Value*.
- assert(!RHS && "LHS and RHS types must match");
- return nullptr;
- }
- return Builder.CreateSelect(CondV, LHS, RHS, "cond");
- }
-
- llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
- llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
-
- CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(condExpr, LHSBlock, RHSBlock,
- CGF.getProfileCount(lhsExpr));
-
- CGF.EmitBlock(LHSBlock);
- CGF.incrementProfileCounter(E);
- eval.begin(CGF);
- Value *LHS = Visit(lhsExpr);
- eval.end(CGF);
-
- LHSBlock = Builder.GetInsertBlock();
- Builder.CreateBr(ContBlock);
-
- CGF.EmitBlock(RHSBlock);
- eval.begin(CGF);
- Value *RHS = Visit(rhsExpr);
- eval.end(CGF);
-
- RHSBlock = Builder.GetInsertBlock();
- CGF.EmitBlock(ContBlock);
-
- // If the LHS or RHS is a throw expression, it will be legitimately null.
- if (!LHS)
- return RHS;
- if (!RHS)
- return LHS;
-
- // Create a PHI node for the real part.
- llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), 2, "cond");
- PN->addIncoming(LHS, LHSBlock);
- PN->addIncoming(RHS, RHSBlock);
- return PN;
-}
-
-Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
- return Visit(E->getChosenSubExpr());
-}
-
-Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
- QualType Ty = VE->getType();
-
- if (Ty->isVariablyModifiedType())
- CGF.EmitVariablyModifiedType(Ty);
-
- Address ArgValue = Address::invalid();
- Address ArgPtr = CGF.EmitVAArg(VE, ArgValue);
-
- llvm::Type *ArgTy = ConvertType(VE->getType());
-
- // If EmitVAArg fails, emit an error.
- if (!ArgPtr.isValid()) {
- CGF.ErrorUnsupported(VE, "va_arg expression");
- return llvm::UndefValue::get(ArgTy);
- }
-
- // FIXME Volatility.
- llvm::Value *Val = Builder.CreateLoad(ArgPtr);
-
- // If EmitVAArg promoted the type, we must truncate it.
- if (ArgTy != Val->getType()) {
- if (ArgTy->isPointerTy() && !Val->getType()->isPointerTy())
- Val = Builder.CreateIntToPtr(Val, ArgTy);
- else
- Val = Builder.CreateTrunc(Val, ArgTy);
- }
-
- return Val;
-}
-
-Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
- return CGF.EmitBlockLiteral(block);
-}
-
-// Convert a vec3 to vec4, or vice versa.
-static Value *ConvertVec3AndVec4(CGBuilderTy &Builder, CodeGenFunction &CGF,
- Value *Src, unsigned NumElementsDst) {
- llvm::Value *UnV = llvm::UndefValue::get(Src->getType());
- SmallVector<llvm::Constant*, 4> Args;
- Args.push_back(Builder.getInt32(0));
- Args.push_back(Builder.getInt32(1));
- Args.push_back(Builder.getInt32(2));
- if (NumElementsDst == 4)
- Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
- llvm::Constant *Mask = llvm::ConstantVector::get(Args);
- return Builder.CreateShuffleVector(Src, UnV, Mask);
-}
-
-// Create cast instructions for converting LLVM value \p Src to LLVM type \p
-// DstTy. \p Src has the same size as \p DstTy. Both are single value types
-// but could be scalar or vectors of different lengths, and either can be
-// pointer.
-// There are 4 cases:
-// 1. non-pointer -> non-pointer : needs 1 bitcast
-// 2. pointer -> pointer : needs 1 bitcast or addrspacecast
-// 3. pointer -> non-pointer
-// a) pointer -> intptr_t : needs 1 ptrtoint
-// b) pointer -> non-intptr_t : needs 1 ptrtoint then 1 bitcast
-// 4. non-pointer -> pointer
-// a) intptr_t -> pointer : needs 1 inttoptr
-// b) non-intptr_t -> pointer : needs 1 bitcast then 1 inttoptr
-// Note: for cases 3b and 4b two casts are required since LLVM casts do not
-// allow casting directly between pointer types and non-integer non-pointer
-// types.
-static Value *createCastsForTypeOfSameSize(CGBuilderTy &Builder,
- const llvm::DataLayout &DL,
- Value *Src, llvm::Type *DstTy,
- StringRef Name = "") {
- auto SrcTy = Src->getType();
-
- // Case 1.
- if (!SrcTy->isPointerTy() && !DstTy->isPointerTy())
- return Builder.CreateBitCast(Src, DstTy, Name);
-
- // Case 2.
- if (SrcTy->isPointerTy() && DstTy->isPointerTy())
- return Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DstTy, Name);
-
- // Case 3.
- if (SrcTy->isPointerTy() && !DstTy->isPointerTy()) {
- // Case 3b.
- if (!DstTy->isIntegerTy())
- Src = Builder.CreatePtrToInt(Src, DL.getIntPtrType(SrcTy));
- // Cases 3a and 3b.
- return Builder.CreateBitOrPointerCast(Src, DstTy, Name);
- }
-
- // Case 4b.
- if (!SrcTy->isIntegerTy())
- Src = Builder.CreateBitCast(Src, DL.getIntPtrType(DstTy));
- // Cases 4a and 4b.
- return Builder.CreateIntToPtr(Src, DstTy, Name);
-}
-
-Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
- Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
- llvm::Type *DstTy = ConvertType(E->getType());
-
- llvm::Type *SrcTy = Src->getType();
- unsigned NumElementsSrc = isa<llvm::VectorType>(SrcTy) ?
- cast<llvm::VectorType>(SrcTy)->getNumElements() : 0;
- unsigned NumElementsDst = isa<llvm::VectorType>(DstTy) ?
- cast<llvm::VectorType>(DstTy)->getNumElements() : 0;
-
- // Going from vec3 to non-vec3 is a special case and requires a shuffle
- // vector to get a vec4, then a bitcast if the target type is different.
- if (NumElementsSrc == 3 && NumElementsDst != 3) {
- Src = ConvertVec3AndVec4(Builder, CGF, Src, 4);
-
- if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) {
- Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
- DstTy);
- }
-
- Src->setName("astype");
- return Src;
- }
-
- // Going from non-vec3 to vec3 is a special case and requires a bitcast
- // to vec4 if the original type is not vec4, then a shuffle vector to
- // get a vec3.
- if (NumElementsSrc != 3 && NumElementsDst == 3) {
- if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) {
- auto Vec4Ty = llvm::VectorType::get(DstTy->getVectorElementType(), 4);
- Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
- Vec4Ty);
- }
-
- Src = ConvertVec3AndVec4(Builder, CGF, Src, 3);
- Src->setName("astype");
- return Src;
- }
-
- return Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(),
- Src, DstTy, "astype");
-}
-
-Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
- return CGF.EmitAtomicExpr(E).getScalarVal();
-}
-
-//===----------------------------------------------------------------------===//
-// Entry Point into this File
-//===----------------------------------------------------------------------===//
-
-/// Emit the computation of the specified expression of scalar type, ignoring
-/// the result.
-Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
- assert(E && hasScalarEvaluationKind(E->getType()) &&
- "Invalid scalar expression to emit");
-
- return ScalarExprEmitter(*this, IgnoreResultAssign)
- .Visit(const_cast<Expr *>(E));
-}
-
-/// Emit a conversion from the specified type to the specified destination type,
-/// both of which are LLVM scalar types.
-Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
- QualType DstTy,
- SourceLocation Loc) {
- assert(hasScalarEvaluationKind(SrcTy) && hasScalarEvaluationKind(DstTy) &&
- "Invalid scalar expression to emit");
- return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy, Loc);
-}
-
-/// Emit a conversion from the specified complex type to the specified
-/// destination type, where the destination type is an LLVM scalar type.
-Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
- QualType SrcTy,
- QualType DstTy,
- SourceLocation Loc) {
- assert(SrcTy->isAnyComplexType() && hasScalarEvaluationKind(DstTy) &&
- "Invalid complex -> scalar conversion");
- return ScalarExprEmitter(*this)
- .EmitComplexToScalarConversion(Src, SrcTy, DstTy, Loc);
-}
-
-
-llvm::Value *CodeGenFunction::
-EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
- bool isInc, bool isPre) {
- return ScalarExprEmitter(*this).EmitScalarPrePostIncDec(E, LV, isInc, isPre);
-}
-
-LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
- // object->isa or (*object).isa
- // Generate code as for: *(Class*)object
-
- Expr *BaseExpr = E->getBase();
- Address Addr = Address::invalid();
- if (BaseExpr->isRValue()) {
- Addr = Address(EmitScalarExpr(BaseExpr), getPointerAlign());
- } else {
- Addr = EmitLValue(BaseExpr).getAddress();
- }
-
- // Cast the address to Class*.
- Addr = Builder.CreateElementBitCast(Addr, ConvertType(E->getType()));
- return MakeAddrLValue(Addr, E->getType());
-}
-
-
-LValue CodeGenFunction::EmitCompoundAssignmentLValue(
- const CompoundAssignOperator *E) {
- ScalarExprEmitter Scalar(*this);
- Value *Result = nullptr;
- switch (E->getOpcode()) {
-#define COMPOUND_OP(Op) \
- case BO_##Op##Assign: \
- return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \
- Result)
- COMPOUND_OP(Mul);
- COMPOUND_OP(Div);
- COMPOUND_OP(Rem);
- COMPOUND_OP(Add);
- COMPOUND_OP(Sub);
- COMPOUND_OP(Shl);
- COMPOUND_OP(Shr);
- COMPOUND_OP(And);
- COMPOUND_OP(Xor);
- COMPOUND_OP(Or);
-#undef COMPOUND_OP
-
- case BO_PtrMemD:
- case BO_PtrMemI:
- case BO_Mul:
- case BO_Div:
- case BO_Rem:
- case BO_Add:
- case BO_Sub:
- case BO_Shl:
- case BO_Shr:
- case BO_LT:
- case BO_GT:
- case BO_LE:
- case BO_GE:
- case BO_EQ:
- case BO_NE:
- case BO_Cmp:
- case BO_And:
- case BO_Xor:
- case BO_Or:
- case BO_LAnd:
- case BO_LOr:
- case BO_Assign:
- case BO_Comma:
- llvm_unreachable("Not valid compound assignment operators");
- }
-
- llvm_unreachable("Unhandled compound assignment operator");
-}
-
-Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
- ArrayRef<Value *> IdxList,
- bool SignedIndices,
- bool IsSubtraction,
- SourceLocation Loc,
- const Twine &Name) {
- Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
-
- // If the pointer overflow sanitizer isn't enabled, do nothing.
- if (!SanOpts.has(SanitizerKind::PointerOverflow))
- return GEPVal;
-
- // If the GEP has already been reduced to a constant, leave it be.
- if (isa<llvm::Constant>(GEPVal))
- return GEPVal;
-
- // Only check for overflows in the default address space.
- if (GEPVal->getType()->getPointerAddressSpace())
- return GEPVal;
-
- auto *GEP = cast<llvm::GEPOperator>(GEPVal);
- assert(GEP->isInBounds() && "Expected inbounds GEP");
-
- SanitizerScope SanScope(this);
- auto &VMContext = getLLVMContext();
- const auto &DL = CGM.getDataLayout();
- auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType());
-
- // Grab references to the signed add/mul overflow intrinsics for intptr_t.
- auto *Zero = llvm::ConstantInt::getNullValue(IntPtrTy);
- auto *SAddIntrinsic =
- CGM.getIntrinsic(llvm::Intrinsic::sadd_with_overflow, IntPtrTy);
- auto *SMulIntrinsic =
- CGM.getIntrinsic(llvm::Intrinsic::smul_with_overflow, IntPtrTy);
-
- // The total (signed) byte offset for the GEP.
- llvm::Value *TotalOffset = nullptr;
- // The offset overflow flag - true if the total offset overflows.
- llvm::Value *OffsetOverflows = Builder.getFalse();
-
- /// Return the result of the given binary operation.
- auto eval = [&](BinaryOperator::Opcode Opcode, llvm::Value *LHS,
- llvm::Value *RHS) -> llvm::Value * {
- assert((Opcode == BO_Add || Opcode == BO_Mul) && "Can't eval binop");
-
- // If the operands are constants, return a constant result.
- if (auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS)) {
- if (auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS)) {
- llvm::APInt N;
- bool HasOverflow = mayHaveIntegerOverflow(LHSCI, RHSCI, Opcode,
- /*Signed=*/true, N);
- if (HasOverflow)
- OffsetOverflows = Builder.getTrue();
- return llvm::ConstantInt::get(VMContext, N);
- }
- }
-
- // Otherwise, compute the result with checked arithmetic.
- auto *ResultAndOverflow = Builder.CreateCall(
- (Opcode == BO_Add) ? SAddIntrinsic : SMulIntrinsic, {LHS, RHS});
- OffsetOverflows = Builder.CreateOr(
- Builder.CreateExtractValue(ResultAndOverflow, 1), OffsetOverflows);
- return Builder.CreateExtractValue(ResultAndOverflow, 0);
- };
-
- // Determine the total byte offset by looking at each GEP operand.
- for (auto GTI = llvm::gep_type_begin(GEP), GTE = llvm::gep_type_end(GEP);
- GTI != GTE; ++GTI) {
- llvm::Value *LocalOffset;
- auto *Index = GTI.getOperand();
- // Compute the local offset contributed by this indexing step:
- if (auto *STy = GTI.getStructTypeOrNull()) {
- // For struct indexing, the local offset is the byte position of the
- // specified field.
- unsigned FieldNo = cast<llvm::ConstantInt>(Index)->getZExtValue();
- LocalOffset = llvm::ConstantInt::get(
- IntPtrTy, DL.getStructLayout(STy)->getElementOffset(FieldNo));
- } else {
- // Otherwise this is array-like indexing. The local offset is the index
- // multiplied by the element size.
- auto *ElementSize = llvm::ConstantInt::get(
- IntPtrTy, DL.getTypeAllocSize(GTI.getIndexedType()));
- auto *IndexS = Builder.CreateIntCast(Index, IntPtrTy, /*isSigned=*/true);
- LocalOffset = eval(BO_Mul, ElementSize, IndexS);
- }
-
- // If this is the first offset, set it as the total offset. Otherwise, add
- // the local offset into the running total.
- if (!TotalOffset || TotalOffset == Zero)
- TotalOffset = LocalOffset;
- else
- TotalOffset = eval(BO_Add, TotalOffset, LocalOffset);
- }
-
- // Common case: if the total offset is zero, don't emit a check.
- if (TotalOffset == Zero)
- return GEPVal;
-
- // Now that we've computed the total offset, add it to the base pointer (with
- // wrapping semantics).
- auto *IntPtr = Builder.CreatePtrToInt(GEP->getPointerOperand(), IntPtrTy);
- auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset);
-
- // The GEP is valid if:
- // 1) The total offset doesn't overflow, and
- // 2) The sign of the difference between the computed address and the base
- // pointer matches the sign of the total offset.
- llvm::Value *ValidGEP;
- auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows);
- if (SignedIndices) {
- auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
- auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
- llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
- ValidGEP = Builder.CreateAnd(
- Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid),
- NoOffsetOverflow);
- } else if (!SignedIndices && !IsSubtraction) {
- auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
- ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow);
- } else {
- auto *NegOrZeroValid = Builder.CreateICmpULE(ComputedGEP, IntPtr);
- ValidGEP = Builder.CreateAnd(NegOrZeroValid, NoOffsetOverflow);
- }
-
- llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)};
- // Pass the computed GEP to the runtime to avoid emitting poisoned arguments.
- llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
- EmitCheck(std::make_pair(ValidGEP, SanitizerKind::PointerOverflow),
- SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
-
- return GEPVal;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGGPUBuiltin.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGGPUBuiltin.cpp
deleted file mode 100644
index b5375ffb8db..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGGPUBuiltin.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-//===------ CGGPUBuiltin.cpp - Codegen for GPU builtins -------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Generates code for built-in GPU calls which are not runtime-specific.
-// (Runtime-specific codegen lives in programming model specific files.)
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "clang/Basic/Builtins.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Instruction.h"
-#include "llvm/Support/MathExtras.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-static llvm::Function *GetVprintfDeclaration(llvm::Module &M) {
- llvm::Type *ArgTypes[] = {llvm::Type::getInt8PtrTy(M.getContext()),
- llvm::Type::getInt8PtrTy(M.getContext())};
- llvm::FunctionType *VprintfFuncType = llvm::FunctionType::get(
- llvm::Type::getInt32Ty(M.getContext()), ArgTypes, false);
-
- if (auto* F = M.getFunction("vprintf")) {
- // Our CUDA system header declares vprintf with the right signature, so
- // nobody else should have been able to declare vprintf with a bogus
- // signature.
- assert(F->getFunctionType() == VprintfFuncType);
- return F;
- }
-
- // vprintf doesn't already exist; create a declaration and insert it into the
- // module.
- return llvm::Function::Create(
- VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, "vprintf", &M);
-}
-
-// Transforms a call to printf into a call to the NVPTX vprintf syscall (which
-// isn't particularly special; it's invoked just like a regular function).
-// vprintf takes two args: A format string, and a pointer to a buffer containing
-// the varargs.
-//
-// For example, the call
-//
-// printf("format string", arg1, arg2, arg3);
-//
-// is converted into something resembling
-//
-// struct Tmp {
-// Arg1 a1;
-// Arg2 a2;
-// Arg3 a3;
-// };
-// char* buf = alloca(sizeof(Tmp));
-// *(Tmp*)buf = {a1, a2, a3};
-// vprintf("format string", buf);
-//
-// buf is aligned to the max of {alignof(Arg1), ...}. Furthermore, each of the
-// args is itself aligned to its preferred alignment.
-//
-// Note that by the time this function runs, E's args have already undergone the
-// standard C vararg promotion (short -> int, float -> double, etc.).
-RValue
-CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue) {
- assert(getTarget().getTriple().isNVPTX());
- assert(E->getBuiltinCallee() == Builtin::BIprintf);
- assert(E->getNumArgs() >= 1); // printf always has at least one arg.
-
- const llvm::DataLayout &DL = CGM.getDataLayout();
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
-
- CallArgList Args;
- EmitCallArgs(Args,
- E->getDirectCallee()->getType()->getAs<FunctionProtoType>(),
- E->arguments(), E->getDirectCallee(),
- /* ParamsToSkip = */ 0);
-
- // We don't know how to emit non-scalar varargs.
- if (std::any_of(Args.begin() + 1, Args.end(), [&](const CallArg &A) {
- return !A.getRValue(*this).isScalar();
- })) {
- CGM.ErrorUnsupported(E, "non-scalar arg to printf");
- return RValue::get(llvm::ConstantInt::get(IntTy, 0));
- }
-
- // Construct and fill the args buffer that we'll pass to vprintf.
- llvm::Value *BufferPtr;
- if (Args.size() <= 1) {
- // If there are no args, pass a null pointer to vprintf.
- BufferPtr = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(Ctx));
- } else {
- llvm::SmallVector<llvm::Type *, 8> ArgTypes;
- for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I)
- ArgTypes.push_back(Args[I].getRValue(*this).getScalarVal()->getType());
-
- // Using llvm::StructType is correct only because printf doesn't accept
- // aggregates. If we had to handle aggregates here, we'd have to manually
- // compute the offsets within the alloca -- we wouldn't be able to assume
- // that the alignment of the llvm type was the same as the alignment of the
- // clang type.
- llvm::Type *AllocaTy = llvm::StructType::create(ArgTypes, "printf_args");
- llvm::Value *Alloca = CreateTempAlloca(AllocaTy);
-
- for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) {
- llvm::Value *P = Builder.CreateStructGEP(AllocaTy, Alloca, I - 1);
- llvm::Value *Arg = Args[I].getRValue(*this).getScalarVal();
- Builder.CreateAlignedStore(Arg, P, DL.getPrefTypeAlignment(Arg->getType()));
- }
- BufferPtr = Builder.CreatePointerCast(Alloca, llvm::Type::getInt8PtrTy(Ctx));
- }
-
- // Invoke vprintf and return.
- llvm::Function* VprintfFunc = GetVprintfDeclaration(CGM.getModule());
- return RValue::get(Builder.CreateCall(
- VprintfFunc, {Args[0].getRValue(*this).getScalarVal(), BufferPtr}));
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.cpp
deleted file mode 100644
index fd0a9c773a2..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.cpp
+++ /dev/null
@@ -1,402 +0,0 @@
-//===---- CGLoopInfo.cpp - LLVM CodeGen for loop metadata -*- C++ -*-------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGLoopInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/CFG.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/InstrTypes.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Metadata.h"
-using namespace clang::CodeGen;
-using namespace llvm;
-
-static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs,
- const llvm::DebugLoc &StartLoc,
- const llvm::DebugLoc &EndLoc, MDNode *&AccGroup) {
-
- if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 &&
- Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
- Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled &&
- Attrs.PipelineInitiationInterval == 0 &&
- Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
- Attrs.UnrollEnable == LoopAttributes::Unspecified &&
- Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
- Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc &&
- !EndLoc)
- return nullptr;
-
- SmallVector<Metadata *, 4> Args;
- // Reserve operand 0 for loop id self reference.
- auto TempNode = MDNode::getTemporary(Ctx, None);
- Args.push_back(TempNode.get());
-
- // If we have a valid start debug location for the loop, add it.
- if (StartLoc) {
- Args.push_back(StartLoc.getAsMDNode());
-
- // If we also have a valid end debug location for the loop, add it.
- if (EndLoc)
- Args.push_back(EndLoc.getAsMDNode());
- }
-
- // Setting vectorize.width
- if (Attrs.VectorizeWidth > 0) {
- Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.width"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt32Ty(Ctx), Attrs.VectorizeWidth))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- // Setting interleave.count
- if (Attrs.InterleaveCount > 0) {
- Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.interleave.count"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt32Ty(Ctx), Attrs.InterleaveCount))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- // Setting unroll.count
- if (Attrs.UnrollCount > 0) {
- Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt32Ty(Ctx), Attrs.UnrollCount))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- // Setting unroll_and_jam.count
- if (Attrs.UnrollAndJamCount > 0) {
- Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll_and_jam.count"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt32Ty(Ctx), Attrs.UnrollAndJamCount))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- // Setting vectorize.enable
- if (Attrs.VectorizeEnable != LoopAttributes::Unspecified) {
- Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt1Ty(Ctx), (Attrs.VectorizeEnable ==
- LoopAttributes::Enable)))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- // Setting unroll.full or unroll.disable
- if (Attrs.UnrollEnable != LoopAttributes::Unspecified) {
- std::string Name;
- if (Attrs.UnrollEnable == LoopAttributes::Enable)
- Name = "llvm.loop.unroll.enable";
- else if (Attrs.UnrollEnable == LoopAttributes::Full)
- Name = "llvm.loop.unroll.full";
- else
- Name = "llvm.loop.unroll.disable";
- Metadata *Vals[] = {MDString::get(Ctx, Name)};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- // Setting unroll_and_jam.full or unroll_and_jam.disable
- if (Attrs.UnrollAndJamEnable != LoopAttributes::Unspecified) {
- std::string Name;
- if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable)
- Name = "llvm.loop.unroll_and_jam.enable";
- else if (Attrs.UnrollAndJamEnable == LoopAttributes::Full)
- Name = "llvm.loop.unroll_and_jam.full";
- else
- Name = "llvm.loop.unroll_and_jam.disable";
- Metadata *Vals[] = {MDString::get(Ctx, Name)};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- if (Attrs.DistributeEnable != LoopAttributes::Unspecified) {
- Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt1Ty(Ctx), (Attrs.DistributeEnable ==
- LoopAttributes::Enable)))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- if (Attrs.IsParallel) {
- AccGroup = MDNode::getDistinct(Ctx, {});
- Args.push_back(MDNode::get(
- Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup}));
- }
-
- if (Attrs.PipelineDisabled) {
- Metadata *Vals[] = {
- MDString::get(Ctx, "llvm.loop.pipeline.disable"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt1Ty(Ctx), (Attrs.PipelineDisabled == true)))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- if (Attrs.PipelineInitiationInterval > 0) {
- Metadata *Vals[] = {
- MDString::get(Ctx, "llvm.loop.pipeline.initiationinterval"),
- ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt32Ty(Ctx), Attrs.PipelineInitiationInterval))};
- Args.push_back(MDNode::get(Ctx, Vals));
- }
-
- // Set the first operand to itself.
- MDNode *LoopID = MDNode::get(Ctx, Args);
- LoopID->replaceOperandWith(0, LoopID);
- return LoopID;
-}
-
-LoopAttributes::LoopAttributes(bool IsParallel)
- : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
- UnrollEnable(LoopAttributes::Unspecified),
- UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
- InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0),
- DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
- PipelineInitiationInterval(0) {}
-
-void LoopAttributes::clear() {
- IsParallel = false;
- VectorizeWidth = 0;
- InterleaveCount = 0;
- UnrollCount = 0;
- UnrollAndJamCount = 0;
- VectorizeEnable = LoopAttributes::Unspecified;
- UnrollEnable = LoopAttributes::Unspecified;
- UnrollAndJamEnable = LoopAttributes::Unspecified;
- DistributeEnable = LoopAttributes::Unspecified;
- PipelineDisabled = false;
- PipelineInitiationInterval = 0;
-}
-
-LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
- const llvm::DebugLoc &StartLoc, const llvm::DebugLoc &EndLoc)
- : LoopID(nullptr), Header(Header), Attrs(Attrs) {
- LoopID =
- createMetadata(Header->getContext(), Attrs, StartLoc, EndLoc, AccGroup);
-}
-
-void LoopInfoStack::push(BasicBlock *Header, const llvm::DebugLoc &StartLoc,
- const llvm::DebugLoc &EndLoc) {
- Active.push_back(LoopInfo(Header, StagedAttrs, StartLoc, EndLoc));
- // Clear the attributes so nested loops do not inherit them.
- StagedAttrs.clear();
-}
-
-void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
- ArrayRef<const clang::Attr *> Attrs,
- const llvm::DebugLoc &StartLoc,
- const llvm::DebugLoc &EndLoc) {
-
- // Identify loop hint attributes from Attrs.
- for (const auto *Attr : Attrs) {
- const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
- const OpenCLUnrollHintAttr *OpenCLHint =
- dyn_cast<OpenCLUnrollHintAttr>(Attr);
-
- // Skip non loop hint attributes
- if (!LH && !OpenCLHint) {
- continue;
- }
-
- LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
- LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
- unsigned ValueInt = 1;
- // Translate opencl_unroll_hint attribute argument to
- // equivalent LoopHintAttr enums.
- // OpenCL v2.0 s6.11.5:
- // 0 - full unroll (no argument).
- // 1 - disable unroll.
- // other positive integer n - unroll by n.
- if (OpenCLHint) {
- ValueInt = OpenCLHint->getUnrollHint();
- if (ValueInt == 0) {
- State = LoopHintAttr::Full;
- } else if (ValueInt != 1) {
- Option = LoopHintAttr::UnrollCount;
- State = LoopHintAttr::Numeric;
- }
- } else if (LH) {
- auto *ValueExpr = LH->getValue();
- if (ValueExpr) {
- llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx);
- ValueInt = ValueAPS.getSExtValue();
- }
-
- Option = LH->getOption();
- State = LH->getState();
- }
- switch (State) {
- case LoopHintAttr::Disable:
- switch (Option) {
- case LoopHintAttr::Vectorize:
- // Disable vectorization by specifying a width of 1.
- setVectorizeWidth(1);
- break;
- case LoopHintAttr::Interleave:
- // Disable interleaving by speciyfing a count of 1.
- setInterleaveCount(1);
- break;
- case LoopHintAttr::Unroll:
- setUnrollState(LoopAttributes::Disable);
- break;
- case LoopHintAttr::UnrollAndJam:
- setUnrollAndJamState(LoopAttributes::Disable);
- break;
- case LoopHintAttr::Distribute:
- setDistributeState(false);
- break;
- case LoopHintAttr::PipelineDisabled:
- setPipelineDisabled(true);
- break;
- case LoopHintAttr::UnrollCount:
- case LoopHintAttr::UnrollAndJamCount:
- case LoopHintAttr::VectorizeWidth:
- case LoopHintAttr::InterleaveCount:
- case LoopHintAttr::PipelineInitiationInterval:
- llvm_unreachable("Options cannot be disabled.");
- break;
- }
- break;
- case LoopHintAttr::Enable:
- switch (Option) {
- case LoopHintAttr::Vectorize:
- case LoopHintAttr::Interleave:
- setVectorizeEnable(true);
- break;
- case LoopHintAttr::Unroll:
- setUnrollState(LoopAttributes::Enable);
- break;
- case LoopHintAttr::UnrollAndJam:
- setUnrollAndJamState(LoopAttributes::Enable);
- break;
- case LoopHintAttr::Distribute:
- setDistributeState(true);
- break;
- case LoopHintAttr::UnrollCount:
- case LoopHintAttr::UnrollAndJamCount:
- case LoopHintAttr::VectorizeWidth:
- case LoopHintAttr::InterleaveCount:
- case LoopHintAttr::PipelineDisabled:
- case LoopHintAttr::PipelineInitiationInterval:
- llvm_unreachable("Options cannot enabled.");
- break;
- }
- break;
- case LoopHintAttr::AssumeSafety:
- switch (Option) {
- case LoopHintAttr::Vectorize:
- case LoopHintAttr::Interleave:
- // Apply "llvm.mem.parallel_loop_access" metadata to load/stores.
- setParallel(true);
- setVectorizeEnable(true);
- break;
- case LoopHintAttr::Unroll:
- case LoopHintAttr::UnrollAndJam:
- case LoopHintAttr::UnrollCount:
- case LoopHintAttr::UnrollAndJamCount:
- case LoopHintAttr::VectorizeWidth:
- case LoopHintAttr::InterleaveCount:
- case LoopHintAttr::Distribute:
- case LoopHintAttr::PipelineDisabled:
- case LoopHintAttr::PipelineInitiationInterval:
- llvm_unreachable("Options cannot be used to assume mem safety.");
- break;
- }
- break;
- case LoopHintAttr::Full:
- switch (Option) {
- case LoopHintAttr::Unroll:
- setUnrollState(LoopAttributes::Full);
- break;
- case LoopHintAttr::UnrollAndJam:
- setUnrollAndJamState(LoopAttributes::Full);
- break;
- case LoopHintAttr::Vectorize:
- case LoopHintAttr::Interleave:
- case LoopHintAttr::UnrollCount:
- case LoopHintAttr::UnrollAndJamCount:
- case LoopHintAttr::VectorizeWidth:
- case LoopHintAttr::InterleaveCount:
- case LoopHintAttr::Distribute:
- case LoopHintAttr::PipelineDisabled:
- case LoopHintAttr::PipelineInitiationInterval:
- llvm_unreachable("Options cannot be used with 'full' hint.");
- break;
- }
- break;
- case LoopHintAttr::Numeric:
- switch (Option) {
- case LoopHintAttr::VectorizeWidth:
- setVectorizeWidth(ValueInt);
- break;
- case LoopHintAttr::InterleaveCount:
- setInterleaveCount(ValueInt);
- break;
- case LoopHintAttr::UnrollCount:
- setUnrollCount(ValueInt);
- break;
- case LoopHintAttr::UnrollAndJamCount:
- setUnrollAndJamCount(ValueInt);
- break;
- case LoopHintAttr::PipelineInitiationInterval:
- setPipelineInitiationInterval(ValueInt);
- break;
- case LoopHintAttr::Unroll:
- case LoopHintAttr::UnrollAndJam:
- case LoopHintAttr::Vectorize:
- case LoopHintAttr::Interleave:
- case LoopHintAttr::Distribute:
- case LoopHintAttr::PipelineDisabled:
- llvm_unreachable("Options cannot be assigned a value.");
- break;
- }
- break;
- }
- }
-
- /// Stage the attributes.
- push(Header, StartLoc, EndLoc);
-}
-
-void LoopInfoStack::pop() {
- assert(!Active.empty() && "No active loops to pop");
- Active.pop_back();
-}
-
-void LoopInfoStack::InsertHelper(Instruction *I) const {
- if (I->mayReadOrWriteMemory()) {
- SmallVector<Metadata *, 4> AccessGroups;
- for (const LoopInfo &AL : Active) {
- // Here we assume that every loop that has an access group is parallel.
- if (MDNode *Group = AL.getAccessGroup())
- AccessGroups.push_back(Group);
- }
- MDNode *UnionMD = nullptr;
- if (AccessGroups.size() == 1)
- UnionMD = cast<MDNode>(AccessGroups[0]);
- else if (AccessGroups.size() >= 2)
- UnionMD = MDNode::get(I->getContext(), AccessGroups);
- I->setMetadata("llvm.access.group", UnionMD);
- }
-
- if (!hasInfo())
- return;
-
- const LoopInfo &L = getInfo();
- if (!L.getLoopID())
- return;
-
- if (I->isTerminator()) {
- for (BasicBlock *Succ : successors(I))
- if (Succ == L.getHeader()) {
- I->setMetadata(llvm::LLVMContext::MD_loop, L.getLoopID());
- break;
- }
- return;
- }
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.h b/gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.h
deleted file mode 100644
index 84ba03bfb00..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGLoopInfo.h
+++ /dev/null
@@ -1,203 +0,0 @@
-//===---- CGLoopInfo.h - LLVM CodeGen for loop metadata -*- C++ -*---------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the internal state used for llvm translation for loop statement
-// metadata.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGLOOPINFO_H
-#define LLVM_CLANG_LIB_CODEGEN_CGLOOPINFO_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/IR/DebugLoc.h"
-#include "llvm/IR/Value.h"
-#include "llvm/Support/Compiler.h"
-
-namespace llvm {
-class BasicBlock;
-class Instruction;
-class MDNode;
-} // end namespace llvm
-
-namespace clang {
-class Attr;
-class ASTContext;
-namespace CodeGen {
-
-/// Attributes that may be specified on loops.
-struct LoopAttributes {
- explicit LoopAttributes(bool IsParallel = false);
- void clear();
-
- /// Generate llvm.loop.parallel metadata for loads and stores.
- bool IsParallel;
-
- /// State of loop vectorization or unrolling.
- enum LVEnableState { Unspecified, Enable, Disable, Full };
-
- /// Value for llvm.loop.vectorize.enable metadata.
- LVEnableState VectorizeEnable;
-
- /// Value for llvm.loop.unroll.* metadata (enable, disable, or full).
- LVEnableState UnrollEnable;
-
- /// Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full).
- LVEnableState UnrollAndJamEnable;
-
- /// Value for llvm.loop.vectorize.width metadata.
- unsigned VectorizeWidth;
-
- /// Value for llvm.loop.interleave.count metadata.
- unsigned InterleaveCount;
-
- /// llvm.unroll.
- unsigned UnrollCount;
-
- /// llvm.unroll.
- unsigned UnrollAndJamCount;
-
- /// Value for llvm.loop.distribute.enable metadata.
- LVEnableState DistributeEnable;
-
- /// Value for llvm.loop.pipeline.disable metadata.
- bool PipelineDisabled;
-
- /// Value for llvm.loop.pipeline.iicount metadata.
- unsigned PipelineInitiationInterval;
-};
-
-/// Information used when generating a structured loop.
-class LoopInfo {
-public:
- /// Construct a new LoopInfo for the loop with entry Header.
- LoopInfo(llvm::BasicBlock *Header, const LoopAttributes &Attrs,
- const llvm::DebugLoc &StartLoc, const llvm::DebugLoc &EndLoc);
-
- /// Get the loop id metadata for this loop.
- llvm::MDNode *getLoopID() const { return LoopID; }
-
- /// Get the header block of this loop.
- llvm::BasicBlock *getHeader() const { return Header; }
-
- /// Get the set of attributes active for this loop.
- const LoopAttributes &getAttributes() const { return Attrs; }
-
- /// Return this loop's access group or nullptr if it does not have one.
- llvm::MDNode *getAccessGroup() const { return AccGroup; }
-
-private:
- /// Loop ID metadata.
- llvm::MDNode *LoopID;
- /// Header block of this loop.
- llvm::BasicBlock *Header;
- /// The attributes for this loop.
- LoopAttributes Attrs;
- /// The access group for memory accesses parallel to this loop.
- llvm::MDNode *AccGroup = nullptr;
-};
-
-/// A stack of loop information corresponding to loop nesting levels.
-/// This stack can be used to prepare attributes which are applied when a loop
-/// is emitted.
-class LoopInfoStack {
- LoopInfoStack(const LoopInfoStack &) = delete;
- void operator=(const LoopInfoStack &) = delete;
-
-public:
- LoopInfoStack() {}
-
- /// Begin a new structured loop. The set of staged attributes will be
- /// applied to the loop and then cleared.
- void push(llvm::BasicBlock *Header, const llvm::DebugLoc &StartLoc,
- const llvm::DebugLoc &EndLoc);
-
- /// Begin a new structured loop. Stage attributes from the Attrs list.
- /// The staged attributes are applied to the loop and then cleared.
- void push(llvm::BasicBlock *Header, clang::ASTContext &Ctx,
- llvm::ArrayRef<const Attr *> Attrs, const llvm::DebugLoc &StartLoc,
- const llvm::DebugLoc &EndLoc);
-
- /// End the current loop.
- void pop();
-
- /// Return the top loop id metadata.
- llvm::MDNode *getCurLoopID() const { return getInfo().getLoopID(); }
-
- /// Return true if the top loop is parallel.
- bool getCurLoopParallel() const {
- return hasInfo() ? getInfo().getAttributes().IsParallel : false;
- }
-
- /// Function called by the CodeGenFunction when an instruction is
- /// created.
- void InsertHelper(llvm::Instruction *I) const;
-
- /// Set the next pushed loop as parallel.
- void setParallel(bool Enable = true) { StagedAttrs.IsParallel = Enable; }
-
- /// Set the next pushed loop 'vectorize.enable'
- void setVectorizeEnable(bool Enable = true) {
- StagedAttrs.VectorizeEnable =
- Enable ? LoopAttributes::Enable : LoopAttributes::Disable;
- }
-
- /// Set the next pushed loop as a distribution candidate.
- void setDistributeState(bool Enable = true) {
- StagedAttrs.DistributeEnable =
- Enable ? LoopAttributes::Enable : LoopAttributes::Disable;
- }
-
- /// Set the next pushed loop unroll state.
- void setUnrollState(const LoopAttributes::LVEnableState &State) {
- StagedAttrs.UnrollEnable = State;
- }
-
- /// Set the next pushed loop unroll_and_jam state.
- void setUnrollAndJamState(const LoopAttributes::LVEnableState &State) {
- StagedAttrs.UnrollAndJamEnable = State;
- }
-
- /// Set the vectorize width for the next loop pushed.
- void setVectorizeWidth(unsigned W) { StagedAttrs.VectorizeWidth = W; }
-
- /// Set the interleave count for the next loop pushed.
- void setInterleaveCount(unsigned C) { StagedAttrs.InterleaveCount = C; }
-
- /// Set the unroll count for the next loop pushed.
- void setUnrollCount(unsigned C) { StagedAttrs.UnrollCount = C; }
-
- /// \brief Set the unroll count for the next loop pushed.
- void setUnrollAndJamCount(unsigned C) { StagedAttrs.UnrollAndJamCount = C; }
-
- /// Set the pipeline disabled state.
- void setPipelineDisabled(bool S) { StagedAttrs.PipelineDisabled = S; }
-
- /// Set the pipeline initiation interval.
- void setPipelineInitiationInterval(unsigned C) {
- StagedAttrs.PipelineInitiationInterval = C;
- }
-
-private:
- /// Returns true if there is LoopInfo on the stack.
- bool hasInfo() const { return !Active.empty(); }
- /// Return the LoopInfo for the current loop. HasInfo should be called
- /// first to ensure LoopInfo is present.
- const LoopInfo &getInfo() const { return Active.back(); }
- /// The set of attributes that will be applied to the next pushed loop.
- LoopAttributes StagedAttrs;
- /// Stack of active loops.
- llvm::SmallVector<LoopInfo, 4> Active;
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGNonTrivialStruct.cpp
deleted file mode 100644
index c6a96a91262..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGNonTrivialStruct.cpp
+++ /dev/null
@@ -1,906 +0,0 @@
-//===--- CGNonTrivialStruct.cpp - Emit Special Functions for C Structs ----===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines functions to generate various special functions for C
-// structs.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "clang/AST/NonTrivialTypeVisitor.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include <array>
-
-using namespace clang;
-using namespace CodeGen;
-
-// Return the size of a field in number of bits.
-static uint64_t getFieldSize(const FieldDecl *FD, QualType FT,
- ASTContext &Ctx) {
- if (FD && FD->isBitField())
- return FD->getBitWidthValue(Ctx);
- return Ctx.getTypeSize(FT);
-}
-
-namespace {
-enum { DstIdx = 0, SrcIdx = 1 };
-const char *ValNameStr[2] = {"dst", "src"};
-
-template <class Derived> struct StructVisitor {
- StructVisitor(ASTContext &Ctx) : Ctx(Ctx) {}
-
- template <class... Ts>
- void visitStructFields(QualType QT, CharUnits CurStructOffset, Ts... Args) {
- const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();
-
- // Iterate over the fields of the struct.
- for (const FieldDecl *FD : RD->fields()) {
- QualType FT = FD->getType();
- FT = QT.isVolatileQualified() ? FT.withVolatile() : FT;
- asDerived().visit(FT, FD, CurStructOffset, Args...);
- }
-
- asDerived().flushTrivialFields(Args...);
- }
-
- template <class... Ts> void visitTrivial(Ts... Args) {}
-
- template <class... Ts> void visitCXXDestructor(Ts... Args) {
- llvm_unreachable("field of a C++ struct type is not expected");
- }
-
- template <class... Ts> void flushTrivialFields(Ts... Args) {}
-
- uint64_t getFieldOffsetInBits(const FieldDecl *FD) {
- return FD ? Ctx.getASTRecordLayout(FD->getParent())
- .getFieldOffset(FD->getFieldIndex())
- : 0;
- }
-
- CharUnits getFieldOffset(const FieldDecl *FD) {
- return Ctx.toCharUnitsFromBits(getFieldOffsetInBits(FD));
- }
-
- Derived &asDerived() { return static_cast<Derived &>(*this); }
-
- ASTContext &getContext() { return Ctx; }
- ASTContext &Ctx;
-};
-
-template <class Derived, bool IsMove>
-struct CopyStructVisitor : StructVisitor<Derived>,
- CopiedTypeVisitor<Derived, IsMove> {
- using StructVisitor<Derived>::asDerived;
- using Super = CopiedTypeVisitor<Derived, IsMove>;
-
- CopyStructVisitor(ASTContext &Ctx) : StructVisitor<Derived>(Ctx) {}
-
- template <class... Ts>
- void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT,
- const FieldDecl *FD, CharUnits CurStructOffsset,
- Ts &&... Args) {
- if (PCK)
- asDerived().flushTrivialFields(std::forward<Ts>(Args)...);
- }
-
- template <class... Ts>
- void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT,
- const FieldDecl *FD, CharUnits CurStructOffsset,
- Ts &&... Args) {
- if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
- asDerived().visitArray(PCK, AT, FT.isVolatileQualified(), FD,
- CurStructOffsset, std::forward<Ts>(Args)...);
- return;
- }
-
- Super::visitWithKind(PCK, FT, FD, CurStructOffsset,
- std::forward<Ts>(Args)...);
- }
-
- template <class... Ts>
- void visitTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset,
- Ts... Args) {
- assert(!FT.isVolatileQualified() && "volatile field not expected");
- ASTContext &Ctx = asDerived().getContext();
- uint64_t FieldSize = getFieldSize(FD, FT, Ctx);
-
- // Ignore zero-sized fields.
- if (FieldSize == 0)
- return;
-
- uint64_t FStartInBits = asDerived().getFieldOffsetInBits(FD);
- uint64_t FEndInBits = FStartInBits + FieldSize;
- uint64_t RoundedFEnd = llvm::alignTo(FEndInBits, Ctx.getCharWidth());
-
- // Set Start if this is the first field of a sequence of trivial fields.
- if (Start == End)
- Start = CurStructOffset + Ctx.toCharUnitsFromBits(FStartInBits);
- End = CurStructOffset + Ctx.toCharUnitsFromBits(RoundedFEnd);
- }
-
- CharUnits Start = CharUnits::Zero(), End = CharUnits::Zero();
-};
-
-// This function creates the mangled name of a special function of a non-trivial
-// C struct. Since there is no ODR in C, the function is mangled based on the
-// struct contents and not the name. The mangled name has the following
-// structure:
-//
-// <function-name> ::= <prefix> <alignment-info> "_" <struct-field-info>
-// <prefix> ::= "__destructor_" | "__default_constructor_" |
-// "__copy_constructor_" | "__move_constructor_" |
-// "__copy_assignment_" | "__move_assignment_"
-// <alignment-info> ::= <dst-alignment> ["_" <src-alignment>]
-// <struct-field-info> ::= <field-info>+
-// <field-info> ::= <struct-or-scalar-field-info> | <array-field-info>
-// <struct-or-scalar-field-info> ::= <struct-field-info> | <strong-field-info> |
-// <trivial-field-info>
-// <array-field-info> ::= "_AB" <array-offset> "s" <element-size> "n"
-// <num-elements> <innermost-element-info> "_AE"
-// <innermost-element-info> ::= <struct-or-scalar-field-info>
-// <strong-field-info> ::= "_s" ["b"] ["v"] <field-offset>
-// <trivial-field-info> ::= "_t" ["v"] <field-offset> "_" <field-size>
-
-template <class Derived> struct GenFuncNameBase {
- std::string getVolatileOffsetStr(bool IsVolatile, CharUnits Offset) {
- std::string S;
- if (IsVolatile)
- S = "v";
- S += llvm::to_string(Offset.getQuantity());
- return S;
- }
-
- void visitARCStrong(QualType FT, const FieldDecl *FD,
- CharUnits CurStructOffset) {
- appendStr("_s");
- if (FT->isBlockPointerType())
- appendStr("b");
- CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
- appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));
- }
-
- void visitARCWeak(QualType FT, const FieldDecl *FD,
- CharUnits CurStructOffset) {
- appendStr("_w");
- CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
- appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));
- }
-
- void visitStruct(QualType QT, const FieldDecl *FD,
- CharUnits CurStructOffset) {
- CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
- asDerived().visitStructFields(QT, FieldOffset);
- }
-
- template <class FieldKind>
- void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,
- const FieldDecl *FD, CharUnits CurStructOffset) {
- // String for non-volatile trivial fields is emitted when
- // flushTrivialFields is called.
- if (!FK)
- return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset);
-
- asDerived().flushTrivialFields();
- CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
- ASTContext &Ctx = asDerived().getContext();
- const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
- unsigned NumElts = Ctx.getConstantArrayElementCount(CAT);
- QualType EltTy = Ctx.getBaseElementType(CAT);
- CharUnits EltSize = Ctx.getTypeSizeInChars(EltTy);
- appendStr("_AB" + llvm::to_string(FieldOffset.getQuantity()) + "s" +
- llvm::to_string(EltSize.getQuantity()) + "n" +
- llvm::to_string(NumElts));
- EltTy = IsVolatile ? EltTy.withVolatile() : EltTy;
- asDerived().visitWithKind(FK, EltTy, nullptr, FieldOffset);
- appendStr("_AE");
- }
-
- void appendStr(StringRef Str) { Name += Str; }
-
- std::string getName(QualType QT, bool IsVolatile) {
- QT = IsVolatile ? QT.withVolatile() : QT;
- asDerived().visitStructFields(QT, CharUnits::Zero());
- return Name;
- }
-
- Derived &asDerived() { return static_cast<Derived &>(*this); }
-
- std::string Name;
-};
-
-template <class Derived>
-struct GenUnaryFuncName : StructVisitor<Derived>, GenFuncNameBase<Derived> {
- GenUnaryFuncName(StringRef Prefix, CharUnits DstAlignment, ASTContext &Ctx)
- : StructVisitor<Derived>(Ctx) {
- this->appendStr(Prefix);
- this->appendStr(llvm::to_string(DstAlignment.getQuantity()));
- }
-};
-
-// Helper function to create a null constant.
-static llvm::Constant *getNullForVariable(Address Addr) {
- llvm::Type *Ty = Addr.getElementType();
- return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(Ty));
-}
-
-template <bool IsMove>
-struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>,
- GenFuncNameBase<GenBinaryFuncName<IsMove>> {
-
- GenBinaryFuncName(StringRef Prefix, CharUnits DstAlignment,
- CharUnits SrcAlignment, ASTContext &Ctx)
- : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>(Ctx) {
- this->appendStr(Prefix);
- this->appendStr(llvm::to_string(DstAlignment.getQuantity()));
- this->appendStr("_" + llvm::to_string(SrcAlignment.getQuantity()));
- }
-
- void flushTrivialFields() {
- if (this->Start == this->End)
- return;
-
- this->appendStr("_t" + llvm::to_string(this->Start.getQuantity()) + "w" +
- llvm::to_string((this->End - this->Start).getQuantity()));
-
- this->Start = this->End = CharUnits::Zero();
- }
-
- void visitVolatileTrivial(QualType FT, const FieldDecl *FD,
- CharUnits CurStackOffset) {
- // Because volatile fields can be bit-fields and are individually copied,
- // their offset and width are in bits.
- uint64_t OffsetInBits =
- this->Ctx.toBits(CurStackOffset) + this->getFieldOffsetInBits(FD);
- this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" +
- llvm::to_string(getFieldSize(FD, FT, this->Ctx)));
- }
-};
-
-struct GenDefaultInitializeFuncName
- : GenUnaryFuncName<GenDefaultInitializeFuncName>,
- DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName> {
- using Super = DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName>;
- GenDefaultInitializeFuncName(CharUnits DstAlignment, ASTContext &Ctx)
- : GenUnaryFuncName<GenDefaultInitializeFuncName>("__default_constructor_",
- DstAlignment, Ctx) {}
- void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
- const FieldDecl *FD, CharUnits CurStructOffset) {
- if (const auto *AT = getContext().getAsArrayType(FT)) {
- visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset);
- return;
- }
-
- Super::visitWithKind(PDIK, FT, FD, CurStructOffset);
- }
-};
-
-struct GenDestructorFuncName : GenUnaryFuncName<GenDestructorFuncName>,
- DestructedTypeVisitor<GenDestructorFuncName> {
- using Super = DestructedTypeVisitor<GenDestructorFuncName>;
- GenDestructorFuncName(const char *Prefix, CharUnits DstAlignment,
- ASTContext &Ctx)
- : GenUnaryFuncName<GenDestructorFuncName>(Prefix, DstAlignment,
- Ctx) {}
- void visitWithKind(QualType::DestructionKind DK, QualType FT,
- const FieldDecl *FD, CharUnits CurStructOffset) {
- if (const auto *AT = getContext().getAsArrayType(FT)) {
- visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset);
- return;
- }
-
- Super::visitWithKind(DK, FT, FD, CurStructOffset);
- }
-};
-
-// Helper function that creates CGFunctionInfo for an N-ary special function.
-template <size_t N>
-static const CGFunctionInfo &getFunctionInfo(CodeGenModule &CGM,
- FunctionArgList &Args) {
- ASTContext &Ctx = CGM.getContext();
- llvm::SmallVector<ImplicitParamDecl *, N> Params;
- QualType ParamTy = Ctx.getPointerType(Ctx.VoidPtrTy);
-
- for (unsigned I = 0; I < N; ++I)
- Params.push_back(ImplicitParamDecl::Create(
- Ctx, nullptr, SourceLocation(), &Ctx.Idents.get(ValNameStr[I]), ParamTy,
- ImplicitParamDecl::Other));
-
- for (auto &P : Params)
- Args.push_back(P);
-
- return CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
-}
-
-// Template classes that are used as bases for classes that emit special
-// functions.
-template <class Derived> struct GenFuncBase {
- template <size_t N>
- void visitStruct(QualType FT, const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, N> Addrs) {
- this->asDerived().callSpecialFunction(
- FT, CurStackOffset + asDerived().getFieldOffset(FD), Addrs);
- }
-
- template <class FieldKind, size_t N>
- void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,
- const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, N> Addrs) {
- // Non-volatile trivial fields are copied when flushTrivialFields is called.
- if (!FK)
- return asDerived().visitTrivial(QualType(AT, 0), FD, CurStackOffset,
- Addrs);
-
- asDerived().flushTrivialFields(Addrs);
- CodeGenFunction &CGF = *this->CGF;
- ASTContext &Ctx = CGF.getContext();
-
- // Compute the end address.
- QualType BaseEltQT;
- std::array<Address, N> StartAddrs = Addrs;
- for (unsigned I = 0; I < N; ++I)
- StartAddrs[I] = getAddrWithOffset(Addrs[I], CurStackOffset, FD);
- Address DstAddr = StartAddrs[DstIdx];
- llvm::Value *NumElts = CGF.emitArrayLength(AT, BaseEltQT, DstAddr);
- unsigned BaseEltSize = Ctx.getTypeSizeInChars(BaseEltQT).getQuantity();
- llvm::Value *BaseEltSizeVal =
- llvm::ConstantInt::get(NumElts->getType(), BaseEltSize);
- llvm::Value *SizeInBytes =
- CGF.Builder.CreateNUWMul(BaseEltSizeVal, NumElts);
- Address BC = CGF.Builder.CreateBitCast(DstAddr, CGF.CGM.Int8PtrTy);
- llvm::Value *DstArrayEnd =
- CGF.Builder.CreateInBoundsGEP(BC.getPointer(), SizeInBytes);
- DstArrayEnd = CGF.Builder.CreateBitCast(DstArrayEnd, CGF.CGM.Int8PtrPtrTy,
- "dstarray.end");
- llvm::BasicBlock *PreheaderBB = CGF.Builder.GetInsertBlock();
-
- // Create the header block and insert the phi instructions.
- llvm::BasicBlock *HeaderBB = CGF.createBasicBlock("loop.header");
- CGF.EmitBlock(HeaderBB);
- llvm::PHINode *PHIs[N];
-
- for (unsigned I = 0; I < N; ++I) {
- PHIs[I] = CGF.Builder.CreatePHI(CGF.CGM.Int8PtrPtrTy, 2, "addr.cur");
- PHIs[I]->addIncoming(StartAddrs[I].getPointer(), PreheaderBB);
- }
-
- // Create the exit and loop body blocks.
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock("loop.exit");
- llvm::BasicBlock *LoopBB = CGF.createBasicBlock("loop.body");
-
- // Emit the comparison and conditional branch instruction that jumps to
- // either the exit or the loop body.
- llvm::Value *Done =
- CGF.Builder.CreateICmpEQ(PHIs[DstIdx], DstArrayEnd, "done");
- CGF.Builder.CreateCondBr(Done, ExitBB, LoopBB);
-
- // Visit the element of the array in the loop body.
- CGF.EmitBlock(LoopBB);
- QualType EltQT = AT->getElementType();
- CharUnits EltSize = Ctx.getTypeSizeInChars(EltQT);
- std::array<Address, N> NewAddrs = Addrs;
-
- for (unsigned I = 0; I < N; ++I)
- NewAddrs[I] = Address(
- PHIs[I], StartAddrs[I].getAlignment().alignmentAtOffset(EltSize));
-
- EltQT = IsVolatile ? EltQT.withVolatile() : EltQT;
- this->asDerived().visitWithKind(FK, EltQT, nullptr, CharUnits::Zero(),
- NewAddrs);
-
- LoopBB = CGF.Builder.GetInsertBlock();
-
- for (unsigned I = 0; I < N; ++I) {
- // Instrs to update the destination and source addresses.
- // Update phi instructions.
- NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize);
- PHIs[I]->addIncoming(NewAddrs[I].getPointer(), LoopBB);
- }
-
- // Insert an unconditional branch to the header block.
- CGF.Builder.CreateBr(HeaderBB);
- CGF.EmitBlock(ExitBB);
- }
-
- /// Return an address with the specified offset from the passed address.
- Address getAddrWithOffset(Address Addr, CharUnits Offset) {
- assert(Addr.isValid() && "invalid address");
- if (Offset.getQuantity() == 0)
- return Addr;
- Addr = CGF->Builder.CreateBitCast(Addr, CGF->CGM.Int8PtrTy);
- Addr = CGF->Builder.CreateConstInBoundsGEP(Addr, Offset.getQuantity(),
- CharUnits::One());
- return CGF->Builder.CreateBitCast(Addr, CGF->CGM.Int8PtrPtrTy);
- }
-
- Address getAddrWithOffset(Address Addr, CharUnits StructFieldOffset,
- const FieldDecl *FD) {
- return getAddrWithOffset(Addr, StructFieldOffset +
- asDerived().getFieldOffset(FD));
- }
-
- template <size_t N>
- llvm::Function *
- getFunction(StringRef FuncName, QualType QT, std::array<Address, N> Addrs,
- std::array<CharUnits, N> Alignments, CodeGenModule &CGM) {
- // If the special function already exists in the module, return it.
- if (llvm::Function *F = CGM.getModule().getFunction(FuncName)) {
- bool WrongType = false;
- if (!F->getReturnType()->isVoidTy())
- WrongType = true;
- else {
- for (const llvm::Argument &Arg : F->args())
- if (Arg.getType() != CGM.Int8PtrPtrTy)
- WrongType = true;
- }
-
- if (WrongType) {
- std::string FuncName = F->getName();
- SourceLocation Loc = QT->castAs<RecordType>()->getDecl()->getLocation();
- CGM.Error(Loc, "special function " + FuncName +
- " for non-trivial C struct has incorrect type");
- return nullptr;
- }
- return F;
- }
-
- ASTContext &Ctx = CGM.getContext();
- FunctionArgList Args;
- const CGFunctionInfo &FI = getFunctionInfo<N>(CGM, Args);
- llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *F =
- llvm::Function::Create(FuncTy, llvm::GlobalValue::LinkOnceODRLinkage,
- FuncName, &CGM.getModule());
- F->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, F);
- CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F);
- IdentifierInfo *II = &Ctx.Idents.get(FuncName);
- FunctionDecl *FD = FunctionDecl::Create(
- Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
- II, Ctx.getFunctionType(Ctx.VoidTy, llvm::None, {}), nullptr,
- SC_PrivateExtern, false, false);
- CodeGenFunction NewCGF(CGM);
- setCGF(&NewCGF);
- CGF->StartFunction(FD, Ctx.VoidTy, F, FI, Args);
-
- for (unsigned I = 0; I < N; ++I) {
- llvm::Value *V = CGF->Builder.CreateLoad(CGF->GetAddrOfLocalVar(Args[I]));
- Addrs[I] = Address(V, Alignments[I]);
- }
-
- asDerived().visitStructFields(QT, CharUnits::Zero(), Addrs);
- CGF->FinishFunction();
- return F;
- }
-
- template <size_t N>
- void callFunc(StringRef FuncName, QualType QT, std::array<Address, N> Addrs,
- CodeGenFunction &CallerCGF) {
- std::array<CharUnits, N> Alignments;
- llvm::Value *Ptrs[N];
-
- for (unsigned I = 0; I < N; ++I) {
- Alignments[I] = Addrs[I].getAlignment();
- Ptrs[I] =
- CallerCGF.Builder.CreateBitCast(Addrs[I], CallerCGF.CGM.Int8PtrPtrTy)
- .getPointer();
- }
-
- if (llvm::Function *F =
- getFunction(FuncName, QT, Addrs, Alignments, CallerCGF.CGM))
- CallerCGF.EmitNounwindRuntimeCall(F, Ptrs);
- }
-
- Derived &asDerived() { return static_cast<Derived &>(*this); }
-
- void setCGF(CodeGenFunction *F) { CGF = F; }
-
- CodeGenFunction *CGF = nullptr;
-};
-
-template <class Derived, bool IsMove>
-struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>,
- GenFuncBase<Derived> {
- GenBinaryFunc(ASTContext &Ctx) : CopyStructVisitor<Derived, IsMove>(Ctx) {}
-
- void flushTrivialFields(std::array<Address, 2> Addrs) {
- CharUnits Size = this->End - this->Start;
-
- if (Size.getQuantity() == 0)
- return;
-
- Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], this->Start);
- Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], this->Start);
-
- // Emit memcpy.
- if (Size.getQuantity() >= 16 || !llvm::isPowerOf2_32(Size.getQuantity())) {
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(this->CGF->SizeTy, Size.getQuantity());
- DstAddr =
- this->CGF->Builder.CreateElementBitCast(DstAddr, this->CGF->Int8Ty);
- SrcAddr =
- this->CGF->Builder.CreateElementBitCast(SrcAddr, this->CGF->Int8Ty);
- this->CGF->Builder.CreateMemCpy(DstAddr, SrcAddr, SizeVal, false);
- } else {
- llvm::Type *Ty = llvm::Type::getIntNTy(
- this->CGF->getLLVMContext(),
- Size.getQuantity() * this->CGF->getContext().getCharWidth());
- DstAddr = this->CGF->Builder.CreateElementBitCast(DstAddr, Ty);
- SrcAddr = this->CGF->Builder.CreateElementBitCast(SrcAddr, Ty);
- llvm::Value *SrcVal = this->CGF->Builder.CreateLoad(SrcAddr, false);
- this->CGF->Builder.CreateStore(SrcVal, DstAddr, false);
- }
-
- this->Start = this->End = CharUnits::Zero();
- }
-
- template <class... Ts>
- void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits Offset,
- std::array<Address, 2> Addrs) {
- LValue DstLV, SrcLV;
- if (FD) {
- QualType RT = QualType(FD->getParent()->getTypeForDecl(), 0);
- llvm::PointerType *PtrTy = this->CGF->ConvertType(RT)->getPointerTo();
- Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset);
- LValue DstBase = this->CGF->MakeAddrLValue(
- this->CGF->Builder.CreateBitCast(DstAddr, PtrTy), FT);
- DstLV = this->CGF->EmitLValueForField(DstBase, FD);
- Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], Offset);
- LValue SrcBase = this->CGF->MakeAddrLValue(
- this->CGF->Builder.CreateBitCast(SrcAddr, PtrTy), FT);
- SrcLV = this->CGF->EmitLValueForField(SrcBase, FD);
- } else {
- llvm::PointerType *Ty = this->CGF->ConvertType(FT)->getPointerTo();
- Address DstAddr = this->CGF->Builder.CreateBitCast(Addrs[DstIdx], Ty);
- Address SrcAddr = this->CGF->Builder.CreateBitCast(Addrs[SrcIdx], Ty);
- DstLV = this->CGF->MakeAddrLValue(DstAddr, FT);
- SrcLV = this->CGF->MakeAddrLValue(SrcAddr, FT);
- }
- RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation());
- this->CGF->EmitStoreThroughLValue(SrcVal, DstLV);
- }
-};
-
-// These classes that emit the special functions for a non-trivial struct.
-struct GenDestructor : StructVisitor<GenDestructor>,
- GenFuncBase<GenDestructor>,
- DestructedTypeVisitor<GenDestructor> {
- using Super = DestructedTypeVisitor<GenDestructor>;
- GenDestructor(ASTContext &Ctx) : StructVisitor<GenDestructor>(Ctx) {}
-
- void visitWithKind(QualType::DestructionKind DK, QualType FT,
- const FieldDecl *FD, CharUnits CurStructOffset,
- std::array<Address, 1> Addrs) {
- if (const auto *AT = getContext().getAsArrayType(FT)) {
- visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset, Addrs);
- return;
- }
-
- Super::visitWithKind(DK, FT, FD, CurStructOffset, Addrs);
- }
-
- void visitARCStrong(QualType QT, const FieldDecl *FD,
- CharUnits CurStackOffset, std::array<Address, 1> Addrs) {
- CGF->destroyARCStrongImprecise(
- *CGF, getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
- }
-
- void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, 1> Addrs) {
- CGF->destroyARCWeak(
- *CGF, getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
- }
-
- void callSpecialFunction(QualType FT, CharUnits Offset,
- std::array<Address, 1> Addrs) {
- CGF->callCStructDestructor(
- CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));
- }
-};
-
-struct GenDefaultInitialize
- : StructVisitor<GenDefaultInitialize>,
- GenFuncBase<GenDefaultInitialize>,
- DefaultInitializedTypeVisitor<GenDefaultInitialize> {
- using Super = DefaultInitializedTypeVisitor<GenDefaultInitialize>;
- typedef GenFuncBase<GenDefaultInitialize> GenFuncBaseTy;
-
- GenDefaultInitialize(ASTContext &Ctx)
- : StructVisitor<GenDefaultInitialize>(Ctx) {}
-
- void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
- const FieldDecl *FD, CharUnits CurStructOffset,
- std::array<Address, 1> Addrs) {
- if (const auto *AT = getContext().getAsArrayType(FT)) {
- visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset,
- Addrs);
- return;
- }
-
- Super::visitWithKind(PDIK, FT, FD, CurStructOffset, Addrs);
- }
-
- void visitARCStrong(QualType QT, const FieldDecl *FD,
- CharUnits CurStackOffset, std::array<Address, 1> Addrs) {
- CGF->EmitNullInitialization(
- getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
- }
-
- void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, 1> Addrs) {
- CGF->EmitNullInitialization(
- getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
- }
-
- template <class FieldKind, size_t... Is>
- void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,
- const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, 1> Addrs) {
- if (!FK)
- return visitTrivial(QualType(AT, 0), FD, CurStackOffset, Addrs);
-
- ASTContext &Ctx = getContext();
- CharUnits Size = Ctx.getTypeSizeInChars(QualType(AT, 0));
- QualType EltTy = Ctx.getBaseElementType(QualType(AT, 0));
-
- if (Size < CharUnits::fromQuantity(16) || EltTy->getAs<RecordType>()) {
- GenFuncBaseTy::visitArray(FK, AT, IsVolatile, FD, CurStackOffset, Addrs);
- return;
- }
-
- llvm::Constant *SizeVal = CGF->Builder.getInt64(Size.getQuantity());
- Address DstAddr = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Address Loc = CGF->Builder.CreateElementBitCast(DstAddr, CGF->Int8Ty);
- CGF->Builder.CreateMemSet(Loc, CGF->Builder.getInt8(0), SizeVal,
- IsVolatile);
- }
-
- void callSpecialFunction(QualType FT, CharUnits Offset,
- std::array<Address, 1> Addrs) {
- CGF->callCStructDefaultConstructor(
- CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));
- }
-};
-
-struct GenCopyConstructor : GenBinaryFunc<GenCopyConstructor, false> {
- GenCopyConstructor(ASTContext &Ctx)
- : GenBinaryFunc<GenCopyConstructor, false>(Ctx) {}
-
- void visitARCStrong(QualType QT, const FieldDecl *FD,
- CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- llvm::Value *SrcVal = CGF->EmitLoadOfScalar(
- Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());
- llvm::Value *Val = CGF->EmitARCRetain(QT, SrcVal);
- CGF->EmitStoreOfScalar(Val, CGF->MakeAddrLValue(Addrs[DstIdx], QT), true);
- }
-
- void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- CGF->EmitARCCopyWeak(Addrs[DstIdx], Addrs[SrcIdx]);
- }
-
- void callSpecialFunction(QualType FT, CharUnits Offset,
- std::array<Address, 2> Addrs) {
- CGF->callCStructCopyConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
- CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
- }
-};
-
-struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> {
- GenMoveConstructor(ASTContext &Ctx)
- : GenBinaryFunc<GenMoveConstructor, true>(Ctx) {}
-
- void visitARCStrong(QualType QT, const FieldDecl *FD,
- CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
- llvm::Value *SrcVal =
- CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
- CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
- CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT),
- /* isInitialization */ true);
- }
-
- void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- CGF->EmitARCMoveWeak(Addrs[DstIdx], Addrs[SrcIdx]);
- }
-
- void callSpecialFunction(QualType FT, CharUnits Offset,
- std::array<Address, 2> Addrs) {
- CGF->callCStructMoveConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
- CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
- }
-};
-
-struct GenCopyAssignment : GenBinaryFunc<GenCopyAssignment, false> {
- GenCopyAssignment(ASTContext &Ctx)
- : GenBinaryFunc<GenCopyAssignment, false>(Ctx) {}
-
- void visitARCStrong(QualType QT, const FieldDecl *FD,
- CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- llvm::Value *SrcVal = CGF->EmitLoadOfScalar(
- Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());
- CGF->EmitARCStoreStrong(CGF->MakeAddrLValue(Addrs[DstIdx], QT), SrcVal,
- false);
- }
-
- void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- CGF->emitARCCopyAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]);
- }
-
- void callSpecialFunction(QualType FT, CharUnits Offset,
- std::array<Address, 2> Addrs) {
- CGF->callCStructCopyAssignmentOperator(
- CGF->MakeAddrLValue(Addrs[DstIdx], FT),
- CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
- }
-};
-
-struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> {
- GenMoveAssignment(ASTContext &Ctx)
- : GenBinaryFunc<GenMoveAssignment, true>(Ctx) {}
-
- void visitARCStrong(QualType QT, const FieldDecl *FD,
- CharUnits CurStackOffset, std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
- llvm::Value *SrcVal =
- CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
- CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
- LValue DstLV = CGF->MakeAddrLValue(Addrs[DstIdx], QT);
- llvm::Value *DstVal =
- CGF->EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal();
- CGF->EmitStoreOfScalar(SrcVal, DstLV);
- CGF->EmitARCRelease(DstVal, ARCImpreciseLifetime);
- }
-
- void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
- std::array<Address, 2> Addrs) {
- Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
- Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
- CGF->emitARCMoveAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]);
- }
-
- void callSpecialFunction(QualType FT, CharUnits Offset,
- std::array<Address, 2> Addrs) {
- CGF->callCStructMoveAssignmentOperator(
- CGF->MakeAddrLValue(Addrs[DstIdx], FT),
- CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
- }
-};
-
-} // namespace
-
-void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF,
- Address Addr, QualType Type) {
- CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Type));
-}
-
-// Default-initialize a variable that is a non-trivial struct or an array of
-// such structure.
-void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) {
- GenDefaultInitialize Gen(getContext());
- Address DstPtr = Builder.CreateBitCast(Dst.getAddress(), CGM.Int8PtrPtrTy);
- Gen.setCGF(this);
- QualType QT = Dst.getType();
- QT = Dst.isVolatile() ? QT.withVolatile() : QT;
- Gen.visit(QT, nullptr, CharUnits::Zero(), std::array<Address, 1>({{DstPtr}}));
-}
-
-template <class G, size_t N>
-static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT,
- bool IsVolatile, CodeGenFunction &CGF,
- std::array<Address, N> Addrs) {
- for (unsigned I = 0; I < N; ++I)
- Addrs[I] = CGF.Builder.CreateBitCast(Addrs[I], CGF.CGM.Int8PtrPtrTy);
- QT = IsVolatile ? QT.withVolatile() : QT;
- Gen.callFunc(FuncName, QT, Addrs, CGF);
-}
-
-// Functions to emit calls to the special functions of a non-trivial C struct.
-void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) {
- bool IsVolatile = Dst.isVolatile();
- Address DstPtr = Dst.getAddress();
- QualType QT = Dst.getType();
- GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext());
- std::string FuncName = GenName.getName(QT, IsVolatile);
- callSpecialFunction(GenDefaultInitialize(getContext()), FuncName, QT,
- IsVolatile, *this, std::array<Address, 1>({{DstPtr}}));
-}
-
-std::string
-CodeGenFunction::getNonTrivialCopyConstructorStr(QualType QT,
- CharUnits Alignment,
- bool IsVolatile,
- ASTContext &Ctx) {
- GenBinaryFuncName<false> GenName("", Alignment, Alignment, Ctx);
- return GenName.getName(QT, IsVolatile);
-}
-
-std::string
-CodeGenFunction::getNonTrivialDestructorStr(QualType QT, CharUnits Alignment,
- bool IsVolatile, ASTContext &Ctx) {
- GenDestructorFuncName GenName("", Alignment, Ctx);
- return GenName.getName(QT, IsVolatile);
-}
-
-void CodeGenFunction::callCStructDestructor(LValue Dst) {
- bool IsVolatile = Dst.isVolatile();
- Address DstPtr = Dst.getAddress();
- QualType QT = Dst.getType();
- GenDestructorFuncName GenName("__destructor_", DstPtr.getAlignment(),
- getContext());
- std::string FuncName = GenName.getName(QT, IsVolatile);
- callSpecialFunction(GenDestructor(getContext()), FuncName, QT, IsVolatile,
- *this, std::array<Address, 1>({{DstPtr}}));
-}
-
-void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) {
- bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
- QualType QT = Dst.getType();
- GenBinaryFuncName<false> GenName("__copy_constructor_", DstPtr.getAlignment(),
- SrcPtr.getAlignment(), getContext());
- std::string FuncName = GenName.getName(QT, IsVolatile);
- callSpecialFunction(GenCopyConstructor(getContext()), FuncName, QT,
- IsVolatile, *this,
- std::array<Address, 2>({{DstPtr, SrcPtr}}));
-}
-
-void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src
-
-) {
- bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
- QualType QT = Dst.getType();
- GenBinaryFuncName<false> GenName("__copy_assignment_", DstPtr.getAlignment(),
- SrcPtr.getAlignment(), getContext());
- std::string FuncName = GenName.getName(QT, IsVolatile);
- callSpecialFunction(GenCopyAssignment(getContext()), FuncName, QT, IsVolatile,
- *this, std::array<Address, 2>({{DstPtr, SrcPtr}}));
-}
-
-void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) {
- bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
- QualType QT = Dst.getType();
- GenBinaryFuncName<true> GenName("__move_constructor_", DstPtr.getAlignment(),
- SrcPtr.getAlignment(), getContext());
- std::string FuncName = GenName.getName(QT, IsVolatile);
- callSpecialFunction(GenMoveConstructor(getContext()), FuncName, QT,
- IsVolatile, *this,
- std::array<Address, 2>({{DstPtr, SrcPtr}}));
-}
-
-void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src
-
-) {
- bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
- Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
- QualType QT = Dst.getType();
- GenBinaryFuncName<true> GenName("__move_assignment_", DstPtr.getAlignment(),
- SrcPtr.getAlignment(), getContext());
- std::string FuncName = GenName.getName(QT, IsVolatile);
- callSpecialFunction(GenMoveAssignment(getContext()), FuncName, QT, IsVolatile,
- *this, std::array<Address, 2>({{DstPtr, SrcPtr}}));
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
deleted file mode 100644
index 9c66ff0e8fb..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
+++ /dev/null
@@ -1,3665 +0,0 @@
-//===---- CGObjC.cpp - Emit LLVM Code for Objective-C ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Objective-C code as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGDebugInfo.h"
-#include "CGObjCRuntime.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/InlineAsm.h"
-using namespace clang;
-using namespace CodeGen;
-
-typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
-static TryEmitResult
-tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
-static RValue AdjustObjCObjectType(CodeGenFunction &CGF,
- QualType ET,
- RValue Result);
-
-/// Given the address of a variable of pointer type, find the correct
-/// null to store into it.
-static llvm::Constant *getNullForVariable(Address addr) {
- llvm::Type *type = addr.getElementType();
- return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(type));
-}
-
-/// Emits an instance of NSConstantString representing the object.
-llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
-{
- llvm::Constant *C =
- CGM.getObjCRuntime().GenerateConstantString(E->getString()).getPointer();
- // FIXME: This bitcast should just be made an invariant on the Runtime.
- return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
-}
-
-/// EmitObjCBoxedExpr - This routine generates code to call
-/// the appropriate expression boxing method. This will either be
-/// one of +[NSNumber numberWith<Type>:], or +[NSString stringWithUTF8String:],
-/// or [NSValue valueWithBytes:objCType:].
-///
-llvm::Value *
-CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
- // Generate the correct selector for this literal's concrete type.
- // Get the method.
- const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod();
- const Expr *SubExpr = E->getSubExpr();
- assert(BoxingMethod && "BoxingMethod is null");
- assert(BoxingMethod->isClassMethod() && "BoxingMethod must be a class method");
- Selector Sel = BoxingMethod->getSelector();
-
- // Generate a reference to the class pointer, which will be the receiver.
- // Assumes that the method was introduced in the class that should be
- // messaged (avoids pulling it out of the result type).
- CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
- llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl);
-
- CallArgList Args;
- const ParmVarDecl *ArgDecl = *BoxingMethod->param_begin();
- QualType ArgQT = ArgDecl->getType().getUnqualifiedType();
-
- // ObjCBoxedExpr supports boxing of structs and unions
- // via [NSValue valueWithBytes:objCType:]
- const QualType ValueType(SubExpr->getType().getCanonicalType());
- if (ValueType->isObjCBoxableRecordType()) {
- // Emit CodeGen for first parameter
- // and cast value to correct type
- Address Temporary = CreateMemTemp(SubExpr->getType());
- EmitAnyExprToMem(SubExpr, Temporary, Qualifiers(), /*isInit*/ true);
- Address BitCast = Builder.CreateBitCast(Temporary, ConvertType(ArgQT));
- Args.add(RValue::get(BitCast.getPointer()), ArgQT);
-
- // Create char array to store type encoding
- std::string Str;
- getContext().getObjCEncodingForType(ValueType, Str);
- llvm::Constant *GV = CGM.GetAddrOfConstantCString(Str).getPointer();
-
- // Cast type encoding to correct type
- const ParmVarDecl *EncodingDecl = BoxingMethod->parameters()[1];
- QualType EncodingQT = EncodingDecl->getType().getUnqualifiedType();
- llvm::Value *Cast = Builder.CreateBitCast(GV, ConvertType(EncodingQT));
-
- Args.add(RValue::get(Cast), EncodingQT);
- } else {
- Args.add(EmitAnyExpr(SubExpr), ArgQT);
- }
-
- RValue result = Runtime.GenerateMessageSend(
- *this, ReturnValueSlot(), BoxingMethod->getReturnType(), Sel, Receiver,
- Args, ClassDecl, BoxingMethod);
- return Builder.CreateBitCast(result.getScalarVal(),
- ConvertType(E->getType()));
-}
-
-llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
- const ObjCMethodDecl *MethodWithObjects) {
- ASTContext &Context = CGM.getContext();
- const ObjCDictionaryLiteral *DLE = nullptr;
- const ObjCArrayLiteral *ALE = dyn_cast<ObjCArrayLiteral>(E);
- if (!ALE)
- DLE = cast<ObjCDictionaryLiteral>(E);
-
- // Optimize empty collections by referencing constants, when available.
- uint64_t NumElements =
- ALE ? ALE->getNumElements() : DLE->getNumElements();
- if (NumElements == 0 && CGM.getLangOpts().ObjCRuntime.hasEmptyCollections()) {
- StringRef ConstantName = ALE ? "__NSArray0__" : "__NSDictionary0__";
- QualType IdTy(CGM.getContext().getObjCIdType());
- llvm::Constant *Constant =
- CGM.CreateRuntimeVariable(ConvertType(IdTy), ConstantName);
- LValue LV = MakeNaturalAlignAddrLValue(Constant, IdTy);
- llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getBeginLoc());
- cast<llvm::LoadInst>(Ptr)->setMetadata(
- CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(getLLVMContext(), None));
- return Builder.CreateBitCast(Ptr, ConvertType(E->getType()));
- }
-
- // Compute the type of the array we're initializing.
- llvm::APInt APNumElements(Context.getTypeSize(Context.getSizeType()),
- NumElements);
- QualType ElementType = Context.getObjCIdType().withConst();
- QualType ElementArrayType
- = Context.getConstantArrayType(ElementType, APNumElements,
- ArrayType::Normal, /*IndexTypeQuals=*/0);
-
- // Allocate the temporary array(s).
- Address Objects = CreateMemTemp(ElementArrayType, "objects");
- Address Keys = Address::invalid();
- if (DLE)
- Keys = CreateMemTemp(ElementArrayType, "keys");
-
- // In ARC, we may need to do extra work to keep all the keys and
- // values alive until after the call.
- SmallVector<llvm::Value *, 16> NeededObjects;
- bool TrackNeededObjects =
- (getLangOpts().ObjCAutoRefCount &&
- CGM.getCodeGenOpts().OptimizationLevel != 0);
-
- // Perform the actual initialialization of the array(s).
- for (uint64_t i = 0; i < NumElements; i++) {
- if (ALE) {
- // Emit the element and store it to the appropriate array slot.
- const Expr *Rhs = ALE->getElement(i);
- LValue LV = MakeAddrLValue(
- Builder.CreateConstArrayGEP(Objects, i, getPointerSize()),
- ElementType, AlignmentSource::Decl);
-
- llvm::Value *value = EmitScalarExpr(Rhs);
- EmitStoreThroughLValue(RValue::get(value), LV, true);
- if (TrackNeededObjects) {
- NeededObjects.push_back(value);
- }
- } else {
- // Emit the key and store it to the appropriate array slot.
- const Expr *Key = DLE->getKeyValueElement(i).Key;
- LValue KeyLV = MakeAddrLValue(
- Builder.CreateConstArrayGEP(Keys, i, getPointerSize()),
- ElementType, AlignmentSource::Decl);
- llvm::Value *keyValue = EmitScalarExpr(Key);
- EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true);
-
- // Emit the value and store it to the appropriate array slot.
- const Expr *Value = DLE->getKeyValueElement(i).Value;
- LValue ValueLV = MakeAddrLValue(
- Builder.CreateConstArrayGEP(Objects, i, getPointerSize()),
- ElementType, AlignmentSource::Decl);
- llvm::Value *valueValue = EmitScalarExpr(Value);
- EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true);
- if (TrackNeededObjects) {
- NeededObjects.push_back(keyValue);
- NeededObjects.push_back(valueValue);
- }
- }
- }
-
- // Generate the argument list.
- CallArgList Args;
- ObjCMethodDecl::param_const_iterator PI = MethodWithObjects->param_begin();
- const ParmVarDecl *argDecl = *PI++;
- QualType ArgQT = argDecl->getType().getUnqualifiedType();
- Args.add(RValue::get(Objects.getPointer()), ArgQT);
- if (DLE) {
- argDecl = *PI++;
- ArgQT = argDecl->getType().getUnqualifiedType();
- Args.add(RValue::get(Keys.getPointer()), ArgQT);
- }
- argDecl = *PI;
- ArgQT = argDecl->getType().getUnqualifiedType();
- llvm::Value *Count =
- llvm::ConstantInt::get(CGM.getTypes().ConvertType(ArgQT), NumElements);
- Args.add(RValue::get(Count), ArgQT);
-
- // Generate a reference to the class pointer, which will be the receiver.
- Selector Sel = MethodWithObjects->getSelector();
- QualType ResultType = E->getType();
- const ObjCObjectPointerType *InterfacePointerType
- = ResultType->getAsObjCInterfacePointerType();
- ObjCInterfaceDecl *Class
- = InterfacePointerType->getObjectType()->getInterface();
- CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.GetClass(*this, Class);
-
- // Generate the message send.
- RValue result = Runtime.GenerateMessageSend(
- *this, ReturnValueSlot(), MethodWithObjects->getReturnType(), Sel,
- Receiver, Args, Class, MethodWithObjects);
-
- // The above message send needs these objects, but in ARC they are
- // passed in a buffer that is essentially __unsafe_unretained.
- // Therefore we must prevent the optimizer from releasing them until
- // after the call.
- if (TrackNeededObjects) {
- EmitARCIntrinsicUse(NeededObjects);
- }
-
- return Builder.CreateBitCast(result.getScalarVal(),
- ConvertType(E->getType()));
-}
-
-llvm::Value *CodeGenFunction::EmitObjCArrayLiteral(const ObjCArrayLiteral *E) {
- return EmitObjCCollectionLiteral(E, E->getArrayWithObjectsMethod());
-}
-
-llvm::Value *CodeGenFunction::EmitObjCDictionaryLiteral(
- const ObjCDictionaryLiteral *E) {
- return EmitObjCCollectionLiteral(E, E->getDictWithObjectsMethod());
-}
-
-/// Emit a selector.
-llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
- // Untyped selector.
- // Note that this implementation allows for non-constant strings to be passed
- // as arguments to @selector(). Currently, the only thing preventing this
- // behaviour is the type checking in the front end.
- return CGM.getObjCRuntime().GetSelector(*this, E->getSelector());
-}
-
-llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
- // FIXME: This should pass the Decl not the name.
- return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol());
-}
-
-/// Adjust the type of an Objective-C object that doesn't match up due
-/// to type erasure at various points, e.g., related result types or the use
-/// of parameterized classes.
-static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT,
- RValue Result) {
- if (!ExpT->isObjCRetainableType())
- return Result;
-
- // If the converted types are the same, we're done.
- llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT);
- if (ExpLLVMTy == Result.getScalarVal()->getType())
- return Result;
-
- // We have applied a substitution. Cast the rvalue appropriately.
- return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(),
- ExpLLVMTy));
-}
-
-/// Decide whether to extend the lifetime of the receiver of a
-/// returns-inner-pointer message.
-static bool
-shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) {
- switch (message->getReceiverKind()) {
-
- // For a normal instance message, we should extend unless the
- // receiver is loaded from a variable with precise lifetime.
- case ObjCMessageExpr::Instance: {
- const Expr *receiver = message->getInstanceReceiver();
-
- // Look through OVEs.
- if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
- if (opaque->getSourceExpr())
- receiver = opaque->getSourceExpr()->IgnoreParens();
- }
-
- const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver);
- if (!ice || ice->getCastKind() != CK_LValueToRValue) return true;
- receiver = ice->getSubExpr()->IgnoreParens();
-
- // Look through OVEs.
- if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
- if (opaque->getSourceExpr())
- receiver = opaque->getSourceExpr()->IgnoreParens();
- }
-
- // Only __strong variables.
- if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
- return true;
-
- // All ivars and fields have precise lifetime.
- if (isa<MemberExpr>(receiver) || isa<ObjCIvarRefExpr>(receiver))
- return false;
-
- // Otherwise, check for variables.
- const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(ice->getSubExpr());
- if (!declRef) return true;
- const VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl());
- if (!var) return true;
-
- // All variables have precise lifetime except local variables with
- // automatic storage duration that aren't specially marked.
- return (var->hasLocalStorage() &&
- !var->hasAttr<ObjCPreciseLifetimeAttr>());
- }
-
- case ObjCMessageExpr::Class:
- case ObjCMessageExpr::SuperClass:
- // It's never necessary for class objects.
- return false;
-
- case ObjCMessageExpr::SuperInstance:
- // We generally assume that 'self' lives throughout a method call.
- return false;
- }
-
- llvm_unreachable("invalid receiver kind");
-}
-
-/// Given an expression of ObjC pointer type, check whether it was
-/// immediately loaded from an ARC __weak l-value.
-static const Expr *findWeakLValue(const Expr *E) {
- assert(E->getType()->isObjCRetainableType());
- E = E->IgnoreParens();
- if (auto CE = dyn_cast<CastExpr>(E)) {
- if (CE->getCastKind() == CK_LValueToRValue) {
- if (CE->getSubExpr()->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
- return CE->getSubExpr();
- }
- }
-
- return nullptr;
-}
-
-/// The ObjC runtime may provide entrypoints that are likely to be faster
-/// than an ordinary message send of the appropriate selector.
-///
-/// The entrypoints are guaranteed to be equivalent to just sending the
-/// corresponding message. If the entrypoint is implemented naively as just a
-/// message send, using it is a trade-off: it sacrifices a few cycles of
-/// overhead to save a small amount of code. However, it's possible for
-/// runtimes to detect and special-case classes that use "standard"
-/// behavior; if that's dynamically a large proportion of all objects, using
-/// the entrypoint will also be faster than using a message send.
-///
-/// If the runtime does support a required entrypoint, then this method will
-/// generate a call and return the resulting value. Otherwise it will return
-/// None and the caller can generate a msgSend instead.
-static Optional<llvm::Value *>
-tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
- llvm::Value *Receiver,
- const CallArgList& Args, Selector Sel,
- const ObjCMethodDecl *method,
- bool isClassMessage) {
- auto &CGM = CGF.CGM;
- if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
- return None;
-
- auto &Runtime = CGM.getLangOpts().ObjCRuntime;
- switch (Sel.getMethodFamily()) {
- case OMF_alloc:
- if (isClassMessage &&
- Runtime.shouldUseRuntimeFunctionsForAlloc() &&
- ResultType->isObjCObjectPointerType()) {
- // [Foo alloc] -> objc_alloc(Foo)
- if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")
- return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
- // [Foo allocWithZone:nil] -> objc_allocWithZone(Foo)
- if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 &&
- Args.size() == 1 && Args.front().getType()->isPointerType() &&
- Sel.getNameForSlot(0) == "allocWithZone") {
- const llvm::Value* arg = Args.front().getKnownRValue().getScalarVal();
- if (isa<llvm::ConstantPointerNull>(arg))
- return CGF.EmitObjCAllocWithZone(Receiver,
- CGF.ConvertType(ResultType));
- return None;
- }
- }
- break;
-
- case OMF_autorelease:
- if (ResultType->isObjCObjectPointerType() &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- Runtime.shouldUseARCFunctionsForRetainRelease())
- return CGF.EmitObjCAutorelease(Receiver, CGF.ConvertType(ResultType));
- break;
-
- case OMF_retain:
- if (ResultType->isObjCObjectPointerType() &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- Runtime.shouldUseARCFunctionsForRetainRelease())
- return CGF.EmitObjCRetainNonBlock(Receiver, CGF.ConvertType(ResultType));
- break;
-
- case OMF_release:
- if (ResultType->isVoidType() &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- Runtime.shouldUseARCFunctionsForRetainRelease()) {
- CGF.EmitObjCRelease(Receiver, ARCPreciseLifetime);
- return nullptr;
- }
- break;
-
- default:
- break;
- }
- return None;
-}
-
-RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
- ReturnValueSlot Return) {
- // Only the lookup mechanism and first two arguments of the method
- // implementation vary between runtimes. We can get the receiver and
- // arguments in generic code.
-
- bool isDelegateInit = E->isDelegateInitCall();
-
- const ObjCMethodDecl *method = E->getMethodDecl();
-
- // If the method is -retain, and the receiver's being loaded from
- // a __weak variable, peephole the entire operation to objc_loadWeakRetained.
- if (method && E->getReceiverKind() == ObjCMessageExpr::Instance &&
- method->getMethodFamily() == OMF_retain) {
- if (auto lvalueExpr = findWeakLValue(E->getInstanceReceiver())) {
- LValue lvalue = EmitLValue(lvalueExpr);
- llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress());
- return AdjustObjCObjectType(*this, E->getType(), RValue::get(result));
- }
- }
-
- // We don't retain the receiver in delegate init calls, and this is
- // safe because the receiver value is always loaded from 'self',
- // which we zero out. We don't want to Block_copy block receivers,
- // though.
- bool retainSelf =
- (!isDelegateInit &&
- CGM.getLangOpts().ObjCAutoRefCount &&
- method &&
- method->hasAttr<NSConsumesSelfAttr>());
-
- CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- bool isSuperMessage = false;
- bool isClassMessage = false;
- ObjCInterfaceDecl *OID = nullptr;
- // Find the receiver
- QualType ReceiverType;
- llvm::Value *Receiver = nullptr;
- switch (E->getReceiverKind()) {
- case ObjCMessageExpr::Instance:
- ReceiverType = E->getInstanceReceiver()->getType();
- if (retainSelf) {
- TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
- E->getInstanceReceiver());
- Receiver = ter.getPointer();
- if (ter.getInt()) retainSelf = false;
- } else
- Receiver = EmitScalarExpr(E->getInstanceReceiver());
- break;
-
- case ObjCMessageExpr::Class: {
- ReceiverType = E->getClassReceiver();
- const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
- assert(ObjTy && "Invalid Objective-C class message send");
- OID = ObjTy->getInterface();
- assert(OID && "Invalid Objective-C class message send");
- Receiver = Runtime.GetClass(*this, OID);
- isClassMessage = true;
- break;
- }
-
- case ObjCMessageExpr::SuperInstance:
- ReceiverType = E->getSuperType();
- Receiver = LoadObjCSelf();
- isSuperMessage = true;
- break;
-
- case ObjCMessageExpr::SuperClass:
- ReceiverType = E->getSuperType();
- Receiver = LoadObjCSelf();
- isSuperMessage = true;
- isClassMessage = true;
- break;
- }
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
-
- // In ARC, we sometimes want to "extend the lifetime"
- // (i.e. retain+autorelease) of receivers of returns-inner-pointer
- // messages.
- if (getLangOpts().ObjCAutoRefCount && method &&
- method->hasAttr<ObjCReturnsInnerPointerAttr>() &&
- shouldExtendReceiverForInnerPointerMessage(E))
- Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver);
-
- QualType ResultType = method ? method->getReturnType() : E->getType();
-
- CallArgList Args;
- EmitCallArgs(Args, method, E->arguments(), /*AC*/AbstractCallee(method));
-
- // For delegate init calls in ARC, do an unsafe store of null into
- // self. This represents the call taking direct ownership of that
- // value. We have to do this after emitting the other call
- // arguments because they might also reference self, but we don't
- // have to worry about any of them modifying self because that would
- // be an undefined read and write of an object in unordered
- // expressions.
- if (isDelegateInit) {
- assert(getLangOpts().ObjCAutoRefCount &&
- "delegate init calls should only be marked in ARC");
-
- // Do an unsafe store of null into self.
- Address selfAddr =
- GetAddrOfLocalVar(cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl());
- Builder.CreateStore(getNullForVariable(selfAddr), selfAddr);
- }
-
- RValue result;
- if (isSuperMessage) {
- // super is only valid in an Objective-C method
- const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
- bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
- result = Runtime.GenerateMessageSendSuper(*this, Return, ResultType,
- E->getSelector(),
- OMD->getClassInterface(),
- isCategoryImpl,
- Receiver,
- isClassMessage,
- Args,
- method);
- } else {
- // Call runtime methods directly if we can.
- if (Optional<llvm::Value *> SpecializedResult =
- tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args,
- E->getSelector(), method,
- isClassMessage)) {
- result = RValue::get(SpecializedResult.getValue());
- } else {
- result = Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(), Receiver, Args,
- OID, method);
- }
- }
-
- // For delegate init calls in ARC, implicitly store the result of
- // the call back into self. This takes ownership of the value.
- if (isDelegateInit) {
- Address selfAddr =
- GetAddrOfLocalVar(cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl());
- llvm::Value *newSelf = result.getScalarVal();
-
- // The delegate return type isn't necessarily a matching type; in
- // fact, it's quite likely to be 'id'.
- llvm::Type *selfTy = selfAddr.getElementType();
- newSelf = Builder.CreateBitCast(newSelf, selfTy);
-
- Builder.CreateStore(newSelf, selfAddr);
- }
-
- return AdjustObjCObjectType(*this, E->getType(), result);
-}
-
-namespace {
-struct FinishARCDealloc final : EHScopeStack::Cleanup {
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CGF.CurCodeDecl);
-
- const ObjCImplDecl *impl = cast<ObjCImplDecl>(method->getDeclContext());
- const ObjCInterfaceDecl *iface = impl->getClassInterface();
- if (!iface->getSuperClass()) return;
-
- bool isCategory = isa<ObjCCategoryImplDecl>(impl);
-
- // Call [super dealloc] if we have a superclass.
- llvm::Value *self = CGF.LoadObjCSelf();
-
- CallArgList args;
- CGF.CGM.getObjCRuntime().GenerateMessageSendSuper(CGF, ReturnValueSlot(),
- CGF.getContext().VoidTy,
- method->getSelector(),
- iface,
- isCategory,
- self,
- /*is class msg*/ false,
- args,
- method);
- }
-};
-}
-
-/// StartObjCMethod - Begin emission of an ObjCMethod. This generates
-/// the LLVM function and sets the other context used by
-/// CodeGenFunction.
-void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) {
- SourceLocation StartLoc = OMD->getBeginLoc();
- FunctionArgList args;
- // Check if we should generate debug info for this method.
- if (OMD->hasAttr<NoDebugAttr>())
- DebugInfo = nullptr; // disable debug info indefinitely for this function
-
- llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
-
- const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
- CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
-
- args.push_back(OMD->getSelfDecl());
- args.push_back(OMD->getCmdDecl());
-
- args.append(OMD->param_begin(), OMD->param_end());
-
- CurGD = OMD;
- CurEHLocation = OMD->getEndLoc();
-
- StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
- OMD->getLocation(), StartLoc);
-
- // In ARC, certain methods get an extra cleanup.
- if (CGM.getLangOpts().ObjCAutoRefCount &&
- OMD->isInstanceMethod() &&
- OMD->getSelector().isUnarySelector()) {
- const IdentifierInfo *ident =
- OMD->getSelector().getIdentifierInfoForSlot(0);
- if (ident->isStr("dealloc"))
- EHStack.pushCleanup<FinishARCDealloc>(getARCCleanupKind());
- }
-}
-
-static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
- LValue lvalue, QualType type);
-
-/// Generate an Objective-C method. An Objective-C method is a C function with
-/// its pointer, name, and types registered in the class structure.
-void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
- StartObjCMethod(OMD, OMD->getClassInterface());
- PGO.assignRegionCounters(GlobalDecl(OMD), CurFn);
- assert(isa<CompoundStmt>(OMD->getBody()));
- incrementProfileCounter(OMD->getBody());
- EmitCompoundStmtWithoutScope(*cast<CompoundStmt>(OMD->getBody()));
- FinishFunction(OMD->getBodyRBrace());
-}
-
-/// emitStructGetterCall - Call the runtime function to load a property
-/// into the return value slot.
-static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
- bool isAtomic, bool hasStrong) {
- ASTContext &Context = CGF.getContext();
-
- Address src =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
- .getAddress();
-
- // objc_copyStruct (ReturnValue, &structIvar,
- // sizeof (Type of Ivar), isAtomic, false);
- CallArgList args;
-
- Address dest = CGF.Builder.CreateBitCast(CGF.ReturnValue, CGF.VoidPtrTy);
- args.add(RValue::get(dest.getPointer()), Context.VoidPtrTy);
-
- src = CGF.Builder.CreateBitCast(src, CGF.VoidPtrTy);
- args.add(RValue::get(src.getPointer()), Context.VoidPtrTy);
-
- CharUnits size = CGF.getContext().getTypeSizeInChars(ivar->getType());
- args.add(RValue::get(CGF.CGM.getSize(size)), Context.getSizeType());
- args.add(RValue::get(CGF.Builder.getInt1(isAtomic)), Context.BoolTy);
- args.add(RValue::get(CGF.Builder.getInt1(hasStrong)), Context.BoolTy);
-
- llvm::Constant *fn = CGF.CGM.getObjCRuntime().GetGetStructFunction();
- CGCallee callee = CGCallee::forDirect(fn);
- CGF.EmitCall(CGF.getTypes().arrangeBuiltinFunctionCall(Context.VoidTy, args),
- callee, ReturnValueSlot(), args);
-}
-
-/// Determine whether the given architecture supports unaligned atomic
-/// accesses. They don't have to be fast, just faster than a function
-/// call and a mutex.
-static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) {
- // FIXME: Allow unaligned atomic load/store on x86. (It is not
- // currently supported by the backend.)
- return 0;
-}
-
-/// Return the maximum size that permits atomic accesses for the given
-/// architecture.
-static CharUnits getMaxAtomicAccessSize(CodeGenModule &CGM,
- llvm::Triple::ArchType arch) {
- // ARM has 8-byte atomic accesses, but it's not clear whether we
- // want to rely on them here.
-
- // In the default case, just assume that any size up to a pointer is
- // fine given adequate alignment.
- return CharUnits::fromQuantity(CGM.PointerSizeInBytes);
-}
-
-namespace {
- class PropertyImplStrategy {
- public:
- enum StrategyKind {
- /// The 'native' strategy is to use the architecture's provided
- /// reads and writes.
- Native,
-
- /// Use objc_setProperty and objc_getProperty.
- GetSetProperty,
-
- /// Use objc_setProperty for the setter, but use expression
- /// evaluation for the getter.
- SetPropertyAndExpressionGet,
-
- /// Use objc_copyStruct.
- CopyStruct,
-
- /// The 'expression' strategy is to emit normal assignment or
- /// lvalue-to-rvalue expressions.
- Expression
- };
-
- StrategyKind getKind() const { return StrategyKind(Kind); }
-
- bool hasStrongMember() const { return HasStrong; }
- bool isAtomic() const { return IsAtomic; }
- bool isCopy() const { return IsCopy; }
-
- CharUnits getIvarSize() const { return IvarSize; }
- CharUnits getIvarAlignment() const { return IvarAlignment; }
-
- PropertyImplStrategy(CodeGenModule &CGM,
- const ObjCPropertyImplDecl *propImpl);
-
- private:
- unsigned Kind : 8;
- unsigned IsAtomic : 1;
- unsigned IsCopy : 1;
- unsigned HasStrong : 1;
-
- CharUnits IvarSize;
- CharUnits IvarAlignment;
- };
-}
-
-/// Pick an implementation strategy for the given property synthesis.
-PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
- const ObjCPropertyImplDecl *propImpl) {
- const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
- ObjCPropertyDecl::SetterKind setterKind = prop->getSetterKind();
-
- IsCopy = (setterKind == ObjCPropertyDecl::Copy);
- IsAtomic = prop->isAtomic();
- HasStrong = false; // doesn't matter here.
-
- // Evaluate the ivar's size and alignment.
- ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
- QualType ivarType = ivar->getType();
- std::tie(IvarSize, IvarAlignment) =
- CGM.getContext().getTypeInfoInChars(ivarType);
-
- // If we have a copy property, we always have to use getProperty/setProperty.
- // TODO: we could actually use setProperty and an expression for non-atomics.
- if (IsCopy) {
- Kind = GetSetProperty;
- return;
- }
-
- // Handle retain.
- if (setterKind == ObjCPropertyDecl::Retain) {
- // In GC-only, there's nothing special that needs to be done.
- if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
- // fallthrough
-
- // In ARC, if the property is non-atomic, use expression emission,
- // which translates to objc_storeStrong. This isn't required, but
- // it's slightly nicer.
- } else if (CGM.getLangOpts().ObjCAutoRefCount && !IsAtomic) {
- // Using standard expression emission for the setter is only
- // acceptable if the ivar is __strong, which won't be true if
- // the property is annotated with __attribute__((NSObject)).
- // TODO: falling all the way back to objc_setProperty here is
- // just laziness, though; we could still use objc_storeStrong
- // if we hacked it right.
- if (ivarType.getObjCLifetime() == Qualifiers::OCL_Strong)
- Kind = Expression;
- else
- Kind = SetPropertyAndExpressionGet;
- return;
-
- // Otherwise, we need to at least use setProperty. However, if
- // the property isn't atomic, we can use normal expression
- // emission for the getter.
- } else if (!IsAtomic) {
- Kind = SetPropertyAndExpressionGet;
- return;
-
- // Otherwise, we have to use both setProperty and getProperty.
- } else {
- Kind = GetSetProperty;
- return;
- }
- }
-
- // If we're not atomic, just use expression accesses.
- if (!IsAtomic) {
- Kind = Expression;
- return;
- }
-
- // Properties on bitfield ivars need to be emitted using expression
- // accesses even if they're nominally atomic.
- if (ivar->isBitField()) {
- Kind = Expression;
- return;
- }
-
- // GC-qualified or ARC-qualified ivars need to be emitted as
- // expressions. This actually works out to being atomic anyway,
- // except for ARC __strong, but that should trigger the above code.
- if (ivarType.hasNonTrivialObjCLifetime() ||
- (CGM.getLangOpts().getGC() &&
- CGM.getContext().getObjCGCAttrKind(ivarType))) {
- Kind = Expression;
- return;
- }
-
- // Compute whether the ivar has strong members.
- if (CGM.getLangOpts().getGC())
- if (const RecordType *recordType = ivarType->getAs<RecordType>())
- HasStrong = recordType->getDecl()->hasObjectMember();
-
- // We can never access structs with object members with a native
- // access, because we need to use write barriers. This is what
- // objc_copyStruct is for.
- if (HasStrong) {
- Kind = CopyStruct;
- return;
- }
-
- // Otherwise, this is target-dependent and based on the size and
- // alignment of the ivar.
-
- // If the size of the ivar is not a power of two, give up. We don't
- // want to get into the business of doing compare-and-swaps.
- if (!IvarSize.isPowerOfTwo()) {
- Kind = CopyStruct;
- return;
- }
-
- llvm::Triple::ArchType arch =
- CGM.getTarget().getTriple().getArch();
-
- // Most architectures require memory to fit within a single cache
- // line, so the alignment has to be at least the size of the access.
- // Otherwise we have to grab a lock.
- if (IvarAlignment < IvarSize && !hasUnalignedAtomics(arch)) {
- Kind = CopyStruct;
- return;
- }
-
- // If the ivar's size exceeds the architecture's maximum atomic
- // access size, we have to use CopyStruct.
- if (IvarSize > getMaxAtomicAccessSize(CGM, arch)) {
- Kind = CopyStruct;
- return;
- }
-
- // Otherwise, we can use native loads and stores.
- Kind = Native;
-}
-
-/// Generate an Objective-C property getter function.
-///
-/// The given Decl must be an ObjCImplementationDecl. \@synthesize
-/// is illegal within a category.
-void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
- const ObjCPropertyImplDecl *PID) {
- llvm::Constant *AtomicHelperFn =
- CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID);
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
- assert(OMD && "Invalid call to generate getter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface());
-
- generateObjCGetterBody(IMP, PID, OMD, AtomicHelperFn);
-
- FinishFunction();
-}
-
-static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) {
- const Expr *getter = propImpl->getGetterCXXConstructor();
- if (!getter) return true;
-
- // Sema only makes only of these when the ivar has a C++ class type,
- // so the form is pretty constrained.
-
- // If the property has a reference type, we might just be binding a
- // reference, in which case the result will be a gl-value. We should
- // treat this as a non-trivial operation.
- if (getter->isGLValue())
- return false;
-
- // If we selected a trivial copy-constructor, we're okay.
- if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(getter))
- return (construct->getConstructor()->isTrivial());
-
- // The constructor might require cleanups (in which case it's never
- // trivial).
- assert(isa<ExprWithCleanups>(getter));
- return false;
-}
-
-/// emitCPPObjectAtomicGetterCall - Call the runtime function to
-/// copy the ivar into the resturn slot.
-static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
- llvm::Value *returnAddr,
- ObjCIvarDecl *ivar,
- llvm::Constant *AtomicHelperFn) {
- // objc_copyCppObjectAtomic (&returnSlot, &CppObjectIvar,
- // AtomicHelperFn);
- CallArgList args;
-
- // The 1st argument is the return Slot.
- args.add(RValue::get(returnAddr), CGF.getContext().VoidPtrTy);
-
- // The 2nd argument is the address of the ivar.
- llvm::Value *ivarAddr =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
- CGF.LoadObjCSelf(), ivar, 0).getPointer();
- ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
- args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
-
- // Third argument is the helper function.
- args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
-
- llvm::Constant *copyCppAtomicObjectFn =
- CGF.CGM.getObjCRuntime().GetCppAtomicObjectGetFunction();
- CGCallee callee = CGCallee::forDirect(copyCppAtomicObjectFn);
- CGF.EmitCall(
- CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
- callee, ReturnValueSlot(), args);
-}
-
-void
-CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl,
- const ObjCMethodDecl *GetterMethodDecl,
- llvm::Constant *AtomicHelperFn) {
- // If there's a non-trivial 'get' expression, we just have to emit that.
- if (!hasTrivialGetExpr(propImpl)) {
- if (!AtomicHelperFn) {
- auto *ret = ReturnStmt::Create(getContext(), SourceLocation(),
- propImpl->getGetterCXXConstructor(),
- /* NRVOCandidate=*/nullptr);
- EmitReturnStmt(*ret);
- }
- else {
- ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
- emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(),
- ivar, AtomicHelperFn);
- }
- return;
- }
-
- const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
- QualType propType = prop->getType();
- ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl();
-
- ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
-
- // Pick an implementation strategy.
- PropertyImplStrategy strategy(CGM, propImpl);
- switch (strategy.getKind()) {
- case PropertyImplStrategy::Native: {
- // We don't need to do anything for a zero-size struct.
- if (strategy.getIvarSize().isZero())
- return;
-
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
-
- // Currently, all atomic accesses have to be through integer
- // types, so there's no point in trying to pick a prettier type.
- uint64_t ivarSize = getContext().toBits(strategy.getIvarSize());
- llvm::Type *bitcastType = llvm::Type::getIntNTy(getLLVMContext(), ivarSize);
- bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay
-
- // Perform an atomic load. This does not impose ordering constraints.
- Address ivarAddr = LV.getAddress();
- ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType);
- llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
- load->setAtomic(llvm::AtomicOrdering::Unordered);
-
- // Store that value into the return address. Doing this with a
- // bitcast is likely to produce some pretty ugly IR, but it's not
- // the *most* terrible thing in the world.
- llvm::Type *retTy = ConvertType(getterMethod->getReturnType());
- uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy);
- llvm::Value *ivarVal = load;
- if (ivarSize > retTySize) {
- llvm::Type *newTy = llvm::Type::getIntNTy(getLLVMContext(), retTySize);
- ivarVal = Builder.CreateTrunc(load, newTy);
- bitcastType = newTy->getPointerTo();
- }
- Builder.CreateStore(ivarVal,
- Builder.CreateBitCast(ReturnValue, bitcastType));
-
- // Make sure we don't do an autorelease.
- AutoreleaseResult = false;
- return;
- }
-
- case PropertyImplStrategy::GetSetProperty: {
- llvm::Constant *getPropertyFn =
- CGM.getObjCRuntime().GetPropertyGetFunction();
- if (!getPropertyFn) {
- CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
- return;
- }
- CGCallee callee = CGCallee::forDirect(getPropertyFn);
-
- // Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true).
- // FIXME: Can't this be simpler? This might even be worse than the
- // corresponding gcc code.
- llvm::Value *cmd =
- Builder.CreateLoad(GetAddrOfLocalVar(getterMethod->getCmdDecl()), "cmd");
- llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
- llvm::Value *ivarOffset =
- EmitIvarOffset(classImpl->getClassInterface(), ivar);
-
- CallArgList args;
- args.add(RValue::get(self), getContext().getObjCIdType());
- args.add(RValue::get(cmd), getContext().getObjCSelType());
- args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
- args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
- getContext().BoolTy);
-
- // FIXME: We shouldn't need to get the function info here, the
- // runtime already should have computed it to build the function.
- llvm::Instruction *CallInstruction;
- RValue RV = EmitCall(
- getTypes().arrangeBuiltinFunctionCall(propType, args),
- callee, ReturnValueSlot(), args, &CallInstruction);
- if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
- call->setTailCall();
-
- // We need to fix the type here. Ivars with copy & retain are
- // always objects so we don't need to worry about complex or
- // aggregates.
- RV = RValue::get(Builder.CreateBitCast(
- RV.getScalarVal(),
- getTypes().ConvertType(getterMethod->getReturnType())));
-
- EmitReturnOfRValue(RV, propType);
-
- // objc_getProperty does an autorelease, so we should suppress ours.
- AutoreleaseResult = false;
-
- return;
- }
-
- case PropertyImplStrategy::CopyStruct:
- emitStructGetterCall(*this, ivar, strategy.isAtomic(),
- strategy.hasStrongMember());
- return;
-
- case PropertyImplStrategy::Expression:
- case PropertyImplStrategy::SetPropertyAndExpressionGet: {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
-
- QualType ivarType = ivar->getType();
- switch (getEvaluationKind(ivarType)) {
- case TEK_Complex: {
- ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
- EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
- /*init*/ true);
- return;
- }
- case TEK_Aggregate: {
- // The return value slot is guaranteed to not be aliased, but
- // that's not necessarily the same as "on the stack", so
- // we still potentially need objc_memmove_collectable.
- EmitAggregateCopy(/* Dest= */ MakeAddrLValue(ReturnValue, ivarType),
- /* Src= */ LV, ivarType, overlapForReturnValue());
- return;
- }
- case TEK_Scalar: {
- llvm::Value *value;
- if (propType->isReferenceType()) {
- value = LV.getAddress().getPointer();
- } else {
- // We want to load and autoreleaseReturnValue ARC __weak ivars.
- if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
- if (getLangOpts().ObjCAutoRefCount) {
- value = emitARCRetainLoadOfScalar(*this, LV, ivarType);
- } else {
- value = EmitARCLoadWeak(LV.getAddress());
- }
-
- // Otherwise we want to do a simple load, suppressing the
- // final autorelease.
- } else {
- value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
- AutoreleaseResult = false;
- }
-
- value = Builder.CreateBitCast(
- value, ConvertType(GetterMethodDecl->getReturnType()));
- }
-
- EmitReturnOfRValue(RValue::get(value), propType);
- return;
- }
- }
- llvm_unreachable("bad evaluation kind");
- }
-
- }
- llvm_unreachable("bad @property implementation strategy!");
-}
-
-/// emitStructSetterCall - Call the runtime function to store the value
-/// from the first formal parameter into the given ivar.
-static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
- ObjCIvarDecl *ivar) {
- // objc_copyStruct (&structIvar, &Arg,
- // sizeof (struct something), true, false);
- CallArgList args;
-
- // The first argument is the address of the ivar.
- llvm::Value *ivarAddr = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
- CGF.LoadObjCSelf(), ivar, 0)
- .getPointer();
- ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
- args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
-
- // The second argument is the address of the parameter variable.
- ParmVarDecl *argVar = *OMD->param_begin();
- DeclRefExpr argRef(CGF.getContext(), argVar, false,
- argVar->getType().getNonReferenceType(), VK_LValue,
- SourceLocation());
- llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer();
- argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
- args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
-
- // The third argument is the sizeof the type.
- llvm::Value *size =
- CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(ivar->getType()));
- args.add(RValue::get(size), CGF.getContext().getSizeType());
-
- // The fourth argument is the 'isAtomic' flag.
- args.add(RValue::get(CGF.Builder.getTrue()), CGF.getContext().BoolTy);
-
- // The fifth argument is the 'hasStrong' flag.
- // FIXME: should this really always be false?
- args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy);
-
- llvm::Constant *fn = CGF.CGM.getObjCRuntime().GetSetStructFunction();
- CGCallee callee = CGCallee::forDirect(fn);
- CGF.EmitCall(
- CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
- callee, ReturnValueSlot(), args);
-}
-
-/// emitCPPObjectAtomicSetterCall - Call the runtime function to store
-/// the value from the first formal parameter into the given ivar, using
-/// the Cpp API for atomic Cpp objects with non-trivial copy assignment.
-static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
- ObjCMethodDecl *OMD,
- ObjCIvarDecl *ivar,
- llvm::Constant *AtomicHelperFn) {
- // objc_copyCppObjectAtomic (&CppObjectIvar, &Arg,
- // AtomicHelperFn);
- CallArgList args;
-
- // The first argument is the address of the ivar.
- llvm::Value *ivarAddr =
- CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
- CGF.LoadObjCSelf(), ivar, 0).getPointer();
- ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
- args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
-
- // The second argument is the address of the parameter variable.
- ParmVarDecl *argVar = *OMD->param_begin();
- DeclRefExpr argRef(CGF.getContext(), argVar, false,
- argVar->getType().getNonReferenceType(), VK_LValue,
- SourceLocation());
- llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer();
- argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
- args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
-
- // Third argument is the helper function.
- args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
-
- llvm::Constant *fn =
- CGF.CGM.getObjCRuntime().GetCppAtomicObjectSetFunction();
- CGCallee callee = CGCallee::forDirect(fn);
- CGF.EmitCall(
- CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
- callee, ReturnValueSlot(), args);
-}
-
-
-static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
- Expr *setter = PID->getSetterCXXAssignment();
- if (!setter) return true;
-
- // Sema only makes only of these when the ivar has a C++ class type,
- // so the form is pretty constrained.
-
- // An operator call is trivial if the function it calls is trivial.
- // This also implies that there's nothing non-trivial going on with
- // the arguments, because operator= can only be trivial if it's a
- // synthesized assignment operator and therefore both parameters are
- // references.
- if (CallExpr *call = dyn_cast<CallExpr>(setter)) {
- if (const FunctionDecl *callee
- = dyn_cast_or_null<FunctionDecl>(call->getCalleeDecl()))
- if (callee->isTrivial())
- return true;
- return false;
- }
-
- assert(isa<ExprWithCleanups>(setter));
- return false;
-}
-
-static bool UseOptimizedSetter(CodeGenModule &CGM) {
- if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
- return false;
- return CGM.getLangOpts().ObjCRuntime.hasOptimizedSetter();
-}
-
-void
-CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl,
- llvm::Constant *AtomicHelperFn) {
- const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
- ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
- ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl();
-
- // Just use the setter expression if Sema gave us one and it's
- // non-trivial.
- if (!hasTrivialSetExpr(propImpl)) {
- if (!AtomicHelperFn)
- // If non-atomic, assignment is called directly.
- EmitStmt(propImpl->getSetterCXXAssignment());
- else
- // If atomic, assignment is called via a locking api.
- emitCPPObjectAtomicSetterCall(*this, setterMethod, ivar,
- AtomicHelperFn);
- return;
- }
-
- PropertyImplStrategy strategy(CGM, propImpl);
- switch (strategy.getKind()) {
- case PropertyImplStrategy::Native: {
- // We don't need to do anything for a zero-size struct.
- if (strategy.getIvarSize().isZero())
- return;
-
- Address argAddr = GetAddrOfLocalVar(*setterMethod->param_begin());
-
- LValue ivarLValue =
- EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, /*quals*/ 0);
- Address ivarAddr = ivarLValue.getAddress();
-
- // Currently, all atomic accesses have to be through integer
- // types, so there's no point in trying to pick a prettier type.
- llvm::Type *bitcastType =
- llvm::Type::getIntNTy(getLLVMContext(),
- getContext().toBits(strategy.getIvarSize()));
-
- // Cast both arguments to the chosen operation type.
- argAddr = Builder.CreateElementBitCast(argAddr, bitcastType);
- ivarAddr = Builder.CreateElementBitCast(ivarAddr, bitcastType);
-
- // This bitcast load is likely to cause some nasty IR.
- llvm::Value *load = Builder.CreateLoad(argAddr);
-
- // Perform an atomic store. There are no memory ordering requirements.
- llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
- store->setAtomic(llvm::AtomicOrdering::Unordered);
- return;
- }
-
- case PropertyImplStrategy::GetSetProperty:
- case PropertyImplStrategy::SetPropertyAndExpressionGet: {
-
- llvm::Constant *setOptimizedPropertyFn = nullptr;
- llvm::Constant *setPropertyFn = nullptr;
- if (UseOptimizedSetter(CGM)) {
- // 10.8 and iOS 6.0 code and GC is off
- setOptimizedPropertyFn =
- CGM.getObjCRuntime()
- .GetOptimizedPropertySetFunction(strategy.isAtomic(),
- strategy.isCopy());
- if (!setOptimizedPropertyFn) {
- CGM.ErrorUnsupported(propImpl, "Obj-C optimized setter - NYI");
- return;
- }
- }
- else {
- setPropertyFn = CGM.getObjCRuntime().GetPropertySetFunction();
- if (!setPropertyFn) {
- CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy");
- return;
- }
- }
-
- // Emit objc_setProperty((id) self, _cmd, offset, arg,
- // <is-atomic>, <is-copy>).
- llvm::Value *cmd =
- Builder.CreateLoad(GetAddrOfLocalVar(setterMethod->getCmdDecl()));
- llvm::Value *self =
- Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
- llvm::Value *ivarOffset =
- EmitIvarOffset(classImpl->getClassInterface(), ivar);
- Address argAddr = GetAddrOfLocalVar(*setterMethod->param_begin());
- llvm::Value *arg = Builder.CreateLoad(argAddr, "arg");
- arg = Builder.CreateBitCast(arg, VoidPtrTy);
-
- CallArgList args;
- args.add(RValue::get(self), getContext().getObjCIdType());
- args.add(RValue::get(cmd), getContext().getObjCSelType());
- if (setOptimizedPropertyFn) {
- args.add(RValue::get(arg), getContext().getObjCIdType());
- args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
- CGCallee callee = CGCallee::forDirect(setOptimizedPropertyFn);
- EmitCall(getTypes().arrangeBuiltinFunctionCall(getContext().VoidTy, args),
- callee, ReturnValueSlot(), args);
- } else {
- args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
- args.add(RValue::get(arg), getContext().getObjCIdType());
- args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
- getContext().BoolTy);
- args.add(RValue::get(Builder.getInt1(strategy.isCopy())),
- getContext().BoolTy);
- // FIXME: We shouldn't need to get the function info here, the runtime
- // already should have computed it to build the function.
- CGCallee callee = CGCallee::forDirect(setPropertyFn);
- EmitCall(getTypes().arrangeBuiltinFunctionCall(getContext().VoidTy, args),
- callee, ReturnValueSlot(), args);
- }
-
- return;
- }
-
- case PropertyImplStrategy::CopyStruct:
- emitStructSetterCall(*this, setterMethod, ivar);
- return;
-
- case PropertyImplStrategy::Expression:
- break;
- }
-
- // Otherwise, fake up some ASTs and emit a normal assignment.
- ValueDecl *selfDecl = setterMethod->getSelfDecl();
- DeclRefExpr self(getContext(), selfDecl, false, selfDecl->getType(),
- VK_LValue, SourceLocation());
- ImplicitCastExpr selfLoad(ImplicitCastExpr::OnStack,
- selfDecl->getType(), CK_LValueToRValue, &self,
- VK_RValue);
- ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(),
- SourceLocation(), SourceLocation(),
- &selfLoad, true, true);
-
- ParmVarDecl *argDecl = *setterMethod->param_begin();
- QualType argType = argDecl->getType().getNonReferenceType();
- DeclRefExpr arg(getContext(), argDecl, false, argType, VK_LValue,
- SourceLocation());
- ImplicitCastExpr argLoad(ImplicitCastExpr::OnStack,
- argType.getUnqualifiedType(), CK_LValueToRValue,
- &arg, VK_RValue);
-
- // The property type can differ from the ivar type in some situations with
- // Objective-C pointer types, we can always bit cast the RHS in these cases.
- // The following absurdity is just to ensure well-formed IR.
- CastKind argCK = CK_NoOp;
- if (ivarRef.getType()->isObjCObjectPointerType()) {
- if (argLoad.getType()->isObjCObjectPointerType())
- argCK = CK_BitCast;
- else if (argLoad.getType()->isBlockPointerType())
- argCK = CK_BlockPointerToObjCPointerCast;
- else
- argCK = CK_CPointerToObjCPointerCast;
- } else if (ivarRef.getType()->isBlockPointerType()) {
- if (argLoad.getType()->isBlockPointerType())
- argCK = CK_BitCast;
- else
- argCK = CK_AnyPointerToBlockPointerCast;
- } else if (ivarRef.getType()->isPointerType()) {
- argCK = CK_BitCast;
- }
- ImplicitCastExpr argCast(ImplicitCastExpr::OnStack,
- ivarRef.getType(), argCK, &argLoad,
- VK_RValue);
- Expr *finalArg = &argLoad;
- if (!getContext().hasSameUnqualifiedType(ivarRef.getType(),
- argLoad.getType()))
- finalArg = &argCast;
-
-
- BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
- ivarRef.getType(), VK_RValue, OK_Ordinary,
- SourceLocation(), FPOptions());
- EmitStmt(&assign);
-}
-
-/// Generate an Objective-C property setter function.
-///
-/// The given Decl must be an ObjCImplementationDecl. \@synthesize
-/// is illegal within a category.
-void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
- const ObjCPropertyImplDecl *PID) {
- llvm::Constant *AtomicHelperFn =
- CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID);
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
- assert(OMD && "Invalid call to generate setter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface());
-
- generateObjCSetterBody(IMP, PID, AtomicHelperFn);
-
- FinishFunction();
-}
-
-namespace {
- struct DestroyIvar final : EHScopeStack::Cleanup {
- private:
- llvm::Value *addr;
- const ObjCIvarDecl *ivar;
- CodeGenFunction::Destroyer *destroyer;
- bool useEHCleanupForArray;
- public:
- DestroyIvar(llvm::Value *addr, const ObjCIvarDecl *ivar,
- CodeGenFunction::Destroyer *destroyer,
- bool useEHCleanupForArray)
- : addr(addr), ivar(ivar), destroyer(destroyer),
- useEHCleanupForArray(useEHCleanupForArray) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- LValue lvalue
- = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
- CGF.emitDestroy(lvalue.getAddress(), ivar->getType(), destroyer,
- flags.isForNormalCleanup() && useEHCleanupForArray);
- }
- };
-}
-
-/// Like CodeGenFunction::destroyARCStrong, but do it with a call.
-static void destroyARCStrongWithStore(CodeGenFunction &CGF,
- Address addr,
- QualType type) {
- llvm::Value *null = getNullForVariable(addr);
- CGF.EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
-}
-
-static void emitCXXDestructMethod(CodeGenFunction &CGF,
- ObjCImplementationDecl *impl) {
- CodeGenFunction::RunCleanupsScope scope(CGF);
-
- llvm::Value *self = CGF.LoadObjCSelf();
-
- const ObjCInterfaceDecl *iface = impl->getClassInterface();
- for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
- ivar; ivar = ivar->getNextIvar()) {
- QualType type = ivar->getType();
-
- // Check whether the ivar is a destructible type.
- QualType::DestructionKind dtorKind = type.isDestructedType();
- if (!dtorKind) continue;
-
- CodeGenFunction::Destroyer *destroyer = nullptr;
-
- // Use a call to objc_storeStrong to destroy strong ivars, for the
- // general benefit of the tools.
- if (dtorKind == QualType::DK_objc_strong_lifetime) {
- destroyer = destroyARCStrongWithStore;
-
- // Otherwise use the default for the destruction kind.
- } else {
- destroyer = CGF.getDestroyer(dtorKind);
- }
-
- CleanupKind cleanupKind = CGF.getCleanupKind(dtorKind);
-
- CGF.EHStack.pushCleanup<DestroyIvar>(cleanupKind, self, ivar, destroyer,
- cleanupKind & EHCleanup);
- }
-
- assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?");
-}
-
-void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
- ObjCMethodDecl *MD,
- bool ctor) {
- MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
- StartObjCMethod(MD, IMP->getClassInterface());
-
- // Emit .cxx_construct.
- if (ctor) {
- // Suppress the final autorelease in ARC.
- AutoreleaseResult = false;
-
- for (const auto *IvarInit : IMP->inits()) {
- FieldDecl *Field = IvarInit->getAnyMember();
- ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
- LoadObjCSelf(), Ivar, 0);
- EmitAggExpr(IvarInit->getInit(),
- AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
- }
- // constructor returns 'self'.
- CodeGenTypes &Types = CGM.getTypes();
- QualType IdTy(CGM.getContext().getObjCIdType());
- llvm::Value *SelfAsId =
- Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
- EmitReturnOfRValue(RValue::get(SelfAsId), IdTy);
-
- // Emit .cxx_destruct.
- } else {
- emitCXXDestructMethod(*this, IMP);
- }
- FinishFunction();
-}
-
-llvm::Value *CodeGenFunction::LoadObjCSelf() {
- VarDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
- DeclRefExpr DRE(getContext(), Self,
- /*is enclosing local*/ (CurFuncDecl != CurCodeDecl),
- Self->getType(), VK_LValue, SourceLocation());
- return EmitLoadOfScalar(EmitDeclRefLValue(&DRE), SourceLocation());
-}
-
-QualType CodeGenFunction::TypeOfSelfObject() {
- const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
- ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
- const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>(
- getContext().getCanonicalType(selfDecl->getType()));
- return PTy->getPointeeType();
-}
-
-void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
- llvm::Constant *EnumerationMutationFnPtr =
- CGM.getObjCRuntime().EnumerationMutationFunction();
- if (!EnumerationMutationFnPtr) {
- CGM.ErrorUnsupported(&S, "Obj-C fast enumeration for this runtime");
- return;
- }
- CGCallee EnumerationMutationFn =
- CGCallee::forDirect(EnumerationMutationFnPtr);
-
- CGDebugInfo *DI = getDebugInfo();
- if (DI)
- DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
-
- RunCleanupsScope ForScope(*this);
-
- // The local variable comes into scope immediately.
- AutoVarEmission variable = AutoVarEmission::invalid();
- if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
- variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
-
- JumpDest LoopEnd = getJumpDestInCurrentScope("forcoll.end");
-
- // Fast enumeration state.
- QualType StateTy = CGM.getObjCFastEnumerationStateType();
- Address StatePtr = CreateMemTemp(StateTy, "state.ptr");
- EmitNullInitialization(StatePtr, StateTy);
-
- // Number of elements in the items array.
- static const unsigned NumItems = 16;
-
- // Fetch the countByEnumeratingWithState:objects:count: selector.
- IdentifierInfo *II[] = {
- &CGM.getContext().Idents.get("countByEnumeratingWithState"),
- &CGM.getContext().Idents.get("objects"),
- &CGM.getContext().Idents.get("count")
- };
- Selector FastEnumSel =
- CGM.getContext().Selectors.getSelector(llvm::array_lengthof(II), &II[0]);
-
- QualType ItemsTy =
- getContext().getConstantArrayType(getContext().getObjCIdType(),
- llvm::APInt(32, NumItems),
- ArrayType::Normal, 0);
- Address ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
-
- // Emit the collection pointer. In ARC, we do a retain.
- llvm::Value *Collection;
- if (getLangOpts().ObjCAutoRefCount) {
- Collection = EmitARCRetainScalarExpr(S.getCollection());
-
- // Enter a cleanup to do the release.
- EmitObjCConsumeObject(S.getCollection()->getType(), Collection);
- } else {
- Collection = EmitScalarExpr(S.getCollection());
- }
-
- // The 'continue' label needs to appear within the cleanup for the
- // collection object.
- JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next");
-
- // Send it our message:
- CallArgList Args;
-
- // The first argument is a temporary of the enumeration-state type.
- Args.add(RValue::get(StatePtr.getPointer()),
- getContext().getPointerType(StateTy));
-
- // The second argument is a temporary array with space for NumItems
- // pointers. We'll actually be loading elements from the array
- // pointer written into the control state; this buffer is so that
- // collections that *aren't* backed by arrays can still queue up
- // batches of elements.
- Args.add(RValue::get(ItemsPtr.getPointer()),
- getContext().getPointerType(ItemsTy));
-
- // The third argument is the capacity of that temporary array.
- llvm::Type *NSUIntegerTy = ConvertType(getContext().getNSUIntegerType());
- llvm::Constant *Count = llvm::ConstantInt::get(NSUIntegerTy, NumItems);
- Args.add(RValue::get(Count), getContext().getNSUIntegerType());
-
- // Start the enumeration.
- RValue CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
- getContext().getNSUIntegerType(),
- FastEnumSel, Collection, Args);
-
- // The initial number of objects that were returned in the buffer.
- llvm::Value *initialBufferLimit = CountRV.getScalarVal();
-
- llvm::BasicBlock *EmptyBB = createBasicBlock("forcoll.empty");
- llvm::BasicBlock *LoopInitBB = createBasicBlock("forcoll.loopinit");
-
- llvm::Value *zero = llvm::Constant::getNullValue(NSUIntegerTy);
-
- // If the limit pointer was zero to begin with, the collection is
- // empty; skip all this. Set the branch weight assuming this has the same
- // probability of exiting the loop as any other loop exit.
- uint64_t EntryCount = getCurrentProfileCount();
- Builder.CreateCondBr(
- Builder.CreateICmpEQ(initialBufferLimit, zero, "iszero"), EmptyBB,
- LoopInitBB,
- createProfileWeights(EntryCount, getProfileCount(S.getBody())));
-
- // Otherwise, initialize the loop.
- EmitBlock(LoopInitBB);
-
- // Save the initial mutations value. This is the value at an
- // address that was written into the state object by
- // countByEnumeratingWithState:objects:count:.
- Address StateMutationsPtrPtr = Builder.CreateStructGEP(
- StatePtr, 2, 2 * getPointerSize(), "mutationsptr.ptr");
- llvm::Value *StateMutationsPtr
- = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
-
- llvm::Value *initialMutations =
- Builder.CreateAlignedLoad(StateMutationsPtr, getPointerAlign(),
- "forcoll.initial-mutations");
-
- // Start looping. This is the point we return to whenever we have a
- // fresh, non-empty batch of objects.
- llvm::BasicBlock *LoopBodyBB = createBasicBlock("forcoll.loopbody");
- EmitBlock(LoopBodyBB);
-
- // The current index into the buffer.
- llvm::PHINode *index = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.index");
- index->addIncoming(zero, LoopInitBB);
-
- // The current buffer size.
- llvm::PHINode *count = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.count");
- count->addIncoming(initialBufferLimit, LoopInitBB);
-
- incrementProfileCounter(&S);
-
- // Check whether the mutations value has changed from where it was
- // at start. StateMutationsPtr should actually be invariant between
- // refreshes.
- StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
- llvm::Value *currentMutations
- = Builder.CreateAlignedLoad(StateMutationsPtr, getPointerAlign(),
- "statemutations");
-
- llvm::BasicBlock *WasMutatedBB = createBasicBlock("forcoll.mutated");
- llvm::BasicBlock *WasNotMutatedBB = createBasicBlock("forcoll.notmutated");
-
- Builder.CreateCondBr(Builder.CreateICmpEQ(currentMutations, initialMutations),
- WasNotMutatedBB, WasMutatedBB);
-
- // If so, call the enumeration-mutation function.
- EmitBlock(WasMutatedBB);
- llvm::Value *V =
- Builder.CreateBitCast(Collection,
- ConvertType(getContext().getObjCIdType()));
- CallArgList Args2;
- Args2.add(RValue::get(V), getContext().getObjCIdType());
- // FIXME: We shouldn't need to get the function info here, the runtime already
- // should have computed it to build the function.
- EmitCall(
- CGM.getTypes().arrangeBuiltinFunctionCall(getContext().VoidTy, Args2),
- EnumerationMutationFn, ReturnValueSlot(), Args2);
-
- // Otherwise, or if the mutation function returns, just continue.
- EmitBlock(WasNotMutatedBB);
-
- // Initialize the element variable.
- RunCleanupsScope elementVariableScope(*this);
- bool elementIsVariable;
- LValue elementLValue;
- QualType elementType;
- if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement())) {
- // Initialize the variable, in case it's a __block variable or something.
- EmitAutoVarInit(variable);
-
- const VarDecl *D = cast<VarDecl>(SD->getSingleDecl());
- DeclRefExpr tempDRE(getContext(), const_cast<VarDecl *>(D), false,
- D->getType(), VK_LValue, SourceLocation());
- elementLValue = EmitLValue(&tempDRE);
- elementType = D->getType();
- elementIsVariable = true;
-
- if (D->isARCPseudoStrong())
- elementLValue.getQuals().setObjCLifetime(Qualifiers::OCL_ExplicitNone);
- } else {
- elementLValue = LValue(); // suppress warning
- elementType = cast<Expr>(S.getElement())->getType();
- elementIsVariable = false;
- }
- llvm::Type *convertedElementType = ConvertType(elementType);
-
- // Fetch the buffer out of the enumeration state.
- // TODO: this pointer should actually be invariant between
- // refreshes, which would help us do certain loop optimizations.
- Address StateItemsPtr = Builder.CreateStructGEP(
- StatePtr, 1, getPointerSize(), "stateitems.ptr");
- llvm::Value *EnumStateItems =
- Builder.CreateLoad(StateItemsPtr, "stateitems");
-
- // Fetch the value at the current index from the buffer.
- llvm::Value *CurrentItemPtr =
- Builder.CreateGEP(EnumStateItems, index, "currentitem.ptr");
- llvm::Value *CurrentItem =
- Builder.CreateAlignedLoad(CurrentItemPtr, getPointerAlign());
-
- // Cast that value to the right type.
- CurrentItem = Builder.CreateBitCast(CurrentItem, convertedElementType,
- "currentitem");
-
- // Make sure we have an l-value. Yes, this gets evaluated every
- // time through the loop.
- if (!elementIsVariable) {
- elementLValue = EmitLValue(cast<Expr>(S.getElement()));
- EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue);
- } else {
- EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue,
- /*isInit*/ true);
- }
-
- // If we do have an element variable, this assignment is the end of
- // its initialization.
- if (elementIsVariable)
- EmitAutoVarCleanups(variable);
-
- // Perform the loop body, setting up break and continue labels.
- BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody));
- {
- RunCleanupsScope Scope(*this);
- EmitStmt(S.getBody());
- }
- BreakContinueStack.pop_back();
-
- // Destroy the element variable now.
- elementVariableScope.ForceCleanup();
-
- // Check whether there are more elements.
- EmitBlock(AfterBody.getBlock());
-
- llvm::BasicBlock *FetchMoreBB = createBasicBlock("forcoll.refetch");
-
- // First we check in the local buffer.
- llvm::Value *indexPlusOne =
- Builder.CreateAdd(index, llvm::ConstantInt::get(NSUIntegerTy, 1));
-
- // If we haven't overrun the buffer yet, we can continue.
- // Set the branch weights based on the simplifying assumption that this is
- // like a while-loop, i.e., ignoring that the false branch fetches more
- // elements and then returns to the loop.
- Builder.CreateCondBr(
- Builder.CreateICmpULT(indexPlusOne, count), LoopBodyBB, FetchMoreBB,
- createProfileWeights(getProfileCount(S.getBody()), EntryCount));
-
- index->addIncoming(indexPlusOne, AfterBody.getBlock());
- count->addIncoming(count, AfterBody.getBlock());
-
- // Otherwise, we have to fetch more elements.
- EmitBlock(FetchMoreBB);
-
- CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
- getContext().getNSUIntegerType(),
- FastEnumSel, Collection, Args);
-
- // If we got a zero count, we're done.
- llvm::Value *refetchCount = CountRV.getScalarVal();
-
- // (note that the message send might split FetchMoreBB)
- index->addIncoming(zero, Builder.GetInsertBlock());
- count->addIncoming(refetchCount, Builder.GetInsertBlock());
-
- Builder.CreateCondBr(Builder.CreateICmpEQ(refetchCount, zero),
- EmptyBB, LoopBodyBB);
-
- // No more elements.
- EmitBlock(EmptyBB);
-
- if (!elementIsVariable) {
- // If the element was not a declaration, set it to be null.
-
- llvm::Value *null = llvm::Constant::getNullValue(convertedElementType);
- elementLValue = EmitLValue(cast<Expr>(S.getElement()));
- EmitStoreThroughLValue(RValue::get(null), elementLValue);
- }
-
- if (DI)
- DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
-
- ForScope.ForceCleanup();
- EmitBlock(LoopEnd.getBlock());
-}
-
-void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S) {
- CGM.getObjCRuntime().EmitTryStmt(*this, S);
-}
-
-void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S) {
- CGM.getObjCRuntime().EmitThrowStmt(*this, S);
-}
-
-void CodeGenFunction::EmitObjCAtSynchronizedStmt(
- const ObjCAtSynchronizedStmt &S) {
- CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S);
-}
-
-namespace {
- struct CallObjCRelease final : EHScopeStack::Cleanup {
- CallObjCRelease(llvm::Value *object) : object(object) {}
- llvm::Value *object;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Releases at the end of the full-expression are imprecise.
- CGF.EmitARCRelease(object, ARCImpreciseLifetime);
- }
- };
-}
-
-/// Produce the code for a CK_ARCConsumeObject. Does a primitive
-/// release at the end of the full-expression.
-llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type,
- llvm::Value *object) {
- // If we're in a conditional branch, we need to make the cleanup
- // conditional.
- pushFullExprCleanup<CallObjCRelease>(getARCCleanupKind(), object);
- return object;
-}
-
-llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
- llvm::Value *value) {
- return EmitARCRetainAutorelease(type, value);
-}
-
-/// Given a number of pointers, inform the optimizer that they're
-/// being intrinsically used up until this point in the program.
-void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
- llvm::Constant *&fn = CGM.getObjCEntrypoints().clang_arc_use;
- if (!fn)
- fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_use);
-
- // This isn't really a "runtime" function, but as an intrinsic it
- // doesn't really matter as long as we align things up.
- EmitNounwindRuntimeCall(fn, values);
-}
-
-static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM,
- llvm::Constant *RTF) {
- if (auto *F = dyn_cast<llvm::Function>(RTF)) {
- // If the target runtime doesn't naturally support ARC, emit weak
- // references to the runtime support library. We don't really
- // permit this to fail, but we need a particular relocation style.
- if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC() &&
- !CGM.getTriple().isOSBinFormatCOFF()) {
- F->setLinkage(llvm::Function::ExternalWeakLinkage);
- }
- }
-}
-
-/// Perform an operation having the signature
-/// i8* (i8*)
-/// where a null input causes a no-op and returns null.
-static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
- llvm::Value *value,
- llvm::Type *returnType,
- llvm::Constant *&fn,
- llvm::Intrinsic::ID IntID,
- bool isTailCall = false) {
- if (isa<llvm::ConstantPointerNull>(value))
- return value;
-
- if (!fn) {
- fn = CGF.CGM.getIntrinsic(IntID);
- setARCRuntimeFunctionLinkage(CGF.CGM, fn);
- }
-
- // Cast the argument to 'id'.
- llvm::Type *origType = returnType ? returnType : value->getType();
- value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
-
- // Call the function.
- llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
- if (isTailCall)
- call->setTailCall();
-
- // Cast the result back to the original type.
- return CGF.Builder.CreateBitCast(call, origType);
-}
-
-/// Perform an operation having the following signature:
-/// i8* (i8**)
-static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
- Address addr,
- llvm::Constant *&fn,
- llvm::Intrinsic::ID IntID) {
- if (!fn) {
- fn = CGF.CGM.getIntrinsic(IntID);
- setARCRuntimeFunctionLinkage(CGF.CGM, fn);
- }
-
- // Cast the argument to 'id*'.
- llvm::Type *origType = addr.getElementType();
- addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
-
- // Call the function.
- llvm::Value *result = CGF.EmitNounwindRuntimeCall(fn, addr.getPointer());
-
- // Cast the result back to a dereference of the original type.
- if (origType != CGF.Int8PtrTy)
- result = CGF.Builder.CreateBitCast(result, origType);
-
- return result;
-}
-
-/// Perform an operation having the following signature:
-/// i8* (i8**, i8*)
-static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
- Address addr,
- llvm::Value *value,
- llvm::Constant *&fn,
- llvm::Intrinsic::ID IntID,
- bool ignored) {
- assert(addr.getElementType() == value->getType());
-
- if (!fn) {
- fn = CGF.CGM.getIntrinsic(IntID);
- setARCRuntimeFunctionLinkage(CGF.CGM, fn);
- }
-
- llvm::Type *origType = value->getType();
-
- llvm::Value *args[] = {
- CGF.Builder.CreateBitCast(addr.getPointer(), CGF.Int8PtrPtrTy),
- CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy)
- };
- llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args);
-
- if (ignored) return nullptr;
-
- return CGF.Builder.CreateBitCast(result, origType);
-}
-
-/// Perform an operation having the following signature:
-/// void (i8**, i8**)
-static void emitARCCopyOperation(CodeGenFunction &CGF,
- Address dst,
- Address src,
- llvm::Constant *&fn,
- llvm::Intrinsic::ID IntID) {
- assert(dst.getType() == src.getType());
-
- if (!fn) {
- fn = CGF.CGM.getIntrinsic(IntID);
- setARCRuntimeFunctionLinkage(CGF.CGM, fn);
- }
-
- llvm::Value *args[] = {
- CGF.Builder.CreateBitCast(dst.getPointer(), CGF.Int8PtrPtrTy),
- CGF.Builder.CreateBitCast(src.getPointer(), CGF.Int8PtrPtrTy)
- };
- CGF.EmitNounwindRuntimeCall(fn, args);
-}
-
-/// Perform an operation having the signature
-/// i8* (i8*)
-/// where a null input causes a no-op and returns null.
-static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF,
- llvm::Value *value,
- llvm::Type *returnType,
- llvm::Constant *&fn,
- StringRef fnName) {
- if (isa<llvm::ConstantPointerNull>(value))
- return value;
-
- if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
- fn = CGF.CGM.CreateRuntimeFunction(fnType, fnName);
-
- // We have Native ARC, so set nonlazybind attribute for performance
- if (llvm::Function *f = dyn_cast<llvm::Function>(fn))
- if (fnName == "objc_retain")
- f->addFnAttr(llvm::Attribute::NonLazyBind);
- }
-
- // Cast the argument to 'id'.
- llvm::Type *origType = returnType ? returnType : value->getType();
- value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
-
- // Call the function.
- llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
-
- // Cast the result back to the original type.
- return CGF.Builder.CreateBitCast(call, origType);
-}
-
-/// Produce the code to do a retain. Based on the type, calls one of:
-/// call i8* \@objc_retain(i8* %value)
-/// call i8* \@objc_retainBlock(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
- if (type->isBlockPointerType())
- return EmitARCRetainBlock(value, /*mandatory*/ false);
- else
- return EmitARCRetainNonBlock(value);
-}
-
-/// Retain the given object, with normal retain semantics.
-/// call i8* \@objc_retain(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_retain,
- llvm::Intrinsic::objc_retain);
-}
-
-/// Retain the given block, with _Block_copy semantics.
-/// call i8* \@objc_retainBlock(i8* %value)
-///
-/// \param mandatory - If false, emit the call with metadata
-/// indicating that it's okay for the optimizer to eliminate this call
-/// if it can prove that the block never escapes except down the stack.
-llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
- bool mandatory) {
- llvm::Value *result
- = emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_retainBlock,
- llvm::Intrinsic::objc_retainBlock);
-
- // If the copy isn't mandatory, add !clang.arc.copy_on_escape to
- // tell the optimizer that it doesn't need to do this copy if the
- // block doesn't escape, where being passed as an argument doesn't
- // count as escaping.
- if (!mandatory && isa<llvm::Instruction>(result)) {
- llvm::CallInst *call
- = cast<llvm::CallInst>(result->stripPointerCasts());
- assert(call->getCalledValue() == CGM.getObjCEntrypoints().objc_retainBlock);
-
- call->setMetadata("clang.arc.copy_on_escape",
- llvm::MDNode::get(Builder.getContext(), None));
- }
-
- return result;
-}
-
-static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
- // Fetch the void(void) inline asm which marks that we're going to
- // do something with the autoreleased return value.
- llvm::InlineAsm *&marker
- = CGF.CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker;
- if (!marker) {
- StringRef assembly
- = CGF.CGM.getTargetCodeGenInfo()
- .getARCRetainAutoreleasedReturnValueMarker();
-
- // If we have an empty assembly string, there's nothing to do.
- if (assembly.empty()) {
-
- // Otherwise, at -O0, build an inline asm that we're going to call
- // in a moment.
- } else if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
- llvm::FunctionType *type =
- llvm::FunctionType::get(CGF.VoidTy, /*variadic*/false);
-
- marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true);
-
- // If we're at -O1 and above, we don't want to litter the code
- // with this marker yet, so leave a breadcrumb for the ARC
- // optimizer to pick up.
- } else {
- llvm::NamedMDNode *metadata =
- CGF.CGM.getModule().getOrInsertNamedMetadata(
- "clang.arc.retainAutoreleasedReturnValueMarker");
- assert(metadata->getNumOperands() <= 1);
- if (metadata->getNumOperands() == 0) {
- auto &ctx = CGF.getLLVMContext();
- metadata->addOperand(llvm::MDNode::get(ctx,
- llvm::MDString::get(ctx, assembly)));
- }
- }
- }
-
- // Call the marker asm if we made one, which we do only at -O0.
- if (marker)
- CGF.Builder.CreateCall(marker, None, CGF.getBundlesForFunclet(marker));
-}
-
-/// Retain the given object which is the result of a function call.
-/// call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
-///
-/// Yes, this function name is one character away from a different
-/// call with completely different semantics.
-llvm::Value *
-CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
- emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
- llvm::Intrinsic::objc_retainAutoreleasedReturnValue);
-}
-
-/// Claim a possibly-autoreleased return value at +0. This is only
-/// valid to do in contexts which do not rely on the retain to keep
-/// the object valid for all of its uses; for example, when
-/// the value is ignored, or when it is being assigned to an
-/// __unsafe_unretained variable.
-///
-/// call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value)
-llvm::Value *
-CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
- emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
- llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue);
-}
-
-/// Release the given object.
-/// call void \@objc_release(i8* %value)
-void CodeGenFunction::EmitARCRelease(llvm::Value *value,
- ARCPreciseLifetime_t precise) {
- if (isa<llvm::ConstantPointerNull>(value)) return;
-
- llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_release;
- if (!fn) {
- fn = CGM.getIntrinsic(llvm::Intrinsic::objc_release);
- setARCRuntimeFunctionLinkage(CGM, fn);
- }
-
- // Cast the argument to 'id'.
- value = Builder.CreateBitCast(value, Int8PtrTy);
-
- // Call objc_release.
- llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
-
- if (precise == ARCImpreciseLifetime) {
- call->setMetadata("clang.imprecise_release",
- llvm::MDNode::get(Builder.getContext(), None));
- }
-}
-
-/// Destroy a __strong variable.
-///
-/// At -O0, emit a call to store 'null' into the address;
-/// instrumenting tools prefer this because the address is exposed,
-/// but it's relatively cumbersome to optimize.
-///
-/// At -O1 and above, just load and call objc_release.
-///
-/// call void \@objc_storeStrong(i8** %addr, i8* null)
-void CodeGenFunction::EmitARCDestroyStrong(Address addr,
- ARCPreciseLifetime_t precise) {
- if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
- llvm::Value *null = getNullForVariable(addr);
- EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
- return;
- }
-
- llvm::Value *value = Builder.CreateLoad(addr);
- EmitARCRelease(value, precise);
-}
-
-/// Store into a strong object. Always calls this:
-/// call void \@objc_storeStrong(i8** %addr, i8* %value)
-llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr,
- llvm::Value *value,
- bool ignored) {
- assert(addr.getElementType() == value->getType());
-
- llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_storeStrong;
- if (!fn) {
- fn = CGM.getIntrinsic(llvm::Intrinsic::objc_storeStrong);
- setARCRuntimeFunctionLinkage(CGM, fn);
- }
-
- llvm::Value *args[] = {
- Builder.CreateBitCast(addr.getPointer(), Int8PtrPtrTy),
- Builder.CreateBitCast(value, Int8PtrTy)
- };
- EmitNounwindRuntimeCall(fn, args);
-
- if (ignored) return nullptr;
- return value;
-}
-
-/// Store into a strong object. Sometimes calls this:
-/// call void \@objc_storeStrong(i8** %addr, i8* %value)
-/// Other times, breaks it down into components.
-llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
- llvm::Value *newValue,
- bool ignored) {
- QualType type = dst.getType();
- bool isBlock = type->isBlockPointerType();
-
- // Use a store barrier at -O0 unless this is a block type or the
- // lvalue is inadequately aligned.
- if (shouldUseFusedARCCalls() &&
- !isBlock &&
- (dst.getAlignment().isZero() ||
- dst.getAlignment() >= CharUnits::fromQuantity(PointerAlignInBytes))) {
- return EmitARCStoreStrongCall(dst.getAddress(), newValue, ignored);
- }
-
- // Otherwise, split it out.
-
- // Retain the new value.
- newValue = EmitARCRetain(type, newValue);
-
- // Read the old value.
- llvm::Value *oldValue = EmitLoadOfScalar(dst, SourceLocation());
-
- // Store. We do this before the release so that any deallocs won't
- // see the old value.
- EmitStoreOfScalar(newValue, dst);
-
- // Finally, release the old value.
- EmitARCRelease(oldValue, dst.isARCPreciseLifetime());
-
- return newValue;
-}
-
-/// Autorelease the given object.
-/// call i8* \@objc_autorelease(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_autorelease,
- llvm::Intrinsic::objc_autorelease);
-}
-
-/// Autorelease the given object.
-/// call i8* \@objc_autoreleaseReturnValue(i8* %value)
-llvm::Value *
-CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_autoreleaseReturnValue,
- llvm::Intrinsic::objc_autoreleaseReturnValue,
- /*isTailCall*/ true);
-}
-
-/// Do a fused retain/autorelease of the given object.
-/// call i8* \@objc_retainAutoreleaseReturnValue(i8* %value)
-llvm::Value *
-CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_retainAutoreleaseReturnValue,
- llvm::Intrinsic::objc_retainAutoreleaseReturnValue,
- /*isTailCall*/ true);
-}
-
-/// Do a fused retain/autorelease of the given object.
-/// call i8* \@objc_retainAutorelease(i8* %value)
-/// or
-/// %retain = call i8* \@objc_retainBlock(i8* %value)
-/// call i8* \@objc_autorelease(i8* %retain)
-llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
- llvm::Value *value) {
- if (!type->isBlockPointerType())
- return EmitARCRetainAutoreleaseNonBlock(value);
-
- if (isa<llvm::ConstantPointerNull>(value)) return value;
-
- llvm::Type *origType = value->getType();
- value = Builder.CreateBitCast(value, Int8PtrTy);
- value = EmitARCRetainBlock(value, /*mandatory*/ true);
- value = EmitARCAutorelease(value);
- return Builder.CreateBitCast(value, origType);
-}
-
-/// Do a fused retain/autorelease of the given object.
-/// call i8* \@objc_retainAutorelease(i8* %value)
-llvm::Value *
-CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
- CGM.getObjCEntrypoints().objc_retainAutorelease,
- llvm::Intrinsic::objc_retainAutorelease);
-}
-
-/// i8* \@objc_loadWeak(i8** %addr)
-/// Essentially objc_autorelease(objc_loadWeakRetained(addr)).
-llvm::Value *CodeGenFunction::EmitARCLoadWeak(Address addr) {
- return emitARCLoadOperation(*this, addr,
- CGM.getObjCEntrypoints().objc_loadWeak,
- llvm::Intrinsic::objc_loadWeak);
-}
-
-/// i8* \@objc_loadWeakRetained(i8** %addr)
-llvm::Value *CodeGenFunction::EmitARCLoadWeakRetained(Address addr) {
- return emitARCLoadOperation(*this, addr,
- CGM.getObjCEntrypoints().objc_loadWeakRetained,
- llvm::Intrinsic::objc_loadWeakRetained);
-}
-
-/// i8* \@objc_storeWeak(i8** %addr, i8* %value)
-/// Returns %value.
-llvm::Value *CodeGenFunction::EmitARCStoreWeak(Address addr,
- llvm::Value *value,
- bool ignored) {
- return emitARCStoreOperation(*this, addr, value,
- CGM.getObjCEntrypoints().objc_storeWeak,
- llvm::Intrinsic::objc_storeWeak, ignored);
-}
-
-/// i8* \@objc_initWeak(i8** %addr, i8* %value)
-/// Returns %value. %addr is known to not have a current weak entry.
-/// Essentially equivalent to:
-/// *addr = nil; objc_storeWeak(addr, value);
-void CodeGenFunction::EmitARCInitWeak(Address addr, llvm::Value *value) {
- // If we're initializing to null, just write null to memory; no need
- // to get the runtime involved. But don't do this if optimization
- // is enabled, because accounting for this would make the optimizer
- // much more complicated.
- if (isa<llvm::ConstantPointerNull>(value) &&
- CGM.getCodeGenOpts().OptimizationLevel == 0) {
- Builder.CreateStore(value, addr);
- return;
- }
-
- emitARCStoreOperation(*this, addr, value,
- CGM.getObjCEntrypoints().objc_initWeak,
- llvm::Intrinsic::objc_initWeak, /*ignored*/ true);
-}
-
-/// void \@objc_destroyWeak(i8** %addr)
-/// Essentially objc_storeWeak(addr, nil).
-void CodeGenFunction::EmitARCDestroyWeak(Address addr) {
- llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_destroyWeak;
- if (!fn) {
- fn = CGM.getIntrinsic(llvm::Intrinsic::objc_destroyWeak);
- setARCRuntimeFunctionLinkage(CGM, fn);
- }
-
- // Cast the argument to 'id*'.
- addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
-
- EmitNounwindRuntimeCall(fn, addr.getPointer());
-}
-
-/// void \@objc_moveWeak(i8** %dest, i8** %src)
-/// Disregards the current value in %dest. Leaves %src pointing to nothing.
-/// Essentially (objc_copyWeak(dest, src), objc_destroyWeak(src)).
-void CodeGenFunction::EmitARCMoveWeak(Address dst, Address src) {
- emitARCCopyOperation(*this, dst, src,
- CGM.getObjCEntrypoints().objc_moveWeak,
- llvm::Intrinsic::objc_moveWeak);
-}
-
-/// void \@objc_copyWeak(i8** %dest, i8** %src)
-/// Disregards the current value in %dest. Essentially
-/// objc_release(objc_initWeak(dest, objc_readWeakRetained(src)))
-void CodeGenFunction::EmitARCCopyWeak(Address dst, Address src) {
- emitARCCopyOperation(*this, dst, src,
- CGM.getObjCEntrypoints().objc_copyWeak,
- llvm::Intrinsic::objc_copyWeak);
-}
-
-void CodeGenFunction::emitARCCopyAssignWeak(QualType Ty, Address DstAddr,
- Address SrcAddr) {
- llvm::Value *Object = EmitARCLoadWeakRetained(SrcAddr);
- Object = EmitObjCConsumeObject(Ty, Object);
- EmitARCStoreWeak(DstAddr, Object, false);
-}
-
-void CodeGenFunction::emitARCMoveAssignWeak(QualType Ty, Address DstAddr,
- Address SrcAddr) {
- llvm::Value *Object = EmitARCLoadWeakRetained(SrcAddr);
- Object = EmitObjCConsumeObject(Ty, Object);
- EmitARCStoreWeak(DstAddr, Object, false);
- EmitARCDestroyWeak(SrcAddr);
-}
-
-/// Produce the code to do a objc_autoreleasepool_push.
-/// call i8* \@objc_autoreleasePoolPush(void)
-llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
- llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPush;
- if (!fn) {
- fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPush);
- setARCRuntimeFunctionLinkage(CGM, fn);
- }
-
- return EmitNounwindRuntimeCall(fn);
-}
-
-/// Produce the code to do a primitive release.
-/// call void \@objc_autoreleasePoolPop(i8* %ptr)
-void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
- assert(value->getType() == Int8PtrTy);
-
- if (getInvokeDest()) {
- // Call the runtime method not the intrinsic if we are handling exceptions
- llvm::Constant *&fn =
- CGM.getObjCEntrypoints().objc_autoreleasePoolPopInvoke;
- if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
- fn = CGM.CreateRuntimeFunction(fnType, "objc_autoreleasePoolPop");
- setARCRuntimeFunctionLinkage(CGM, fn);
- }
-
- // objc_autoreleasePoolPop can throw.
- EmitRuntimeCallOrInvoke(fn, value);
- } else {
- llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPop;
- if (!fn) {
- fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPop);
- setARCRuntimeFunctionLinkage(CGM, fn);
- }
-
- EmitRuntimeCall(fn, value);
- }
-}
-
-/// Produce the code to do an MRR version objc_autoreleasepool_push.
-/// Which is: [[NSAutoreleasePool alloc] init];
-/// Where alloc is declared as: + (id) alloc; in NSAutoreleasePool class.
-/// init is declared as: - (id) init; in its NSObject super class.
-///
-llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
- CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(*this);
- // [NSAutoreleasePool alloc]
- IdentifierInfo *II = &CGM.getContext().Idents.get("alloc");
- Selector AllocSel = getContext().Selectors.getSelector(0, &II);
- CallArgList Args;
- RValue AllocRV =
- Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
- getContext().getObjCIdType(),
- AllocSel, Receiver, Args);
-
- // [Receiver init]
- Receiver = AllocRV.getScalarVal();
- II = &CGM.getContext().Idents.get("init");
- Selector InitSel = getContext().Selectors.getSelector(0, &II);
- RValue InitRV =
- Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
- getContext().getObjCIdType(),
- InitSel, Receiver, Args);
- return InitRV.getScalarVal();
-}
-
-/// Allocate the given objc object.
-/// call i8* \@objc_alloc(i8* %value)
-llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value,
- llvm::Type *resultType) {
- return emitObjCValueOperation(*this, value, resultType,
- CGM.getObjCEntrypoints().objc_alloc,
- "objc_alloc");
-}
-
-/// Allocate the given objc object.
-/// call i8* \@objc_allocWithZone(i8* %value)
-llvm::Value *CodeGenFunction::EmitObjCAllocWithZone(llvm::Value *value,
- llvm::Type *resultType) {
- return emitObjCValueOperation(*this, value, resultType,
- CGM.getObjCEntrypoints().objc_allocWithZone,
- "objc_allocWithZone");
-}
-
-/// Produce the code to do a primitive release.
-/// [tmp drain];
-void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
- IdentifierInfo *II = &CGM.getContext().Idents.get("drain");
- Selector DrainSel = getContext().Selectors.getSelector(0, &II);
- CallArgList Args;
- CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
- getContext().VoidTy, DrainSel, Arg, Args);
-}
-
-void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
- Address addr,
- QualType type) {
- CGF.EmitARCDestroyStrong(addr, ARCPreciseLifetime);
-}
-
-void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
- Address addr,
- QualType type) {
- CGF.EmitARCDestroyStrong(addr, ARCImpreciseLifetime);
-}
-
-void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
- Address addr,
- QualType type) {
- CGF.EmitARCDestroyWeak(addr);
-}
-
-void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
- QualType type) {
- llvm::Value *value = CGF.Builder.CreateLoad(addr);
- CGF.EmitARCIntrinsicUse(value);
-}
-
-/// Autorelease the given object.
-/// call i8* \@objc_autorelease(i8* %value)
-llvm::Value *CodeGenFunction::EmitObjCAutorelease(llvm::Value *value,
- llvm::Type *returnType) {
- return emitObjCValueOperation(*this, value, returnType,
- CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction,
- "objc_autorelease");
-}
-
-/// Retain the given object, with normal retain semantics.
-/// call i8* \@objc_retain(i8* %value)
-llvm::Value *CodeGenFunction::EmitObjCRetainNonBlock(llvm::Value *value,
- llvm::Type *returnType) {
- return emitObjCValueOperation(*this, value, returnType,
- CGM.getObjCEntrypoints().objc_retainRuntimeFunction,
- "objc_retain");
-}
-
-/// Release the given object.
-/// call void \@objc_release(i8* %value)
-void CodeGenFunction::EmitObjCRelease(llvm::Value *value,
- ARCPreciseLifetime_t precise) {
- if (isa<llvm::ConstantPointerNull>(value)) return;
-
- llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_release;
- if (!fn) {
- if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
- fn = CGM.CreateRuntimeFunction(fnType, "objc_release");
- setARCRuntimeFunctionLinkage(CGM, fn);
- // We have Native ARC, so set nonlazybind attribute for performance
- if (llvm::Function *f = dyn_cast<llvm::Function>(fn))
- f->addFnAttr(llvm::Attribute::NonLazyBind);
- }
- }
-
- // Cast the argument to 'id'.
- value = Builder.CreateBitCast(value, Int8PtrTy);
-
- // Call objc_release.
- llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
-
- if (precise == ARCImpreciseLifetime) {
- call->setMetadata("clang.imprecise_release",
- llvm::MDNode::get(Builder.getContext(), None));
- }
-}
-
-namespace {
- struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup {
- llvm::Value *Token;
-
- CallObjCAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitObjCAutoreleasePoolPop(Token);
- }
- };
- struct CallObjCMRRAutoreleasePoolObject final : EHScopeStack::Cleanup {
- llvm::Value *Token;
-
- CallObjCMRRAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitObjCMRRAutoreleasePoolPop(Token);
- }
- };
-}
-
-void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) {
- if (CGM.getLangOpts().ObjCAutoRefCount)
- EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, Ptr);
- else
- EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, Ptr);
-}
-
-static bool shouldRetainObjCLifetime(Qualifiers::ObjCLifetime lifetime) {
- switch (lifetime) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Autoreleasing:
- return true;
-
- case Qualifiers::OCL_Weak:
- return false;
- }
-
- llvm_unreachable("impossible lifetime!");
-}
-
-static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
- LValue lvalue,
- QualType type) {
- llvm::Value *result;
- bool shouldRetain = shouldRetainObjCLifetime(type.getObjCLifetime());
- if (shouldRetain) {
- result = CGF.EmitLoadOfLValue(lvalue, SourceLocation()).getScalarVal();
- } else {
- assert(type.getObjCLifetime() == Qualifiers::OCL_Weak);
- result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress());
- }
- return TryEmitResult(result, !shouldRetain);
-}
-
-static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
- const Expr *e) {
- e = e->IgnoreParens();
- QualType type = e->getType();
-
- // If we're loading retained from a __strong xvalue, we can avoid
- // an extra retain/release pair by zeroing out the source of this
- // "move" operation.
- if (e->isXValue() &&
- !type.isConstQualified() &&
- type.getObjCLifetime() == Qualifiers::OCL_Strong) {
- // Emit the lvalue.
- LValue lv = CGF.EmitLValue(e);
-
- // Load the object pointer.
- llvm::Value *result = CGF.EmitLoadOfLValue(lv,
- SourceLocation()).getScalarVal();
-
- // Set the source pointer to NULL.
- CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv);
-
- return TryEmitResult(result, true);
- }
-
- // As a very special optimization, in ARC++, if the l-value is the
- // result of a non-volatile assignment, do a simple retain of the
- // result of the call to objc_storeWeak instead of reloading.
- if (CGF.getLangOpts().CPlusPlus &&
- !type.isVolatileQualified() &&
- type.getObjCLifetime() == Qualifiers::OCL_Weak &&
- isa<BinaryOperator>(e) &&
- cast<BinaryOperator>(e)->getOpcode() == BO_Assign)
- return TryEmitResult(CGF.EmitScalarExpr(e), false);
-
- // Try to emit code for scalar constant instead of emitting LValue and
- // loading it because we are not guaranteed to have an l-value. One of such
- // cases is DeclRefExpr referencing non-odr-used constant-evaluated variable.
- if (const auto *decl_expr = dyn_cast<DeclRefExpr>(e)) {
- auto *DRE = const_cast<DeclRefExpr *>(decl_expr);
- if (CodeGenFunction::ConstantEmission constant = CGF.tryEmitAsConstant(DRE))
- return TryEmitResult(CGF.emitScalarConstant(constant, DRE),
- !shouldRetainObjCLifetime(type.getObjCLifetime()));
- }
-
- return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type);
-}
-
-typedef llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
- llvm::Value *value)>
- ValueTransform;
-
-/// Insert code immediately after a call.
-static llvm::Value *emitARCOperationAfterCall(CodeGenFunction &CGF,
- llvm::Value *value,
- ValueTransform doAfterCall,
- ValueTransform doFallback) {
- if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(value)) {
- CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
-
- // Place the retain immediately following the call.
- CGF.Builder.SetInsertPoint(call->getParent(),
- ++llvm::BasicBlock::iterator(call));
- value = doAfterCall(CGF, value);
-
- CGF.Builder.restoreIP(ip);
- return value;
- } else if (llvm::InvokeInst *invoke = dyn_cast<llvm::InvokeInst>(value)) {
- CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
-
- // Place the retain at the beginning of the normal destination block.
- llvm::BasicBlock *BB = invoke->getNormalDest();
- CGF.Builder.SetInsertPoint(BB, BB->begin());
- value = doAfterCall(CGF, value);
-
- CGF.Builder.restoreIP(ip);
- return value;
-
- // Bitcasts can arise because of related-result returns. Rewrite
- // the operand.
- } else if (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(value)) {
- llvm::Value *operand = bitcast->getOperand(0);
- operand = emitARCOperationAfterCall(CGF, operand, doAfterCall, doFallback);
- bitcast->setOperand(0, operand);
- return bitcast;
-
- // Generic fall-back case.
- } else {
- // Retain using the non-block variant: we never need to do a copy
- // of a block that's been returned to us.
- return doFallback(CGF, value);
- }
-}
-
-/// Given that the given expression is some sort of call (which does
-/// not return retained), emit a retain following it.
-static llvm::Value *emitARCRetainCallResult(CodeGenFunction &CGF,
- const Expr *e) {
- llvm::Value *value = CGF.EmitScalarExpr(e);
- return emitARCOperationAfterCall(CGF, value,
- [](CodeGenFunction &CGF, llvm::Value *value) {
- return CGF.EmitARCRetainAutoreleasedReturnValue(value);
- },
- [](CodeGenFunction &CGF, llvm::Value *value) {
- return CGF.EmitARCRetainNonBlock(value);
- });
-}
-
-/// Given that the given expression is some sort of call (which does
-/// not return retained), perform an unsafeClaim following it.
-static llvm::Value *emitARCUnsafeClaimCallResult(CodeGenFunction &CGF,
- const Expr *e) {
- llvm::Value *value = CGF.EmitScalarExpr(e);
- return emitARCOperationAfterCall(CGF, value,
- [](CodeGenFunction &CGF, llvm::Value *value) {
- return CGF.EmitARCUnsafeClaimAutoreleasedReturnValue(value);
- },
- [](CodeGenFunction &CGF, llvm::Value *value) {
- return value;
- });
-}
-
-llvm::Value *CodeGenFunction::EmitARCReclaimReturnedObject(const Expr *E,
- bool allowUnsafeClaim) {
- if (allowUnsafeClaim &&
- CGM.getLangOpts().ObjCRuntime.hasARCUnsafeClaimAutoreleasedReturnValue()) {
- return emitARCUnsafeClaimCallResult(*this, E);
- } else {
- llvm::Value *value = emitARCRetainCallResult(*this, E);
- return EmitObjCConsumeObject(E->getType(), value);
- }
-}
-
-/// Determine whether it might be important to emit a separate
-/// objc_retain_block on the result of the given expression, or
-/// whether it's okay to just emit it in a +1 context.
-static bool shouldEmitSeparateBlockRetain(const Expr *e) {
- assert(e->getType()->isBlockPointerType());
- e = e->IgnoreParens();
-
- // For future goodness, emit block expressions directly in +1
- // contexts if we can.
- if (isa<BlockExpr>(e))
- return false;
-
- if (const CastExpr *cast = dyn_cast<CastExpr>(e)) {
- switch (cast->getCastKind()) {
- // Emitting these operations in +1 contexts is goodness.
- case CK_LValueToRValue:
- case CK_ARCReclaimReturnedObject:
- case CK_ARCConsumeObject:
- case CK_ARCProduceObject:
- return false;
-
- // These operations preserve a block type.
- case CK_NoOp:
- case CK_BitCast:
- return shouldEmitSeparateBlockRetain(cast->getSubExpr());
-
- // These operations are known to be bad (or haven't been considered).
- case CK_AnyPointerToBlockPointerCast:
- default:
- return true;
- }
- }
-
- return true;
-}
-
-namespace {
-/// A CRTP base class for emitting expressions of retainable object
-/// pointer type in ARC.
-template <typename Impl, typename Result> class ARCExprEmitter {
-protected:
- CodeGenFunction &CGF;
- Impl &asImpl() { return *static_cast<Impl*>(this); }
-
- ARCExprEmitter(CodeGenFunction &CGF) : CGF(CGF) {}
-
-public:
- Result visit(const Expr *e);
- Result visitCastExpr(const CastExpr *e);
- Result visitPseudoObjectExpr(const PseudoObjectExpr *e);
- Result visitBinaryOperator(const BinaryOperator *e);
- Result visitBinAssign(const BinaryOperator *e);
- Result visitBinAssignUnsafeUnretained(const BinaryOperator *e);
- Result visitBinAssignAutoreleasing(const BinaryOperator *e);
- Result visitBinAssignWeak(const BinaryOperator *e);
- Result visitBinAssignStrong(const BinaryOperator *e);
-
- // Minimal implementation:
- // Result visitLValueToRValue(const Expr *e)
- // Result visitConsumeObject(const Expr *e)
- // Result visitExtendBlockObject(const Expr *e)
- // Result visitReclaimReturnedObject(const Expr *e)
- // Result visitCall(const Expr *e)
- // Result visitExpr(const Expr *e)
- //
- // Result emitBitCast(Result result, llvm::Type *resultType)
- // llvm::Value *getValueOfResult(Result result)
-};
-}
-
-/// Try to emit a PseudoObjectExpr under special ARC rules.
-///
-/// This massively duplicates emitPseudoObjectRValue.
-template <typename Impl, typename Result>
-Result
-ARCExprEmitter<Impl,Result>::visitPseudoObjectExpr(const PseudoObjectExpr *E) {
- SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
-
- // Find the result expression.
- const Expr *resultExpr = E->getResultExpr();
- assert(resultExpr);
- Result result;
-
- for (PseudoObjectExpr::const_semantics_iterator
- i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
- const Expr *semantic = *i;
-
- // If this semantic expression is an opaque value, bind it
- // to the result of its source expression.
- if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
- typedef CodeGenFunction::OpaqueValueMappingData OVMA;
- OVMA opaqueData;
-
- // If this semantic is the result of the pseudo-object
- // expression, try to evaluate the source as +1.
- if (ov == resultExpr) {
- assert(!OVMA::shouldBindAsLValue(ov));
- result = asImpl().visit(ov->getSourceExpr());
- opaqueData = OVMA::bind(CGF, ov,
- RValue::get(asImpl().getValueOfResult(result)));
-
- // Otherwise, just bind it.
- } else {
- opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());
- }
- opaques.push_back(opaqueData);
-
- // Otherwise, if the expression is the result, evaluate it
- // and remember the result.
- } else if (semantic == resultExpr) {
- result = asImpl().visit(semantic);
-
- // Otherwise, evaluate the expression in an ignored context.
- } else {
- CGF.EmitIgnoredExpr(semantic);
- }
- }
-
- // Unbind all the opaques now.
- for (unsigned i = 0, e = opaques.size(); i != e; ++i)
- opaques[i].unbind(CGF);
-
- return result;
-}
-
-template <typename Impl, typename Result>
-Result ARCExprEmitter<Impl,Result>::visitCastExpr(const CastExpr *e) {
- switch (e->getCastKind()) {
-
- // No-op casts don't change the type, so we just ignore them.
- case CK_NoOp:
- return asImpl().visit(e->getSubExpr());
-
- // These casts can change the type.
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_BitCast: {
- llvm::Type *resultType = CGF.ConvertType(e->getType());
- assert(e->getSubExpr()->getType()->hasPointerRepresentation());
- Result result = asImpl().visit(e->getSubExpr());
- return asImpl().emitBitCast(result, resultType);
- }
-
- // Handle some casts specially.
- case CK_LValueToRValue:
- return asImpl().visitLValueToRValue(e->getSubExpr());
- case CK_ARCConsumeObject:
- return asImpl().visitConsumeObject(e->getSubExpr());
- case CK_ARCExtendBlockObject:
- return asImpl().visitExtendBlockObject(e->getSubExpr());
- case CK_ARCReclaimReturnedObject:
- return asImpl().visitReclaimReturnedObject(e->getSubExpr());
-
- // Otherwise, use the default logic.
- default:
- return asImpl().visitExpr(e);
- }
-}
-
-template <typename Impl, typename Result>
-Result
-ARCExprEmitter<Impl,Result>::visitBinaryOperator(const BinaryOperator *e) {
- switch (e->getOpcode()) {
- case BO_Comma:
- CGF.EmitIgnoredExpr(e->getLHS());
- CGF.EnsureInsertPoint();
- return asImpl().visit(e->getRHS());
-
- case BO_Assign:
- return asImpl().visitBinAssign(e);
-
- default:
- return asImpl().visitExpr(e);
- }
-}
-
-template <typename Impl, typename Result>
-Result ARCExprEmitter<Impl,Result>::visitBinAssign(const BinaryOperator *e) {
- switch (e->getLHS()->getType().getObjCLifetime()) {
- case Qualifiers::OCL_ExplicitNone:
- return asImpl().visitBinAssignUnsafeUnretained(e);
-
- case Qualifiers::OCL_Weak:
- return asImpl().visitBinAssignWeak(e);
-
- case Qualifiers::OCL_Autoreleasing:
- return asImpl().visitBinAssignAutoreleasing(e);
-
- case Qualifiers::OCL_Strong:
- return asImpl().visitBinAssignStrong(e);
-
- case Qualifiers::OCL_None:
- return asImpl().visitExpr(e);
- }
- llvm_unreachable("bad ObjC ownership qualifier");
-}
-
-/// The default rule for __unsafe_unretained emits the RHS recursively,
-/// stores into the unsafe variable, and propagates the result outward.
-template <typename Impl, typename Result>
-Result ARCExprEmitter<Impl,Result>::
- visitBinAssignUnsafeUnretained(const BinaryOperator *e) {
- // Recursively emit the RHS.
- // For __block safety, do this before emitting the LHS.
- Result result = asImpl().visit(e->getRHS());
-
- // Perform the store.
- LValue lvalue =
- CGF.EmitCheckedLValue(e->getLHS(), CodeGenFunction::TCK_Store);
- CGF.EmitStoreThroughLValue(RValue::get(asImpl().getValueOfResult(result)),
- lvalue);
-
- return result;
-}
-
-template <typename Impl, typename Result>
-Result
-ARCExprEmitter<Impl,Result>::visitBinAssignAutoreleasing(const BinaryOperator *e) {
- return asImpl().visitExpr(e);
-}
-
-template <typename Impl, typename Result>
-Result
-ARCExprEmitter<Impl,Result>::visitBinAssignWeak(const BinaryOperator *e) {
- return asImpl().visitExpr(e);
-}
-
-template <typename Impl, typename Result>
-Result
-ARCExprEmitter<Impl,Result>::visitBinAssignStrong(const BinaryOperator *e) {
- return asImpl().visitExpr(e);
-}
-
-/// The general expression-emission logic.
-template <typename Impl, typename Result>
-Result ARCExprEmitter<Impl,Result>::visit(const Expr *e) {
- // We should *never* see a nested full-expression here, because if
- // we fail to emit at +1, our caller must not retain after we close
- // out the full-expression. This isn't as important in the unsafe
- // emitter.
- assert(!isa<ExprWithCleanups>(e));
-
- // Look through parens, __extension__, generic selection, etc.
- e = e->IgnoreParens();
-
- // Handle certain kinds of casts.
- if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
- return asImpl().visitCastExpr(ce);
-
- // Handle the comma operator.
- } else if (auto op = dyn_cast<BinaryOperator>(e)) {
- return asImpl().visitBinaryOperator(op);
-
- // TODO: handle conditional operators here
-
- // For calls and message sends, use the retained-call logic.
- // Delegate inits are a special case in that they're the only
- // returns-retained expression that *isn't* surrounded by
- // a consume.
- } else if (isa<CallExpr>(e) ||
- (isa<ObjCMessageExpr>(e) &&
- !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
- return asImpl().visitCall(e);
-
- // Look through pseudo-object expressions.
- } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
- return asImpl().visitPseudoObjectExpr(pseudo);
- }
-
- return asImpl().visitExpr(e);
-}
-
-namespace {
-
-/// An emitter for +1 results.
-struct ARCRetainExprEmitter :
- public ARCExprEmitter<ARCRetainExprEmitter, TryEmitResult> {
-
- ARCRetainExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
-
- llvm::Value *getValueOfResult(TryEmitResult result) {
- return result.getPointer();
- }
-
- TryEmitResult emitBitCast(TryEmitResult result, llvm::Type *resultType) {
- llvm::Value *value = result.getPointer();
- value = CGF.Builder.CreateBitCast(value, resultType);
- result.setPointer(value);
- return result;
- }
-
- TryEmitResult visitLValueToRValue(const Expr *e) {
- return tryEmitARCRetainLoadOfScalar(CGF, e);
- }
-
- /// For consumptions, just emit the subexpression and thus elide
- /// the retain/release pair.
- TryEmitResult visitConsumeObject(const Expr *e) {
- llvm::Value *result = CGF.EmitScalarExpr(e);
- return TryEmitResult(result, true);
- }
-
- /// Block extends are net +0. Naively, we could just recurse on
- /// the subexpression, but actually we need to ensure that the
- /// value is copied as a block, so there's a little filter here.
- TryEmitResult visitExtendBlockObject(const Expr *e) {
- llvm::Value *result; // will be a +0 value
-
- // If we can't safely assume the sub-expression will produce a
- // block-copied value, emit the sub-expression at +0.
- if (shouldEmitSeparateBlockRetain(e)) {
- result = CGF.EmitScalarExpr(e);
-
- // Otherwise, try to emit the sub-expression at +1 recursively.
- } else {
- TryEmitResult subresult = asImpl().visit(e);
-
- // If that produced a retained value, just use that.
- if (subresult.getInt()) {
- return subresult;
- }
-
- // Otherwise it's +0.
- result = subresult.getPointer();
- }
-
- // Retain the object as a block.
- result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
- return TryEmitResult(result, true);
- }
-
- /// For reclaims, emit the subexpression as a retained call and
- /// skip the consumption.
- TryEmitResult visitReclaimReturnedObject(const Expr *e) {
- llvm::Value *result = emitARCRetainCallResult(CGF, e);
- return TryEmitResult(result, true);
- }
-
- /// When we have an undecorated call, retroactively do a claim.
- TryEmitResult visitCall(const Expr *e) {
- llvm::Value *result = emitARCRetainCallResult(CGF, e);
- return TryEmitResult(result, true);
- }
-
- // TODO: maybe special-case visitBinAssignWeak?
-
- TryEmitResult visitExpr(const Expr *e) {
- // We didn't find an obvious production, so emit what we've got and
- // tell the caller that we didn't manage to retain.
- llvm::Value *result = CGF.EmitScalarExpr(e);
- return TryEmitResult(result, false);
- }
-};
-}
-
-static TryEmitResult
-tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
- return ARCRetainExprEmitter(CGF).visit(e);
-}
-
-static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
- LValue lvalue,
- QualType type) {
- TryEmitResult result = tryEmitARCRetainLoadOfScalar(CGF, lvalue, type);
- llvm::Value *value = result.getPointer();
- if (!result.getInt())
- value = CGF.EmitARCRetain(type, value);
- return value;
-}
-
-/// EmitARCRetainScalarExpr - Semantically equivalent to
-/// EmitARCRetainObject(e->getType(), EmitScalarExpr(e)), but making a
-/// best-effort attempt to peephole expressions that naturally produce
-/// retained objects.
-llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
- // The retain needs to happen within the full-expression.
- if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
- enterFullExpression(cleanups);
- RunCleanupsScope scope(*this);
- return EmitARCRetainScalarExpr(cleanups->getSubExpr());
- }
-
- TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
- llvm::Value *value = result.getPointer();
- if (!result.getInt())
- value = EmitARCRetain(e->getType(), value);
- return value;
-}
-
-llvm::Value *
-CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
- // The retain needs to happen within the full-expression.
- if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
- enterFullExpression(cleanups);
- RunCleanupsScope scope(*this);
- return EmitARCRetainAutoreleaseScalarExpr(cleanups->getSubExpr());
- }
-
- TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
- llvm::Value *value = result.getPointer();
- if (result.getInt())
- value = EmitARCAutorelease(value);
- else
- value = EmitARCRetainAutorelease(e->getType(), value);
- return value;
-}
-
-llvm::Value *CodeGenFunction::EmitARCExtendBlockObject(const Expr *e) {
- llvm::Value *result;
- bool doRetain;
-
- if (shouldEmitSeparateBlockRetain(e)) {
- result = EmitScalarExpr(e);
- doRetain = true;
- } else {
- TryEmitResult subresult = tryEmitARCRetainScalarExpr(*this, e);
- result = subresult.getPointer();
- doRetain = !subresult.getInt();
- }
-
- if (doRetain)
- result = EmitARCRetainBlock(result, /*mandatory*/ true);
- return EmitObjCConsumeObject(e->getType(), result);
-}
-
-llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
- // In ARC, retain and autorelease the expression.
- if (getLangOpts().ObjCAutoRefCount) {
- // Do so before running any cleanups for the full-expression.
- // EmitARCRetainAutoreleaseScalarExpr does this for us.
- return EmitARCRetainAutoreleaseScalarExpr(expr);
- }
-
- // Otherwise, use the normal scalar-expression emission. The
- // exception machinery doesn't do anything special with the
- // exception like retaining it, so there's no safety associated with
- // only running cleanups after the throw has started, and when it
- // matters it tends to be substantially inferior code.
- return EmitScalarExpr(expr);
-}
-
-namespace {
-
-/// An emitter for assigning into an __unsafe_unretained context.
-struct ARCUnsafeUnretainedExprEmitter :
- public ARCExprEmitter<ARCUnsafeUnretainedExprEmitter, llvm::Value*> {
-
- ARCUnsafeUnretainedExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
-
- llvm::Value *getValueOfResult(llvm::Value *value) {
- return value;
- }
-
- llvm::Value *emitBitCast(llvm::Value *value, llvm::Type *resultType) {
- return CGF.Builder.CreateBitCast(value, resultType);
- }
-
- llvm::Value *visitLValueToRValue(const Expr *e) {
- return CGF.EmitScalarExpr(e);
- }
-
- /// For consumptions, just emit the subexpression and perform the
- /// consumption like normal.
- llvm::Value *visitConsumeObject(const Expr *e) {
- llvm::Value *value = CGF.EmitScalarExpr(e);
- return CGF.EmitObjCConsumeObject(e->getType(), value);
- }
-
- /// No special logic for block extensions. (This probably can't
- /// actually happen in this emitter, though.)
- llvm::Value *visitExtendBlockObject(const Expr *e) {
- return CGF.EmitARCExtendBlockObject(e);
- }
-
- /// For reclaims, perform an unsafeClaim if that's enabled.
- llvm::Value *visitReclaimReturnedObject(const Expr *e) {
- return CGF.EmitARCReclaimReturnedObject(e, /*unsafe*/ true);
- }
-
- /// When we have an undecorated call, just emit it without adding
- /// the unsafeClaim.
- llvm::Value *visitCall(const Expr *e) {
- return CGF.EmitScalarExpr(e);
- }
-
- /// Just do normal scalar emission in the default case.
- llvm::Value *visitExpr(const Expr *e) {
- return CGF.EmitScalarExpr(e);
- }
-};
-}
-
-static llvm::Value *emitARCUnsafeUnretainedScalarExpr(CodeGenFunction &CGF,
- const Expr *e) {
- return ARCUnsafeUnretainedExprEmitter(CGF).visit(e);
-}
-
-/// EmitARCUnsafeUnretainedScalarExpr - Semantically equivalent to
-/// immediately releasing the resut of EmitARCRetainScalarExpr, but
-/// avoiding any spurious retains, including by performing reclaims
-/// with objc_unsafeClaimAutoreleasedReturnValue.
-llvm::Value *CodeGenFunction::EmitARCUnsafeUnretainedScalarExpr(const Expr *e) {
- // Look through full-expressions.
- if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
- enterFullExpression(cleanups);
- RunCleanupsScope scope(*this);
- return emitARCUnsafeUnretainedScalarExpr(*this, cleanups->getSubExpr());
- }
-
- return emitARCUnsafeUnretainedScalarExpr(*this, e);
-}
-
-std::pair<LValue,llvm::Value*>
-CodeGenFunction::EmitARCStoreUnsafeUnretained(const BinaryOperator *e,
- bool ignored) {
- // Evaluate the RHS first. If we're ignoring the result, assume
- // that we can emit at an unsafe +0.
- llvm::Value *value;
- if (ignored) {
- value = EmitARCUnsafeUnretainedScalarExpr(e->getRHS());
- } else {
- value = EmitScalarExpr(e->getRHS());
- }
-
- // Emit the LHS and perform the store.
- LValue lvalue = EmitLValue(e->getLHS());
- EmitStoreOfScalar(value, lvalue);
-
- return std::pair<LValue,llvm::Value*>(std::move(lvalue), value);
-}
-
-std::pair<LValue,llvm::Value*>
-CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
- bool ignored) {
- // Evaluate the RHS first.
- TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS());
- llvm::Value *value = result.getPointer();
-
- bool hasImmediateRetain = result.getInt();
-
- // If we didn't emit a retained object, and the l-value is of block
- // type, then we need to emit the block-retain immediately in case
- // it invalidates the l-value.
- if (!hasImmediateRetain && e->getType()->isBlockPointerType()) {
- value = EmitARCRetainBlock(value, /*mandatory*/ false);
- hasImmediateRetain = true;
- }
-
- LValue lvalue = EmitLValue(e->getLHS());
-
- // If the RHS was emitted retained, expand this.
- if (hasImmediateRetain) {
- llvm::Value *oldValue = EmitLoadOfScalar(lvalue, SourceLocation());
- EmitStoreOfScalar(value, lvalue);
- EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime());
- } else {
- value = EmitARCStoreStrong(lvalue, value, ignored);
- }
-
- return std::pair<LValue,llvm::Value*>(lvalue, value);
-}
-
-std::pair<LValue,llvm::Value*>
-CodeGenFunction::EmitARCStoreAutoreleasing(const BinaryOperator *e) {
- llvm::Value *value = EmitARCRetainAutoreleaseScalarExpr(e->getRHS());
- LValue lvalue = EmitLValue(e->getLHS());
-
- EmitStoreOfScalar(value, lvalue);
-
- return std::pair<LValue,llvm::Value*>(lvalue, value);
-}
-
-void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
- const ObjCAutoreleasePoolStmt &ARPS) {
- const Stmt *subStmt = ARPS.getSubStmt();
- const CompoundStmt &S = cast<CompoundStmt>(*subStmt);
-
- CGDebugInfo *DI = getDebugInfo();
- if (DI)
- DI->EmitLexicalBlockStart(Builder, S.getLBracLoc());
-
- // Keep track of the current cleanup stack depth.
- RunCleanupsScope Scope(*this);
- if (CGM.getLangOpts().ObjCRuntime.hasNativeARC()) {
- llvm::Value *token = EmitObjCAutoreleasePoolPush();
- EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token);
- } else {
- llvm::Value *token = EmitObjCMRRAutoreleasePoolPush();
- EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, token);
- }
-
- for (const auto *I : S.body())
- EmitStmt(I);
-
- if (DI)
- DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
-}
-
-/// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
-/// make sure it survives garbage collection until this point.
-void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
- // We just use an inline assembly.
- llvm::FunctionType *extenderType
- = llvm::FunctionType::get(VoidTy, VoidPtrTy, RequiredArgs::All);
- llvm::Value *extender
- = llvm::InlineAsm::get(extenderType,
- /* assembly */ "",
- /* constraints */ "r",
- /* side effects */ true);
-
- object = Builder.CreateBitCast(object, VoidPtrTy);
- EmitNounwindRuntimeCall(extender, object);
-}
-
-/// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with
-/// non-trivial copy assignment function, produce following helper function.
-/// static void copyHelper(Ty *dest, const Ty *source) { *dest = *source; }
-///
-llvm::Constant *
-CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
- const ObjCPropertyImplDecl *PID) {
- if (!getLangOpts().CPlusPlus ||
- !getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
- return nullptr;
- QualType Ty = PID->getPropertyIvarDecl()->getType();
- if (!Ty->isRecordType())
- return nullptr;
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- if ((!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic)))
- return nullptr;
- llvm::Constant *HelperFn = nullptr;
- if (hasTrivialSetExpr(PID))
- return nullptr;
- assert(PID->getSetterCXXAssignment() && "SetterCXXAssignment - null");
- if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty)))
- return HelperFn;
-
- ASTContext &C = getContext();
- IdentifierInfo *II
- = &CGM.getContext().Idents.get("__assign_helper_atomic_property_");
-
- QualType ReturnTy = C.VoidTy;
- QualType DestTy = C.getPointerType(Ty);
- QualType SrcTy = Ty;
- SrcTy.addConst();
- SrcTy = C.getPointerType(SrcTy);
-
- SmallVector<QualType, 2> ArgTys;
- ArgTys.push_back(DestTy);
- ArgTys.push_back(SrcTy);
- QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
-
- FunctionDecl *FD = FunctionDecl::Create(
- C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
- FunctionTy, nullptr, SC_Static, false, false);
-
- FunctionArgList args;
- ImplicitParamDecl DstDecl(C, FD, SourceLocation(), /*Id=*/nullptr, DestTy,
- ImplicitParamDecl::Other);
- args.push_back(&DstDecl);
- ImplicitParamDecl SrcDecl(C, FD, SourceLocation(), /*Id=*/nullptr, SrcTy,
- ImplicitParamDecl::Other);
- args.push_back(&SrcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
-
- llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
-
- llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__assign_helper_atomic_property_",
- &CGM.getModule());
-
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
- StartFunction(FD, ReturnTy, Fn, FI, args);
-
- DeclRefExpr DstExpr(getContext(), &DstDecl, false, DestTy, VK_RValue,
- SourceLocation());
- UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
- VK_LValue, OK_Ordinary, SourceLocation(), false);
-
- DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
- SourceLocation());
- UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
- VK_LValue, OK_Ordinary, SourceLocation(), false);
-
- Expr *Args[2] = { &DST, &SRC };
- CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
- CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
- VK_LValue, SourceLocation(), FPOptions());
-
- EmitStmt(TheCall);
-
- FinishFunction();
- HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
- CGM.setAtomicSetterHelperFnMap(Ty, HelperFn);
- return HelperFn;
-}
-
-llvm::Constant *
-CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
- const ObjCPropertyImplDecl *PID) {
- if (!getLangOpts().CPlusPlus ||
- !getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
- return nullptr;
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- QualType Ty = PD->getType();
- if (!Ty->isRecordType())
- return nullptr;
- if ((!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic)))
- return nullptr;
- llvm::Constant *HelperFn = nullptr;
- if (hasTrivialGetExpr(PID))
- return nullptr;
- assert(PID->getGetterCXXConstructor() && "getGetterCXXConstructor - null");
- if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty)))
- return HelperFn;
-
- ASTContext &C = getContext();
- IdentifierInfo *II =
- &CGM.getContext().Idents.get("__copy_helper_atomic_property_");
-
- QualType ReturnTy = C.VoidTy;
- QualType DestTy = C.getPointerType(Ty);
- QualType SrcTy = Ty;
- SrcTy.addConst();
- SrcTy = C.getPointerType(SrcTy);
-
- SmallVector<QualType, 2> ArgTys;
- ArgTys.push_back(DestTy);
- ArgTys.push_back(SrcTy);
- QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
-
- FunctionDecl *FD = FunctionDecl::Create(
- C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
- FunctionTy, nullptr, SC_Static, false, false);
-
- FunctionArgList args;
- ImplicitParamDecl DstDecl(C, FD, SourceLocation(), /*Id=*/nullptr, DestTy,
- ImplicitParamDecl::Other);
- args.push_back(&DstDecl);
- ImplicitParamDecl SrcDecl(C, FD, SourceLocation(), /*Id=*/nullptr, SrcTy,
- ImplicitParamDecl::Other);
- args.push_back(&SrcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
-
- llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
-
- llvm::Function *Fn = llvm::Function::Create(
- LTy, llvm::GlobalValue::InternalLinkage, "__copy_helper_atomic_property_",
- &CGM.getModule());
-
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
- StartFunction(FD, ReturnTy, Fn, FI, args);
-
- DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
- SourceLocation());
-
- UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
- VK_LValue, OK_Ordinary, SourceLocation(), false);
-
- CXXConstructExpr *CXXConstExpr =
- cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
-
- SmallVector<Expr*, 4> ConstructorArgs;
- ConstructorArgs.push_back(&SRC);
- ConstructorArgs.append(std::next(CXXConstExpr->arg_begin()),
- CXXConstExpr->arg_end());
-
- CXXConstructExpr *TheCXXConstructExpr =
- CXXConstructExpr::Create(C, Ty, SourceLocation(),
- CXXConstExpr->getConstructor(),
- CXXConstExpr->isElidable(),
- ConstructorArgs,
- CXXConstExpr->hadMultipleCandidates(),
- CXXConstExpr->isListInitialization(),
- CXXConstExpr->isStdInitListInitialization(),
- CXXConstExpr->requiresZeroInitialization(),
- CXXConstExpr->getConstructionKind(),
- SourceRange());
-
- DeclRefExpr DstExpr(getContext(), &DstDecl, false, DestTy, VK_RValue,
- SourceLocation());
-
- RValue DV = EmitAnyExpr(&DstExpr);
- CharUnits Alignment
- = getContext().getTypeAlignInChars(TheCXXConstructExpr->getType());
- EmitAggExpr(TheCXXConstructExpr,
- AggValueSlot::forAddr(Address(DV.getScalarVal(), Alignment),
- Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
-
- FinishFunction();
- HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
- CGM.setAtomicGetterHelperFnMap(Ty, HelperFn);
- return HelperFn;
-}
-
-llvm::Value *
-CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) {
- // Get selectors for retain/autorelease.
- IdentifierInfo *CopyID = &getContext().Idents.get("copy");
- Selector CopySelector =
- getContext().Selectors.getNullarySelector(CopyID);
- IdentifierInfo *AutoreleaseID = &getContext().Idents.get("autorelease");
- Selector AutoreleaseSelector =
- getContext().Selectors.getNullarySelector(AutoreleaseID);
-
- // Emit calls to retain/autorelease.
- CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Val = Block;
- RValue Result;
- Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
- Ty, CopySelector,
- Val, CallArgList(), nullptr, nullptr);
- Val = Result.getScalarVal();
- Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
- Ty, AutoreleaseSelector,
- Val, CallArgList(), nullptr, nullptr);
- Val = Result.getScalarVal();
- return Val;
-}
-
-llvm::Value *
-CodeGenFunction::EmitBuiltinAvailable(ArrayRef<llvm::Value *> Args) {
- assert(Args.size() == 3 && "Expected 3 argument here!");
-
- if (!CGM.IsOSVersionAtLeastFn) {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int32Ty, {Int32Ty, Int32Ty, Int32Ty}, false);
- CGM.IsOSVersionAtLeastFn =
- CGM.CreateRuntimeFunction(FTy, "__isOSVersionAtLeast");
- }
-
- llvm::Value *CallRes =
- EmitNounwindRuntimeCall(CGM.IsOSVersionAtLeastFn, Args);
-
- return Builder.CreateICmpNE(CallRes, llvm::Constant::getNullValue(Int32Ty));
-}
-
-void CodeGenModule::emitAtAvailableLinkGuard() {
- if (!IsOSVersionAtLeastFn)
- return;
- // @available requires CoreFoundation only on Darwin.
- if (!Target.getTriple().isOSDarwin())
- return;
- // Add -framework CoreFoundation to the linker commands. We still want to
- // emit the core foundation reference down below because otherwise if
- // CoreFoundation is not used in the code, the linker won't link the
- // framework.
- auto &Context = getLLVMContext();
- llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"),
- llvm::MDString::get(Context, "CoreFoundation")};
- LinkerOptionsMetadata.push_back(llvm::MDNode::get(Context, Args));
- // Emit a reference to a symbol from CoreFoundation to ensure that
- // CoreFoundation is linked into the final binary.
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int32Ty, {VoidPtrTy}, false);
- llvm::Constant *CFFunc =
- CreateRuntimeFunction(FTy, "CFBundleGetVersionNumber");
-
- llvm::FunctionType *CheckFTy = llvm::FunctionType::get(VoidTy, {}, false);
- llvm::Function *CFLinkCheckFunc = cast<llvm::Function>(CreateBuiltinFunction(
- CheckFTy, "__clang_at_available_requires_core_foundation_framework"));
- CFLinkCheckFunc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
- CFLinkCheckFunc->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CodeGenFunction CGF(*this);
- CGF.Builder.SetInsertPoint(CGF.createBasicBlock("", CFLinkCheckFunc));
- CGF.EmitNounwindRuntimeCall(CFFunc, llvm::Constant::getNullValue(VoidPtrTy));
- CGF.Builder.CreateUnreachable();
- addCompilerUsedGlobal(CFLinkCheckFunc);
-}
-
-CGObjCRuntime::~CGObjCRuntime() {}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp
deleted file mode 100644
index 548bd6b3fd7..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp
+++ /dev/null
@@ -1,4022 +0,0 @@
-//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides Objective-C code generation targeting the GNU runtime. The
-// class in this file generates structures used by the GNU Objective-C runtime
-// library. These structures are defined in objc/objc.h and objc/objc-api.h in
-// the GNU runtime distribution.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGObjCRuntime.h"
-#include "CGCleanup.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "CGCXXABI.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/ConvertUTF.h"
-#include <cctype>
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-
-std::string SymbolNameForMethod( StringRef ClassName,
- StringRef CategoryName, const Selector MethodName,
- bool isClassMethod) {
- std::string MethodNameColonStripped = MethodName.getAsString();
- std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
- ':', '_');
- return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
- CategoryName + "_" + MethodNameColonStripped).str();
-}
-
-/// Class that lazily initialises the runtime function. Avoids inserting the
-/// types and the function declaration into a module if they're not used, and
-/// avoids constructing the type more than once if it's used more than once.
-class LazyRuntimeFunction {
- CodeGenModule *CGM;
- llvm::FunctionType *FTy;
- const char *FunctionName;
- llvm::Constant *Function;
-
-public:
- /// Constructor leaves this class uninitialized, because it is intended to
- /// be used as a field in another class and not all of the types that are
- /// used as arguments will necessarily be available at construction time.
- LazyRuntimeFunction()
- : CGM(nullptr), FunctionName(nullptr), Function(nullptr) {}
-
- /// Initialises the lazy function with the name, return type, and the types
- /// of the arguments.
- template <typename... Tys>
- void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy,
- Tys *... Types) {
- CGM = Mod;
- FunctionName = name;
- Function = nullptr;
- if(sizeof...(Tys)) {
- SmallVector<llvm::Type *, 8> ArgTys({Types...});
- FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
- }
- else {
- FTy = llvm::FunctionType::get(RetTy, None, false);
- }
- }
-
- llvm::FunctionType *getType() { return FTy; }
-
- /// Overloaded cast operator, allows the class to be implicitly cast to an
- /// LLVM constant.
- operator llvm::Constant *() {
- if (!Function) {
- if (!FunctionName)
- return nullptr;
- Function = CGM->CreateRuntimeFunction(FTy, FunctionName);
- }
- return Function;
- }
- operator llvm::Function *() {
- return cast<llvm::Function>((llvm::Constant *)*this);
- }
-};
-
-
-/// GNU Objective-C runtime code generation. This class implements the parts of
-/// Objective-C support that are specific to the GNU family of runtimes (GCC,
-/// GNUstep and ObjFW).
-class CGObjCGNU : public CGObjCRuntime {
-protected:
- /// The LLVM module into which output is inserted
- llvm::Module &TheModule;
- /// strut objc_super. Used for sending messages to super. This structure
- /// contains the receiver (object) and the expected class.
- llvm::StructType *ObjCSuperTy;
- /// struct objc_super*. The type of the argument to the superclass message
- /// lookup functions.
- llvm::PointerType *PtrToObjCSuperTy;
- /// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring
- /// SEL is included in a header somewhere, in which case it will be whatever
- /// type is declared in that header, most likely {i8*, i8*}.
- llvm::PointerType *SelectorTy;
- /// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the
- /// places where it's used
- llvm::IntegerType *Int8Ty;
- /// Pointer to i8 - LLVM type of char*, for all of the places where the
- /// runtime needs to deal with C strings.
- llvm::PointerType *PtrToInt8Ty;
- /// struct objc_protocol type
- llvm::StructType *ProtocolTy;
- /// Protocol * type.
- llvm::PointerType *ProtocolPtrTy;
- /// Instance Method Pointer type. This is a pointer to a function that takes,
- /// at a minimum, an object and a selector, and is the generic type for
- /// Objective-C methods. Due to differences between variadic / non-variadic
- /// calling conventions, it must always be cast to the correct type before
- /// actually being used.
- llvm::PointerType *IMPTy;
- /// Type of an untyped Objective-C object. Clang treats id as a built-in type
- /// when compiling Objective-C code, so this may be an opaque pointer (i8*),
- /// but if the runtime header declaring it is included then it may be a
- /// pointer to a structure.
- llvm::PointerType *IdTy;
- /// Pointer to a pointer to an Objective-C object. Used in the new ABI
- /// message lookup function and some GC-related functions.
- llvm::PointerType *PtrToIdTy;
- /// The clang type of id. Used when using the clang CGCall infrastructure to
- /// call Objective-C methods.
- CanQualType ASTIdTy;
- /// LLVM type for C int type.
- llvm::IntegerType *IntTy;
- /// LLVM type for an opaque pointer. This is identical to PtrToInt8Ty, but is
- /// used in the code to document the difference between i8* meaning a pointer
- /// to a C string and i8* meaning a pointer to some opaque type.
- llvm::PointerType *PtrTy;
- /// LLVM type for C long type. The runtime uses this in a lot of places where
- /// it should be using intptr_t, but we can't fix this without breaking
- /// compatibility with GCC...
- llvm::IntegerType *LongTy;
- /// LLVM type for C size_t. Used in various runtime data structures.
- llvm::IntegerType *SizeTy;
- /// LLVM type for C intptr_t.
- llvm::IntegerType *IntPtrTy;
- /// LLVM type for C ptrdiff_t. Mainly used in property accessor functions.
- llvm::IntegerType *PtrDiffTy;
- /// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance
- /// variables.
- llvm::PointerType *PtrToIntTy;
- /// LLVM type for Objective-C BOOL type.
- llvm::Type *BoolTy;
- /// 32-bit integer type, to save us needing to look it up every time it's used.
- llvm::IntegerType *Int32Ty;
- /// 64-bit integer type, to save us needing to look it up every time it's used.
- llvm::IntegerType *Int64Ty;
- /// The type of struct objc_property.
- llvm::StructType *PropertyMetadataTy;
- /// Metadata kind used to tie method lookups to message sends. The GNUstep
- /// runtime provides some LLVM passes that can use this to do things like
- /// automatic IMP caching and speculative inlining.
- unsigned msgSendMDKind;
- /// Does the current target use SEH-based exceptions? False implies
- /// Itanium-style DWARF unwinding.
- bool usesSEHExceptions;
-
- /// Helper to check if we are targeting a specific runtime version or later.
- bool isRuntime(ObjCRuntime::Kind kind, unsigned major, unsigned minor=0) {
- const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
- return (R.getKind() == kind) &&
- (R.getVersion() >= VersionTuple(major, minor));
- }
-
- std::string SymbolForProtocol(StringRef Name) {
- return (StringRef("._OBJC_PROTOCOL_") + Name).str();
- }
-
- std::string SymbolForProtocolRef(StringRef Name) {
- return (StringRef("._OBJC_REF_PROTOCOL_") + Name).str();
- }
-
-
- /// Helper function that generates a constant string and returns a pointer to
- /// the start of the string. The result of this function can be used anywhere
- /// where the C code specifies const char*.
- llvm::Constant *MakeConstantString(StringRef Str, const char *Name = "") {
- ConstantAddress Array = CGM.GetAddrOfConstantCString(Str, Name);
- return llvm::ConstantExpr::getGetElementPtr(Array.getElementType(),
- Array.getPointer(), Zeros);
- }
-
- /// Emits a linkonce_odr string, whose name is the prefix followed by the
- /// string value. This allows the linker to combine the strings between
- /// different modules. Used for EH typeinfo names, selector strings, and a
- /// few other things.
- llvm::Constant *ExportUniqueString(const std::string &Str,
- const std::string &prefix,
- bool Private=false) {
- std::string name = prefix + Str;
- auto *ConstStr = TheModule.getGlobalVariable(name);
- if (!ConstStr) {
- llvm::Constant *value = llvm::ConstantDataArray::getString(VMContext,Str);
- auto *GV = new llvm::GlobalVariable(TheModule, value->getType(), true,
- llvm::GlobalValue::LinkOnceODRLinkage, value, name);
- GV->setComdat(TheModule.getOrInsertComdat(name));
- if (Private)
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- ConstStr = GV;
- }
- return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(),
- ConstStr, Zeros);
- }
-
- /// Returns a property name and encoding string.
- llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD,
- const Decl *Container) {
- assert(!isRuntime(ObjCRuntime::GNUstep, 2));
- if (isRuntime(ObjCRuntime::GNUstep, 1, 6)) {
- std::string NameAndAttributes;
- std::string TypeStr =
- CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container);
- NameAndAttributes += '\0';
- NameAndAttributes += TypeStr.length() + 3;
- NameAndAttributes += TypeStr;
- NameAndAttributes += '\0';
- NameAndAttributes += PD->getNameAsString();
- return MakeConstantString(NameAndAttributes);
- }
- return MakeConstantString(PD->getNameAsString());
- }
-
- /// Push the property attributes into two structure fields.
- void PushPropertyAttributes(ConstantStructBuilder &Fields,
- const ObjCPropertyDecl *property, bool isSynthesized=true, bool
- isDynamic=true) {
- int attrs = property->getPropertyAttributes();
- // For read-only properties, clear the copy and retain flags
- if (attrs & ObjCPropertyDecl::OBJC_PR_readonly) {
- attrs &= ~ObjCPropertyDecl::OBJC_PR_copy;
- attrs &= ~ObjCPropertyDecl::OBJC_PR_retain;
- attrs &= ~ObjCPropertyDecl::OBJC_PR_weak;
- attrs &= ~ObjCPropertyDecl::OBJC_PR_strong;
- }
- // The first flags field has the same attribute values as clang uses internally
- Fields.addInt(Int8Ty, attrs & 0xff);
- attrs >>= 8;
- attrs <<= 2;
- // For protocol properties, synthesized and dynamic have no meaning, so we
- // reuse these flags to indicate that this is a protocol property (both set
- // has no meaning, as a property can't be both synthesized and dynamic)
- attrs |= isSynthesized ? (1<<0) : 0;
- attrs |= isDynamic ? (1<<1) : 0;
- // The second field is the next four fields left shifted by two, with the
- // low bit set to indicate whether the field is synthesized or dynamic.
- Fields.addInt(Int8Ty, attrs & 0xff);
- // Two padding fields
- Fields.addInt(Int8Ty, 0);
- Fields.addInt(Int8Ty, 0);
- }
-
- virtual llvm::Constant *GenerateCategoryProtocolList(const
- ObjCCategoryDecl *OCD);
- virtual ConstantArrayBuilder PushPropertyListHeader(ConstantStructBuilder &Fields,
- int count) {
- // int count;
- Fields.addInt(IntTy, count);
- // int size; (only in GNUstep v2 ABI.
- if (isRuntime(ObjCRuntime::GNUstep, 2)) {
- llvm::DataLayout td(&TheModule);
- Fields.addInt(IntTy, td.getTypeSizeInBits(PropertyMetadataTy) /
- CGM.getContext().getCharWidth());
- }
- // struct objc_property_list *next;
- Fields.add(NULLPtr);
- // struct objc_property properties[]
- return Fields.beginArray(PropertyMetadataTy);
- }
- virtual void PushProperty(ConstantArrayBuilder &PropertiesArray,
- const ObjCPropertyDecl *property,
- const Decl *OCD,
- bool isSynthesized=true, bool
- isDynamic=true) {
- auto Fields = PropertiesArray.beginStruct(PropertyMetadataTy);
- ASTContext &Context = CGM.getContext();
- Fields.add(MakePropertyEncodingString(property, OCD));
- PushPropertyAttributes(Fields, property, isSynthesized, isDynamic);
- auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
- if (accessor) {
- std::string TypeStr = Context.getObjCEncodingForMethodDecl(accessor);
- llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
- Fields.add(MakeConstantString(accessor->getSelector().getAsString()));
- Fields.add(TypeEncoding);
- } else {
- Fields.add(NULLPtr);
- Fields.add(NULLPtr);
- }
- };
- addPropertyMethod(property->getGetterMethodDecl());
- addPropertyMethod(property->getSetterMethodDecl());
- Fields.finishAndAddTo(PropertiesArray);
- }
-
- /// Ensures that the value has the required type, by inserting a bitcast if
- /// required. This function lets us avoid inserting bitcasts that are
- /// redundant.
- llvm::Value* EnforceType(CGBuilderTy &B, llvm::Value *V, llvm::Type *Ty) {
- if (V->getType() == Ty) return V;
- return B.CreateBitCast(V, Ty);
- }
- Address EnforceType(CGBuilderTy &B, Address V, llvm::Type *Ty) {
- if (V.getType() == Ty) return V;
- return B.CreateBitCast(V, Ty);
- }
-
- // Some zeros used for GEPs in lots of places.
- llvm::Constant *Zeros[2];
- /// Null pointer value. Mainly used as a terminator in various arrays.
- llvm::Constant *NULLPtr;
- /// LLVM context.
- llvm::LLVMContext &VMContext;
-
-protected:
-
- /// Placeholder for the class. Lots of things refer to the class before we've
- /// actually emitted it. We use this alias as a placeholder, and then replace
- /// it with a pointer to the class structure before finally emitting the
- /// module.
- llvm::GlobalAlias *ClassPtrAlias;
- /// Placeholder for the metaclass. Lots of things refer to the class before
- /// we've / actually emitted it. We use this alias as a placeholder, and then
- /// replace / it with a pointer to the metaclass structure before finally
- /// emitting the / module.
- llvm::GlobalAlias *MetaClassPtrAlias;
- /// All of the classes that have been generated for this compilation units.
- std::vector<llvm::Constant*> Classes;
- /// All of the categories that have been generated for this compilation units.
- std::vector<llvm::Constant*> Categories;
- /// All of the Objective-C constant strings that have been generated for this
- /// compilation units.
- std::vector<llvm::Constant*> ConstantStrings;
- /// Map from string values to Objective-C constant strings in the output.
- /// Used to prevent emitting Objective-C strings more than once. This should
- /// not be required at all - CodeGenModule should manage this list.
- llvm::StringMap<llvm::Constant*> ObjCStrings;
- /// All of the protocols that have been declared.
- llvm::StringMap<llvm::Constant*> ExistingProtocols;
- /// For each variant of a selector, we store the type encoding and a
- /// placeholder value. For an untyped selector, the type will be the empty
- /// string. Selector references are all done via the module's selector table,
- /// so we create an alias as a placeholder and then replace it with the real
- /// value later.
- typedef std::pair<std::string, llvm::GlobalAlias*> TypedSelector;
- /// Type of the selector map. This is roughly equivalent to the structure
- /// used in the GNUstep runtime, which maintains a list of all of the valid
- /// types for a selector in a table.
- typedef llvm::DenseMap<Selector, SmallVector<TypedSelector, 2> >
- SelectorMap;
- /// A map from selectors to selector types. This allows us to emit all
- /// selectors of the same name and type together.
- SelectorMap SelectorTable;
-
- /// Selectors related to memory management. When compiling in GC mode, we
- /// omit these.
- Selector RetainSel, ReleaseSel, AutoreleaseSel;
- /// Runtime functions used for memory management in GC mode. Note that clang
- /// supports code generation for calling these functions, but neither GNU
- /// runtime actually supports this API properly yet.
- LazyRuntimeFunction IvarAssignFn, StrongCastAssignFn, MemMoveFn, WeakReadFn,
- WeakAssignFn, GlobalAssignFn;
-
- typedef std::pair<std::string, std::string> ClassAliasPair;
- /// All classes that have aliases set for them.
- std::vector<ClassAliasPair> ClassAliases;
-
-protected:
- /// Function used for throwing Objective-C exceptions.
- LazyRuntimeFunction ExceptionThrowFn;
- /// Function used for rethrowing exceptions, used at the end of \@finally or
- /// \@synchronize blocks.
- LazyRuntimeFunction ExceptionReThrowFn;
- /// Function called when entering a catch function. This is required for
- /// differentiating Objective-C exceptions and foreign exceptions.
- LazyRuntimeFunction EnterCatchFn;
- /// Function called when exiting from a catch block. Used to do exception
- /// cleanup.
- LazyRuntimeFunction ExitCatchFn;
- /// Function called when entering an \@synchronize block. Acquires the lock.
- LazyRuntimeFunction SyncEnterFn;
- /// Function called when exiting an \@synchronize block. Releases the lock.
- LazyRuntimeFunction SyncExitFn;
-
-private:
- /// Function called if fast enumeration detects that the collection is
- /// modified during the update.
- LazyRuntimeFunction EnumerationMutationFn;
- /// Function for implementing synthesized property getters that return an
- /// object.
- LazyRuntimeFunction GetPropertyFn;
- /// Function for implementing synthesized property setters that return an
- /// object.
- LazyRuntimeFunction SetPropertyFn;
- /// Function used for non-object declared property getters.
- LazyRuntimeFunction GetStructPropertyFn;
- /// Function used for non-object declared property setters.
- LazyRuntimeFunction SetStructPropertyFn;
-
-protected:
- /// The version of the runtime that this class targets. Must match the
- /// version in the runtime.
- int RuntimeVersion;
- /// The version of the protocol class. Used to differentiate between ObjC1
- /// and ObjC2 protocols. Objective-C 1 protocols can not contain optional
- /// components and can not contain declared properties. We always emit
- /// Objective-C 2 property structures, but we have to pretend that they're
- /// Objective-C 1 property structures when targeting the GCC runtime or it
- /// will abort.
- const int ProtocolVersion;
- /// The version of the class ABI. This value is used in the class structure
- /// and indicates how various fields should be interpreted.
- const int ClassABIVersion;
- /// Generates an instance variable list structure. This is a structure
- /// containing a size and an array of structures containing instance variable
- /// metadata. This is used purely for introspection in the fragile ABI. In
- /// the non-fragile ABI, it's used for instance variable fixup.
- virtual llvm::Constant *GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
- ArrayRef<llvm::Constant *> IvarTypes,
- ArrayRef<llvm::Constant *> IvarOffsets,
- ArrayRef<llvm::Constant *> IvarAlign,
- ArrayRef<Qualifiers::ObjCLifetime> IvarOwnership);
-
- /// Generates a method list structure. This is a structure containing a size
- /// and an array of structures containing method metadata.
- ///
- /// This structure is used by both classes and categories, and contains a next
- /// pointer allowing them to be chained together in a linked list.
- llvm::Constant *GenerateMethodList(StringRef ClassName,
- StringRef CategoryName,
- ArrayRef<const ObjCMethodDecl*> Methods,
- bool isClassMethodList);
-
- /// Emits an empty protocol. This is used for \@protocol() where no protocol
- /// is found. The runtime will (hopefully) fix up the pointer to refer to the
- /// real protocol.
- virtual llvm::Constant *GenerateEmptyProtocol(StringRef ProtocolName);
-
- /// Generates a list of property metadata structures. This follows the same
- /// pattern as method and instance variable metadata lists.
- llvm::Constant *GeneratePropertyList(const Decl *Container,
- const ObjCContainerDecl *OCD,
- bool isClassProperty=false,
- bool protocolOptionalProperties=false);
-
- /// Generates a list of referenced protocols. Classes, categories, and
- /// protocols all use this structure.
- llvm::Constant *GenerateProtocolList(ArrayRef<std::string> Protocols);
-
- /// To ensure that all protocols are seen by the runtime, we add a category on
- /// a class defined in the runtime, declaring no methods, but adopting the
- /// protocols. This is a horribly ugly hack, but it allows us to collect all
- /// of the protocols without changing the ABI.
- void GenerateProtocolHolderCategory();
-
- /// Generates a class structure.
- llvm::Constant *GenerateClassStructure(
- llvm::Constant *MetaClass,
- llvm::Constant *SuperClass,
- unsigned info,
- const char *Name,
- llvm::Constant *Version,
- llvm::Constant *InstanceSize,
- llvm::Constant *IVars,
- llvm::Constant *Methods,
- llvm::Constant *Protocols,
- llvm::Constant *IvarOffsets,
- llvm::Constant *Properties,
- llvm::Constant *StrongIvarBitmap,
- llvm::Constant *WeakIvarBitmap,
- bool isMeta=false);
-
- /// Generates a method list. This is used by protocols to define the required
- /// and optional methods.
- virtual llvm::Constant *GenerateProtocolMethodList(
- ArrayRef<const ObjCMethodDecl*> Methods);
- /// Emits optional and required method lists.
- template<class T>
- void EmitProtocolMethodList(T &&Methods, llvm::Constant *&Required,
- llvm::Constant *&Optional) {
- SmallVector<const ObjCMethodDecl*, 16> RequiredMethods;
- SmallVector<const ObjCMethodDecl*, 16> OptionalMethods;
- for (const auto *I : Methods)
- if (I->isOptional())
- OptionalMethods.push_back(I);
- else
- RequiredMethods.push_back(I);
- Required = GenerateProtocolMethodList(RequiredMethods);
- Optional = GenerateProtocolMethodList(OptionalMethods);
- }
-
- /// Returns a selector with the specified type encoding. An empty string is
- /// used to return an untyped selector (with the types field set to NULL).
- virtual llvm::Value *GetTypedSelector(CodeGenFunction &CGF, Selector Sel,
- const std::string &TypeEncoding);
-
- /// Returns the name of ivar offset variables. In the GNUstep v1 ABI, this
- /// contains the class and ivar names, in the v2 ABI this contains the type
- /// encoding as well.
- virtual std::string GetIVarOffsetVariableName(const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar) {
- const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
- + '.' + Ivar->getNameAsString();
- return Name;
- }
- /// Returns the variable used to store the offset of an instance variable.
- llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar);
- /// Emits a reference to a class. This allows the linker to object if there
- /// is no class of the matching name.
- void EmitClassRef(const std::string &className);
-
- /// Emits a pointer to the named class
- virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
- const std::string &Name, bool isWeak);
-
- /// Looks up the method for sending a message to the specified object. This
- /// mechanism differs between the GCC and GNU runtimes, so this method must be
- /// overridden in subclasses.
- virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
- llvm::Value *&Receiver,
- llvm::Value *cmd,
- llvm::MDNode *node,
- MessageSendInfo &MSI) = 0;
-
- /// Looks up the method for sending a message to a superclass. This
- /// mechanism differs between the GCC and GNU runtimes, so this method must
- /// be overridden in subclasses.
- virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
- Address ObjCSuper,
- llvm::Value *cmd,
- MessageSendInfo &MSI) = 0;
-
- /// Libobjc2 uses a bitfield representation where small(ish) bitfields are
- /// stored in a 64-bit value with the low bit set to 1 and the remaining 63
- /// bits set to their values, LSB first, while larger ones are stored in a
- /// structure of this / form:
- ///
- /// struct { int32_t length; int32_t values[length]; };
- ///
- /// The values in the array are stored in host-endian format, with the least
- /// significant bit being assumed to come first in the bitfield. Therefore,
- /// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] },
- /// while a bitfield / with the 63rd bit set will be 1<<64.
- llvm::Constant *MakeBitField(ArrayRef<bool> bits);
-
-public:
- CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
- unsigned protocolClassVersion, unsigned classABI=1);
-
- ConstantAddress GenerateConstantString(const StringLiteral *) override;
-
- RValue
- GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return,
- QualType ResultType, Selector Sel,
- llvm::Value *Receiver, const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method) override;
- RValue
- GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return,
- QualType ResultType, Selector Sel,
- const ObjCInterfaceDecl *Class,
- bool isCategoryImpl, llvm::Value *Receiver,
- bool IsClassMessage, const CallArgList &CallArgs,
- const ObjCMethodDecl *Method) override;
- llvm::Value *GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *OID) override;
- llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override;
- Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override;
- llvm::Value *GetSelector(CodeGenFunction &CGF,
- const ObjCMethodDecl *Method) override;
- virtual llvm::Constant *GetConstantSelector(Selector Sel,
- const std::string &TypeEncoding) {
- llvm_unreachable("Runtime unable to generate constant selector");
- }
- llvm::Constant *GetConstantSelector(const ObjCMethodDecl *M) {
- return GetConstantSelector(M->getSelector(),
- CGM.getContext().getObjCEncodingForMethodDecl(M));
- }
- llvm::Constant *GetEHType(QualType T) override;
-
- llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) override;
- void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
- void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
- void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override;
- llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD) override;
- void GenerateProtocol(const ObjCProtocolDecl *PD) override;
- llvm::Function *ModuleInitFunction() override;
- llvm::Constant *GetPropertyGetFunction() override;
- llvm::Constant *GetPropertySetFunction() override;
- llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy) override;
- llvm::Constant *GetSetStructFunction() override;
- llvm::Constant *GetGetStructFunction() override;
- llvm::Constant *GetCppAtomicObjectGetFunction() override;
- llvm::Constant *GetCppAtomicObjectSetFunction() override;
- llvm::Constant *EnumerationMutationFunction() override;
-
- void EmitTryStmt(CodeGenFunction &CGF,
- const ObjCAtTryStmt &S) override;
- void EmitSynchronizedStmt(CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S) override;
- void EmitThrowStmt(CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint=true) override;
- llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF,
- Address AddrWeakObj) override;
- void EmitObjCWeakAssign(CodeGenFunction &CGF,
- llvm::Value *src, Address dst) override;
- void EmitObjCGlobalAssign(CodeGenFunction &CGF,
- llvm::Value *src, Address dest,
- bool threadlocal=false) override;
- void EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src,
- Address dest, llvm::Value *ivarOffset) override;
- void EmitObjCStrongCastAssign(CodeGenFunction &CGF,
- llvm::Value *src, Address dest) override;
- void EmitGCMemmoveCollectable(CodeGenFunction &CGF, Address DestPtr,
- Address SrcPtr,
- llvm::Value *Size) override;
- LValue EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy,
- llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) override;
- llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) override;
- llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
- llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) override {
- return NULLPtr;
- }
- llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) override {
- return NULLPtr;
- }
-
- llvm::Constant *BuildByrefLayout(CodeGenModule &CGM, QualType T) override {
- return NULLPtr;
- }
-};
-
-/// Class representing the legacy GCC Objective-C ABI. This is the default when
-/// -fobjc-nonfragile-abi is not specified.
-///
-/// The GCC ABI target actually generates code that is approximately compatible
-/// with the new GNUstep runtime ABI, but refrains from using any features that
-/// would not work with the GCC runtime. For example, clang always generates
-/// the extended form of the class structure, and the extra fields are simply
-/// ignored by GCC libobjc.
-class CGObjCGCC : public CGObjCGNU {
- /// The GCC ABI message lookup function. Returns an IMP pointing to the
- /// method implementation for this message.
- LazyRuntimeFunction MsgLookupFn;
- /// The GCC ABI superclass message lookup function. Takes a pointer to a
- /// structure describing the receiver and the class, and a selector as
- /// arguments. Returns the IMP for the corresponding method.
- LazyRuntimeFunction MsgLookupSuperFn;
-
-protected:
- llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver,
- llvm::Value *cmd, llvm::MDNode *node,
- MessageSendInfo &MSI) override {
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *args[] = {
- EnforceType(Builder, Receiver, IdTy),
- EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
- imp->setMetadata(msgSendMDKind, node);
- return imp.getInstruction();
- }
-
- llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper,
- llvm::Value *cmd, MessageSendInfo &MSI) override {
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
- PtrToObjCSuperTy).getPointer(), cmd};
- return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
- }
-
-public:
- CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
- // IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy);
- // IMP objc_msg_lookup_super(struct objc_super*, SEL);
- MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy);
- }
-};
-
-/// Class used when targeting the new GNUstep runtime ABI.
-class CGObjCGNUstep : public CGObjCGNU {
- /// The slot lookup function. Returns a pointer to a cacheable structure
- /// that contains (among other things) the IMP.
- LazyRuntimeFunction SlotLookupFn;
- /// The GNUstep ABI superclass message lookup function. Takes a pointer to
- /// a structure describing the receiver and the class, and a selector as
- /// arguments. Returns the slot for the corresponding method. Superclass
- /// message lookup rarely changes, so this is a good caching opportunity.
- LazyRuntimeFunction SlotLookupSuperFn;
- /// Specialised function for setting atomic retain properties
- LazyRuntimeFunction SetPropertyAtomic;
- /// Specialised function for setting atomic copy properties
- LazyRuntimeFunction SetPropertyAtomicCopy;
- /// Specialised function for setting nonatomic retain properties
- LazyRuntimeFunction SetPropertyNonAtomic;
- /// Specialised function for setting nonatomic copy properties
- LazyRuntimeFunction SetPropertyNonAtomicCopy;
- /// Function to perform atomic copies of C++ objects with nontrivial copy
- /// constructors from Objective-C ivars.
- LazyRuntimeFunction CxxAtomicObjectGetFn;
- /// Function to perform atomic copies of C++ objects with nontrivial copy
- /// constructors to Objective-C ivars.
- LazyRuntimeFunction CxxAtomicObjectSetFn;
- /// Type of an slot structure pointer. This is returned by the various
- /// lookup functions.
- llvm::Type *SlotTy;
-
- public:
- llvm::Constant *GetEHType(QualType T) override;
-
- protected:
- llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver,
- llvm::Value *cmd, llvm::MDNode *node,
- MessageSendInfo &MSI) override {
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Function *LookupFn = SlotLookupFn;
-
- // Store the receiver on the stack so that we can reload it later
- Address ReceiverPtr =
- CGF.CreateTempAlloca(Receiver->getType(), CGF.getPointerAlign());
- Builder.CreateStore(Receiver, ReceiverPtr);
-
- llvm::Value *self;
-
- if (isa<ObjCMethodDecl>(CGF.CurCodeDecl)) {
- self = CGF.LoadObjCSelf();
- } else {
- self = llvm::ConstantPointerNull::get(IdTy);
- }
-
- // The lookup function is guaranteed not to capture the receiver pointer.
- LookupFn->addParamAttr(0, llvm::Attribute::NoCapture);
-
- llvm::Value *args[] = {
- EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy),
- EnforceType(Builder, cmd, SelectorTy),
- EnforceType(Builder, self, IdTy) };
- llvm::CallSite slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args);
- slot.setOnlyReadsMemory();
- slot->setMetadata(msgSendMDKind, node);
-
- // Load the imp from the slot
- llvm::Value *imp = Builder.CreateAlignedLoad(
- Builder.CreateStructGEP(nullptr, slot.getInstruction(), 4),
- CGF.getPointerAlign());
-
- // The lookup function may have changed the receiver, so make sure we use
- // the new one.
- Receiver = Builder.CreateLoad(ReceiverPtr, true);
- return imp;
- }
-
- llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper,
- llvm::Value *cmd,
- MessageSendInfo &MSI) override {
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *lookupArgs[] = {ObjCSuper.getPointer(), cmd};
-
- llvm::CallInst *slot =
- CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs);
- slot->setOnlyReadsMemory();
-
- return Builder.CreateAlignedLoad(Builder.CreateStructGEP(nullptr, slot, 4),
- CGF.getPointerAlign());
- }
-
- public:
- CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 9, 3, 1) {}
- CGObjCGNUstep(CodeGenModule &Mod, unsigned ABI, unsigned ProtocolABI,
- unsigned ClassABI) :
- CGObjCGNU(Mod, ABI, ProtocolABI, ClassABI) {
- const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
-
- llvm::StructType *SlotStructTy =
- llvm::StructType::get(PtrTy, PtrTy, PtrTy, IntTy, IMPTy);
- SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
- // Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
- SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy,
- SelectorTy, IdTy);
- // Slot_t objc_slot_lookup_super(struct objc_super*, SEL);
- SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
- PtrToObjCSuperTy, SelectorTy);
- // If we're in ObjC++ mode, then we want to make
- if (usesSEHExceptions) {
- llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
- // void objc_exception_rethrow(void)
- ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
- } else if (CGM.getLangOpts().CPlusPlus) {
- llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
- // void *__cxa_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
- // void __cxa_end_catch(void)
- ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy);
- // void _Unwind_Resume_or_Rethrow(void*)
- ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
- PtrTy);
- } else if (R.getVersion() >= VersionTuple(1, 7)) {
- llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
- // id objc_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy);
- // void objc_end_catch(void)
- ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy);
- // void _Unwind_Resume_or_Rethrow(void*)
- ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy);
- }
- llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
- SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
- SelectorTy, IdTy, PtrDiffTy);
- SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy);
- SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy);
- SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy",
- VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy);
- // void objc_setCppObjectAtomic(void *dest, const void *src, void
- // *helper);
- CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy);
- // void objc_getCppObjectAtomic(void *dest, const void *src, void
- // *helper);
- CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy);
- }
-
- llvm::Constant *GetCppAtomicObjectGetFunction() override {
- // The optimised functions were added in version 1.7 of the GNUstep
- // runtime.
- assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
- VersionTuple(1, 7));
- return CxxAtomicObjectGetFn;
- }
-
- llvm::Constant *GetCppAtomicObjectSetFunction() override {
- // The optimised functions were added in version 1.7 of the GNUstep
- // runtime.
- assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
- VersionTuple(1, 7));
- return CxxAtomicObjectSetFn;
- }
-
- llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy) override {
- // The optimised property functions omit the GC check, and so are not
- // safe to use in GC mode. The standard functions are fast in GC mode,
- // so there is less advantage in using them.
- assert ((CGM.getLangOpts().getGC() == LangOptions::NonGC));
- // The optimised functions were added in version 1.7 of the GNUstep
- // runtime.
- assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
- VersionTuple(1, 7));
-
- if (atomic) {
- if (copy) return SetPropertyAtomicCopy;
- return SetPropertyAtomic;
- }
-
- return copy ? SetPropertyNonAtomicCopy : SetPropertyNonAtomic;
- }
-};
-
-/// GNUstep Objective-C ABI version 2 implementation.
-/// This is the ABI that provides a clean break with the legacy GCC ABI and
-/// cleans up a number of things that were added to work around 1980s linkers.
-class CGObjCGNUstep2 : public CGObjCGNUstep {
- enum SectionKind
- {
- SelectorSection = 0,
- ClassSection,
- ClassReferenceSection,
- CategorySection,
- ProtocolSection,
- ProtocolReferenceSection,
- ClassAliasSection,
- ConstantStringSection
- };
- static const char *const SectionsBaseNames[8];
- template<SectionKind K>
- std::string sectionName() {
- std::string name(SectionsBaseNames[K]);
- if (CGM.getTriple().isOSBinFormatCOFF())
- name += "$m";
- return name;
- }
- /// The GCC ABI superclass message lookup function. Takes a pointer to a
- /// structure describing the receiver and the class, and a selector as
- /// arguments. Returns the IMP for the corresponding method.
- LazyRuntimeFunction MsgLookupSuperFn;
- /// A flag indicating if we've emitted at least one protocol.
- /// If we haven't, then we need to emit an empty protocol, to ensure that the
- /// __start__objc_protocols and __stop__objc_protocols sections exist.
- bool EmittedProtocol = false;
- /// A flag indicating if we've emitted at least one protocol reference.
- /// If we haven't, then we need to emit an empty protocol, to ensure that the
- /// __start__objc_protocol_refs and __stop__objc_protocol_refs sections
- /// exist.
- bool EmittedProtocolRef = false;
- /// A flag indicating if we've emitted at least one class.
- /// If we haven't, then we need to emit an empty protocol, to ensure that the
- /// __start__objc_classes and __stop__objc_classes sections / exist.
- bool EmittedClass = false;
- /// Generate the name of a symbol for a reference to a class. Accesses to
- /// classes should be indirected via this.
- std::string SymbolForClassRef(StringRef Name, bool isWeak) {
- if (isWeak)
- return (StringRef("._OBJC_WEAK_REF_CLASS_") + Name).str();
- else
- return (StringRef("._OBJC_REF_CLASS_") + Name).str();
- }
- /// Generate the name of a class symbol.
- std::string SymbolForClass(StringRef Name) {
- return (StringRef("._OBJC_CLASS_") + Name).str();
- }
- void CallRuntimeFunction(CGBuilderTy &B, StringRef FunctionName,
- ArrayRef<llvm::Value*> Args) {
- SmallVector<llvm::Type *,8> Types;
- for (auto *Arg : Args)
- Types.push_back(Arg->getType());
- llvm::FunctionType *FT = llvm::FunctionType::get(B.getVoidTy(), Types,
- false);
- llvm::Value *Fn = CGM.CreateRuntimeFunction(FT, FunctionName);
- B.CreateCall(Fn, Args);
- }
-
- ConstantAddress GenerateConstantString(const StringLiteral *SL) override {
-
- auto Str = SL->getString();
- CharUnits Align = CGM.getPointerAlign();
-
- // Look for an existing one
- llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str);
- if (old != ObjCStrings.end())
- return ConstantAddress(old->getValue(), Align);
-
- bool isNonASCII = SL->containsNonAscii();
-
- auto LiteralLength = SL->getLength();
-
- if ((CGM.getTarget().getPointerWidth(0) == 64) &&
- (LiteralLength < 9) && !isNonASCII) {
- // Tiny strings are only used on 64-bit platforms. They store 8 7-bit
- // ASCII characters in the high 56 bits, followed by a 4-bit length and a
- // 3-bit tag (which is always 4).
- uint64_t str = 0;
- // Fill in the characters
- for (unsigned i=0 ; i<LiteralLength ; i++)
- str |= ((uint64_t)SL->getCodeUnit(i)) << ((64 - 4 - 3) - (i*7));
- // Fill in the length
- str |= LiteralLength << 3;
- // Set the tag
- str |= 4;
- auto *ObjCStr = llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(Int64Ty, str), IdTy);
- ObjCStrings[Str] = ObjCStr;
- return ConstantAddress(ObjCStr, Align);
- }
-
- StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass;
-
- if (StringClass.empty()) StringClass = "NSConstantString";
-
- std::string Sym = SymbolForClass(StringClass);
-
- llvm::Constant *isa = TheModule.getNamedGlobal(Sym);
-
- if (!isa)
- isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false,
- llvm::GlobalValue::ExternalLinkage, nullptr, Sym);
- else if (isa->getType() != PtrToIdTy)
- isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy);
-
- // struct
- // {
- // Class isa;
- // uint32_t flags;
- // uint32_t length; // Number of codepoints
- // uint32_t size; // Number of bytes
- // uint32_t hash;
- // const char *data;
- // };
-
- ConstantInitBuilder Builder(CGM);
- auto Fields = Builder.beginStruct();
- Fields.add(isa);
- // For now, all non-ASCII strings are represented as UTF-16. As such, the
- // number of bytes is simply double the number of UTF-16 codepoints. In
- // ASCII strings, the number of bytes is equal to the number of non-ASCII
- // codepoints.
- if (isNonASCII) {
- unsigned NumU8CodeUnits = Str.size();
- // A UTF-16 representation of a unicode string contains at most the same
- // number of code units as a UTF-8 representation. Allocate that much
- // space, plus one for the final null character.
- SmallVector<llvm::UTF16, 128> ToBuf(NumU8CodeUnits + 1);
- const llvm::UTF8 *FromPtr = (const llvm::UTF8 *)Str.data();
- llvm::UTF16 *ToPtr = &ToBuf[0];
- (void)llvm::ConvertUTF8toUTF16(&FromPtr, FromPtr + NumU8CodeUnits,
- &ToPtr, ToPtr + NumU8CodeUnits, llvm::strictConversion);
- uint32_t StringLength = ToPtr - &ToBuf[0];
- // Add null terminator
- *ToPtr = 0;
- // Flags: 2 indicates UTF-16 encoding
- Fields.addInt(Int32Ty, 2);
- // Number of UTF-16 codepoints
- Fields.addInt(Int32Ty, StringLength);
- // Number of bytes
- Fields.addInt(Int32Ty, StringLength * 2);
- // Hash. Not currently initialised by the compiler.
- Fields.addInt(Int32Ty, 0);
- // pointer to the data string.
- auto Arr = llvm::makeArrayRef(&ToBuf[0], ToPtr+1);
- auto *C = llvm::ConstantDataArray::get(VMContext, Arr);
- auto *Buffer = new llvm::GlobalVariable(TheModule, C->getType(),
- /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, C, ".str");
- Buffer->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- Fields.add(Buffer);
- } else {
- // Flags: 0 indicates ASCII encoding
- Fields.addInt(Int32Ty, 0);
- // Number of UTF-16 codepoints, each ASCII byte is a UTF-16 codepoint
- Fields.addInt(Int32Ty, Str.size());
- // Number of bytes
- Fields.addInt(Int32Ty, Str.size());
- // Hash. Not currently initialised by the compiler.
- Fields.addInt(Int32Ty, 0);
- // Data pointer
- Fields.add(MakeConstantString(Str));
- }
- std::string StringName;
- bool isNamed = !isNonASCII;
- if (isNamed) {
- StringName = ".objc_str_";
- for (int i=0,e=Str.size() ; i<e ; ++i) {
- unsigned char c = Str[i];
- if (isalnum(c))
- StringName += c;
- else if (c == ' ')
- StringName += '_';
- else {
- isNamed = false;
- break;
- }
- }
- }
- auto *ObjCStrGV =
- Fields.finishAndCreateGlobal(
- isNamed ? StringRef(StringName) : ".objc_string",
- Align, false, isNamed ? llvm::GlobalValue::LinkOnceODRLinkage
- : llvm::GlobalValue::PrivateLinkage);
- ObjCStrGV->setSection(sectionName<ConstantStringSection>());
- if (isNamed) {
- ObjCStrGV->setComdat(TheModule.getOrInsertComdat(StringName));
- ObjCStrGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- }
- llvm::Constant *ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStrGV, IdTy);
- ObjCStrings[Str] = ObjCStr;
- ConstantStrings.push_back(ObjCStr);
- return ConstantAddress(ObjCStr, Align);
- }
-
- void PushProperty(ConstantArrayBuilder &PropertiesArray,
- const ObjCPropertyDecl *property,
- const Decl *OCD,
- bool isSynthesized=true, bool
- isDynamic=true) override {
- // struct objc_property
- // {
- // const char *name;
- // const char *attributes;
- // const char *type;
- // SEL getter;
- // SEL setter;
- // };
- auto Fields = PropertiesArray.beginStruct(PropertyMetadataTy);
- ASTContext &Context = CGM.getContext();
- Fields.add(MakeConstantString(property->getNameAsString()));
- std::string TypeStr =
- CGM.getContext().getObjCEncodingForPropertyDecl(property, OCD);
- Fields.add(MakeConstantString(TypeStr));
- std::string typeStr;
- Context.getObjCEncodingForType(property->getType(), typeStr);
- Fields.add(MakeConstantString(typeStr));
- auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
- if (accessor) {
- std::string TypeStr = Context.getObjCEncodingForMethodDecl(accessor);
- Fields.add(GetConstantSelector(accessor->getSelector(), TypeStr));
- } else {
- Fields.add(NULLPtr);
- }
- };
- addPropertyMethod(property->getGetterMethodDecl());
- addPropertyMethod(property->getSetterMethodDecl());
- Fields.finishAndAddTo(PropertiesArray);
- }
-
- llvm::Constant *
- GenerateProtocolMethodList(ArrayRef<const ObjCMethodDecl*> Methods) override {
- // struct objc_protocol_method_description
- // {
- // SEL selector;
- // const char *types;
- // };
- llvm::StructType *ObjCMethodDescTy =
- llvm::StructType::get(CGM.getLLVMContext(),
- { PtrToInt8Ty, PtrToInt8Ty });
- ASTContext &Context = CGM.getContext();
- ConstantInitBuilder Builder(CGM);
- // struct objc_protocol_method_description_list
- // {
- // int count;
- // int size;
- // struct objc_protocol_method_description methods[];
- // };
- auto MethodList = Builder.beginStruct();
- // int count;
- MethodList.addInt(IntTy, Methods.size());
- // int size; // sizeof(struct objc_method_description)
- llvm::DataLayout td(&TheModule);
- MethodList.addInt(IntTy, td.getTypeSizeInBits(ObjCMethodDescTy) /
- CGM.getContext().getCharWidth());
- // struct objc_method_description[]
- auto MethodArray = MethodList.beginArray(ObjCMethodDescTy);
- for (auto *M : Methods) {
- auto Method = MethodArray.beginStruct(ObjCMethodDescTy);
- Method.add(CGObjCGNU::GetConstantSelector(M));
- Method.add(GetTypeString(Context.getObjCEncodingForMethodDecl(M, true)));
- Method.finishAndAddTo(MethodArray);
- }
- MethodArray.finishAndAddTo(MethodList);
- return MethodList.finishAndCreateGlobal(".objc_protocol_method_list",
- CGM.getPointerAlign());
- }
- llvm::Constant *GenerateCategoryProtocolList(const ObjCCategoryDecl *OCD)
- override {
- SmallVector<llvm::Constant*, 16> Protocols;
- for (const auto *PI : OCD->getReferencedProtocols())
- Protocols.push_back(
- llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI),
- ProtocolPtrTy));
- return GenerateProtocolList(Protocols);
- }
-
- llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper,
- llvm::Value *cmd, MessageSendInfo &MSI) override {
- // Don't access the slot unless we're trying to cache the result.
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *lookupArgs[] = {CGObjCGNU::EnforceType(Builder, ObjCSuper,
- PtrToObjCSuperTy).getPointer(), cmd};
- return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
- }
-
- llvm::GlobalVariable *GetClassVar(StringRef Name, bool isWeak=false) {
- std::string SymbolName = SymbolForClassRef(Name, isWeak);
- auto *ClassSymbol = TheModule.getNamedGlobal(SymbolName);
- if (ClassSymbol)
- return ClassSymbol;
- ClassSymbol = new llvm::GlobalVariable(TheModule,
- IdTy, false, llvm::GlobalValue::ExternalLinkage,
- nullptr, SymbolName);
- // If this is a weak symbol, then we are creating a valid definition for
- // the symbol, pointing to a weak definition of the real class pointer. If
- // this is not a weak reference, then we are expecting another compilation
- // unit to provide the real indirection symbol.
- if (isWeak)
- ClassSymbol->setInitializer(new llvm::GlobalVariable(TheModule,
- Int8Ty, false, llvm::GlobalValue::ExternalWeakLinkage,
- nullptr, SymbolForClass(Name)));
- assert(ClassSymbol->getName() == SymbolName);
- return ClassSymbol;
- }
- llvm::Value *GetClassNamed(CodeGenFunction &CGF,
- const std::string &Name,
- bool isWeak) override {
- return CGF.Builder.CreateLoad(Address(GetClassVar(Name, isWeak),
- CGM.getPointerAlign()));
- }
- int32_t FlagsForOwnership(Qualifiers::ObjCLifetime Ownership) {
- // typedef enum {
- // ownership_invalid = 0,
- // ownership_strong = 1,
- // ownership_weak = 2,
- // ownership_unsafe = 3
- // } ivar_ownership;
- int Flag;
- switch (Ownership) {
- case Qualifiers::OCL_Strong:
- Flag = 1;
- break;
- case Qualifiers::OCL_Weak:
- Flag = 2;
- break;
- case Qualifiers::OCL_ExplicitNone:
- Flag = 3;
- break;
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_Autoreleasing:
- assert(Ownership != Qualifiers::OCL_Autoreleasing);
- Flag = 0;
- }
- return Flag;
- }
- llvm::Constant *GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
- ArrayRef<llvm::Constant *> IvarTypes,
- ArrayRef<llvm::Constant *> IvarOffsets,
- ArrayRef<llvm::Constant *> IvarAlign,
- ArrayRef<Qualifiers::ObjCLifetime> IvarOwnership) override {
- llvm_unreachable("Method should not be called!");
- }
-
- llvm::Constant *GenerateEmptyProtocol(StringRef ProtocolName) override {
- std::string Name = SymbolForProtocol(ProtocolName);
- auto *GV = TheModule.getGlobalVariable(Name);
- if (!GV) {
- // Emit a placeholder symbol.
- GV = new llvm::GlobalVariable(TheModule, ProtocolTy, false,
- llvm::GlobalValue::ExternalLinkage, nullptr, Name);
- GV->setAlignment(CGM.getPointerAlign().getQuantity());
- }
- return llvm::ConstantExpr::getBitCast(GV, ProtocolPtrTy);
- }
-
- /// Existing protocol references.
- llvm::StringMap<llvm::Constant*> ExistingProtocolRefs;
-
- llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD) override {
- auto Name = PD->getNameAsString();
- auto *&Ref = ExistingProtocolRefs[Name];
- if (!Ref) {
- auto *&Protocol = ExistingProtocols[Name];
- if (!Protocol)
- Protocol = GenerateProtocolRef(PD);
- std::string RefName = SymbolForProtocolRef(Name);
- assert(!TheModule.getGlobalVariable(RefName));
- // Emit a reference symbol.
- auto GV = new llvm::GlobalVariable(TheModule, ProtocolPtrTy,
- false, llvm::GlobalValue::LinkOnceODRLinkage,
- llvm::ConstantExpr::getBitCast(Protocol, ProtocolPtrTy), RefName);
- GV->setComdat(TheModule.getOrInsertComdat(RefName));
- GV->setSection(sectionName<ProtocolReferenceSection>());
- GV->setAlignment(CGM.getPointerAlign().getQuantity());
- Ref = GV;
- }
- EmittedProtocolRef = true;
- return CGF.Builder.CreateAlignedLoad(Ref, CGM.getPointerAlign());
- }
-
- llvm::Constant *GenerateProtocolList(ArrayRef<llvm::Constant*> Protocols) {
- llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(ProtocolPtrTy,
- Protocols.size());
- llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
- Protocols);
- ConstantInitBuilder builder(CGM);
- auto ProtocolBuilder = builder.beginStruct();
- ProtocolBuilder.addNullPointer(PtrTy);
- ProtocolBuilder.addInt(SizeTy, Protocols.size());
- ProtocolBuilder.add(ProtocolArray);
- return ProtocolBuilder.finishAndCreateGlobal(".objc_protocol_list",
- CGM.getPointerAlign(), false, llvm::GlobalValue::InternalLinkage);
- }
-
- void GenerateProtocol(const ObjCProtocolDecl *PD) override {
- // Do nothing - we only emit referenced protocols.
- }
- llvm::Constant *GenerateProtocolRef(const ObjCProtocolDecl *PD) {
- std::string ProtocolName = PD->getNameAsString();
- auto *&Protocol = ExistingProtocols[ProtocolName];
- if (Protocol)
- return Protocol;
-
- EmittedProtocol = true;
-
- auto SymName = SymbolForProtocol(ProtocolName);
- auto *OldGV = TheModule.getGlobalVariable(SymName);
-
- // Use the protocol definition, if there is one.
- if (const ObjCProtocolDecl *Def = PD->getDefinition())
- PD = Def;
- else {
- // If there is no definition, then create an external linkage symbol and
- // hope that someone else fills it in for us (and fail to link if they
- // don't).
- assert(!OldGV);
- Protocol = new llvm::GlobalVariable(TheModule, ProtocolTy,
- /*isConstant*/false,
- llvm::GlobalValue::ExternalLinkage, nullptr, SymName);
- return Protocol;
- }
-
- SmallVector<llvm::Constant*, 16> Protocols;
- for (const auto *PI : PD->protocols())
- Protocols.push_back(
- llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI),
- ProtocolPtrTy));
- llvm::Constant *ProtocolList = GenerateProtocolList(Protocols);
-
- // Collect information about methods
- llvm::Constant *InstanceMethodList, *OptionalInstanceMethodList;
- llvm::Constant *ClassMethodList, *OptionalClassMethodList;
- EmitProtocolMethodList(PD->instance_methods(), InstanceMethodList,
- OptionalInstanceMethodList);
- EmitProtocolMethodList(PD->class_methods(), ClassMethodList,
- OptionalClassMethodList);
-
- // The isa pointer must be set to a magic number so the runtime knows it's
- // the correct layout.
- ConstantInitBuilder builder(CGM);
- auto ProtocolBuilder = builder.beginStruct();
- ProtocolBuilder.add(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
- ProtocolBuilder.add(MakeConstantString(ProtocolName));
- ProtocolBuilder.add(ProtocolList);
- ProtocolBuilder.add(InstanceMethodList);
- ProtocolBuilder.add(ClassMethodList);
- ProtocolBuilder.add(OptionalInstanceMethodList);
- ProtocolBuilder.add(OptionalClassMethodList);
- // Required instance properties
- ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, false, false));
- // Optional instance properties
- ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, false, true));
- // Required class properties
- ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, true, false));
- // Optional class properties
- ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, true, true));
-
- auto *GV = ProtocolBuilder.finishAndCreateGlobal(SymName,
- CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage);
- GV->setSection(sectionName<ProtocolSection>());
- GV->setComdat(TheModule.getOrInsertComdat(SymName));
- if (OldGV) {
- OldGV->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GV,
- OldGV->getType()));
- OldGV->removeFromParent();
- GV->setName(SymName);
- }
- Protocol = GV;
- return GV;
- }
- llvm::Constant *EnforceType(llvm::Constant *Val, llvm::Type *Ty) {
- if (Val->getType() == Ty)
- return Val;
- return llvm::ConstantExpr::getBitCast(Val, Ty);
- }
- llvm::Value *GetTypedSelector(CodeGenFunction &CGF, Selector Sel,
- const std::string &TypeEncoding) override {
- return GetConstantSelector(Sel, TypeEncoding);
- }
- llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) {
- if (TypeEncoding.empty())
- return NULLPtr;
- std::string MangledTypes = TypeEncoding;
- std::replace(MangledTypes.begin(), MangledTypes.end(),
- '@', '\1');
- std::string TypesVarName = ".objc_sel_types_" + MangledTypes;
- auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName);
- if (!TypesGlobal) {
- llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext,
- TypeEncoding);
- auto *GV = new llvm::GlobalVariable(TheModule, Init->getType(),
- true, llvm::GlobalValue::LinkOnceODRLinkage, Init, TypesVarName);
- GV->setComdat(TheModule.getOrInsertComdat(TypesVarName));
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- TypesGlobal = GV;
- }
- return llvm::ConstantExpr::getGetElementPtr(TypesGlobal->getValueType(),
- TypesGlobal, Zeros);
- }
- llvm::Constant *GetConstantSelector(Selector Sel,
- const std::string &TypeEncoding) override {
- // @ is used as a special character in symbol names (used for symbol
- // versioning), so mangle the name to not include it. Replace it with a
- // character that is not a valid type encoding character (and, being
- // non-printable, never will be!)
- std::string MangledTypes = TypeEncoding;
- std::replace(MangledTypes.begin(), MangledTypes.end(),
- '@', '\1');
- auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" +
- MangledTypes).str();
- if (auto *GV = TheModule.getNamedGlobal(SelVarName))
- return EnforceType(GV, SelectorTy);
- ConstantInitBuilder builder(CGM);
- auto SelBuilder = builder.beginStruct();
- SelBuilder.add(ExportUniqueString(Sel.getAsString(), ".objc_sel_name_",
- true));
- SelBuilder.add(GetTypeString(TypeEncoding));
- auto *GV = SelBuilder.finishAndCreateGlobal(SelVarName,
- CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage);
- GV->setComdat(TheModule.getOrInsertComdat(SelVarName));
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- GV->setSection(sectionName<SelectorSection>());
- auto *SelVal = EnforceType(GV, SelectorTy);
- return SelVal;
- }
- llvm::StructType *emptyStruct = nullptr;
-
- /// Return pointers to the start and end of a section. On ELF platforms, we
- /// use the __start_ and __stop_ symbols that GNU-compatible linkers will set
- /// to the start and end of section names, as long as those section names are
- /// valid identifiers and the symbols are referenced but not defined. On
- /// Windows, we use the fact that MSVC-compatible linkers will lexically sort
- /// by subsections and place everything that we want to reference in a middle
- /// subsection and then insert zero-sized symbols in subsections a and z.
- std::pair<llvm::Constant*,llvm::Constant*>
- GetSectionBounds(StringRef Section) {
- if (CGM.getTriple().isOSBinFormatCOFF()) {
- if (emptyStruct == nullptr) {
- emptyStruct = llvm::StructType::create(VMContext, ".objc_section_sentinel");
- emptyStruct->setBody({}, /*isPacked*/true);
- }
- auto ZeroInit = llvm::Constant::getNullValue(emptyStruct);
- auto Sym = [&](StringRef Prefix, StringRef SecSuffix) {
- auto *Sym = new llvm::GlobalVariable(TheModule, emptyStruct,
- /*isConstant*/false,
- llvm::GlobalValue::LinkOnceODRLinkage, ZeroInit, Prefix +
- Section);
- Sym->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Sym->setSection((Section + SecSuffix).str());
- Sym->setComdat(TheModule.getOrInsertComdat((Prefix +
- Section).str()));
- Sym->setAlignment(1);
- return Sym;
- };
- return { Sym("__start_", "$a"), Sym("__stop", "$z") };
- }
- auto *Start = new llvm::GlobalVariable(TheModule, PtrTy,
- /*isConstant*/false,
- llvm::GlobalValue::ExternalLinkage, nullptr, StringRef("__start_") +
- Section);
- Start->setVisibility(llvm::GlobalValue::HiddenVisibility);
- auto *Stop = new llvm::GlobalVariable(TheModule, PtrTy,
- /*isConstant*/false,
- llvm::GlobalValue::ExternalLinkage, nullptr, StringRef("__stop_") +
- Section);
- Stop->setVisibility(llvm::GlobalValue::HiddenVisibility);
- return { Start, Stop };
- }
- CatchTypeInfo getCatchAllTypeInfo() override {
- return CGM.getCXXABI().getCatchAllTypeInfo();
- }
- llvm::Function *ModuleInitFunction() override {
- llvm::Function *LoadFunction = llvm::Function::Create(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false),
- llvm::GlobalValue::LinkOnceODRLinkage, ".objcv2_load_function",
- &TheModule);
- LoadFunction->setVisibility(llvm::GlobalValue::HiddenVisibility);
- LoadFunction->setComdat(TheModule.getOrInsertComdat(".objcv2_load_function"));
-
- llvm::BasicBlock *EntryBB =
- llvm::BasicBlock::Create(VMContext, "entry", LoadFunction);
- CGBuilderTy B(CGM, VMContext);
- B.SetInsertPoint(EntryBB);
- ConstantInitBuilder builder(CGM);
- auto InitStructBuilder = builder.beginStruct();
- InitStructBuilder.addInt(Int64Ty, 0);
- for (auto *s : SectionsBaseNames) {
- auto bounds = GetSectionBounds(s);
- InitStructBuilder.add(bounds.first);
- InitStructBuilder.add(bounds.second);
- };
- auto *InitStruct = InitStructBuilder.finishAndCreateGlobal(".objc_init",
- CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage);
- InitStruct->setVisibility(llvm::GlobalValue::HiddenVisibility);
- InitStruct->setComdat(TheModule.getOrInsertComdat(".objc_init"));
-
- CallRuntimeFunction(B, "__objc_load", {InitStruct});;
- B.CreateRetVoid();
- // Make sure that the optimisers don't delete this function.
- CGM.addCompilerUsedGlobal(LoadFunction);
- // FIXME: Currently ELF only!
- // We have to do this by hand, rather than with @llvm.ctors, so that the
- // linker can remove the duplicate invocations.
- auto *InitVar = new llvm::GlobalVariable(TheModule, LoadFunction->getType(),
- /*isConstant*/true, llvm::GlobalValue::LinkOnceAnyLinkage,
- LoadFunction, ".objc_ctor");
- // Check that this hasn't been renamed. This shouldn't happen, because
- // this function should be called precisely once.
- assert(InitVar->getName() == ".objc_ctor");
- // In Windows, initialisers are sorted by the suffix. XCL is for library
- // initialisers, which run before user initialisers. We are running
- // Objective-C loads at the end of library load. This means +load methods
- // will run before any other static constructors, but that static
- // constructors can see a fully initialised Objective-C state.
- if (CGM.getTriple().isOSBinFormatCOFF())
- InitVar->setSection(".CRT$XCLz");
- else
- InitVar->setSection(".ctors");
- InitVar->setVisibility(llvm::GlobalValue::HiddenVisibility);
- InitVar->setComdat(TheModule.getOrInsertComdat(".objc_ctor"));
- CGM.addUsedGlobal(InitVar);
- for (auto *C : Categories) {
- auto *Cat = cast<llvm::GlobalVariable>(C->stripPointerCasts());
- Cat->setSection(sectionName<CategorySection>());
- CGM.addUsedGlobal(Cat);
- }
- auto createNullGlobal = [&](StringRef Name, ArrayRef<llvm::Constant*> Init,
- StringRef Section) {
- auto nullBuilder = builder.beginStruct();
- for (auto *F : Init)
- nullBuilder.add(F);
- auto GV = nullBuilder.finishAndCreateGlobal(Name, CGM.getPointerAlign(),
- false, llvm::GlobalValue::LinkOnceODRLinkage);
- GV->setSection(Section);
- GV->setComdat(TheModule.getOrInsertComdat(Name));
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.addUsedGlobal(GV);
- return GV;
- };
- for (auto clsAlias : ClassAliases)
- createNullGlobal(std::string(".objc_class_alias") +
- clsAlias.second, { MakeConstantString(clsAlias.second),
- GetClassVar(clsAlias.first) }, sectionName<ClassAliasSection>());
- // On ELF platforms, add a null value for each special section so that we
- // can always guarantee that the _start and _stop symbols will exist and be
- // meaningful. This is not required on COFF platforms, where our start and
- // stop symbols will create the section.
- if (!CGM.getTriple().isOSBinFormatCOFF()) {
- createNullGlobal(".objc_null_selector", {NULLPtr, NULLPtr},
- sectionName<SelectorSection>());
- if (Categories.empty())
- createNullGlobal(".objc_null_category", {NULLPtr, NULLPtr,
- NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr},
- sectionName<CategorySection>());
- if (!EmittedClass) {
- createNullGlobal(".objc_null_cls_init_ref", NULLPtr,
- sectionName<ClassSection>());
- createNullGlobal(".objc_null_class_ref", { NULLPtr, NULLPtr },
- sectionName<ClassReferenceSection>());
- }
- if (!EmittedProtocol)
- createNullGlobal(".objc_null_protocol", {NULLPtr, NULLPtr, NULLPtr,
- NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr,
- NULLPtr}, sectionName<ProtocolSection>());
- if (!EmittedProtocolRef)
- createNullGlobal(".objc_null_protocol_ref", {NULLPtr},
- sectionName<ProtocolReferenceSection>());
- if (ClassAliases.empty())
- createNullGlobal(".objc_null_class_alias", { NULLPtr, NULLPtr },
- sectionName<ClassAliasSection>());
- if (ConstantStrings.empty()) {
- auto i32Zero = llvm::ConstantInt::get(Int32Ty, 0);
- createNullGlobal(".objc_null_constant_string", { NULLPtr, i32Zero,
- i32Zero, i32Zero, i32Zero, NULLPtr },
- sectionName<ConstantStringSection>());
- }
- }
- ConstantStrings.clear();
- Categories.clear();
- Classes.clear();
- return nullptr;
- }
- /// In the v2 ABI, ivar offset variables use the type encoding in their name
- /// to trigger linker failures if the types don't match.
- std::string GetIVarOffsetVariableName(const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar) override {
- std::string TypeEncoding;
- CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding);
- // Prevent the @ from being interpreted as a symbol version.
- std::replace(TypeEncoding.begin(), TypeEncoding.end(),
- '@', '\1');
- const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
- + '.' + Ivar->getNameAsString() + '.' + TypeEncoding;
- return Name;
- }
- llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) override {
- const std::string Name = GetIVarOffsetVariableName(Ivar->getContainingInterface(), Ivar);
- llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name);
- if (!IvarOffsetPointer)
- IvarOffsetPointer = new llvm::GlobalVariable(TheModule, IntTy, false,
- llvm::GlobalValue::ExternalLinkage, nullptr, Name);
- CharUnits Align = CGM.getIntAlign();
- llvm::Value *Offset = CGF.Builder.CreateAlignedLoad(IvarOffsetPointer, Align);
- if (Offset->getType() != PtrDiffTy)
- Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy);
- return Offset;
- }
- void GenerateClass(const ObjCImplementationDecl *OID) override {
- ASTContext &Context = CGM.getContext();
-
- // Get the class name
- ObjCInterfaceDecl *classDecl =
- const_cast<ObjCInterfaceDecl *>(OID->getClassInterface());
- std::string className = classDecl->getNameAsString();
- auto *classNameConstant = MakeConstantString(className);
-
- ConstantInitBuilder builder(CGM);
- auto metaclassFields = builder.beginStruct();
- // struct objc_class *isa;
- metaclassFields.addNullPointer(PtrTy);
- // struct objc_class *super_class;
- metaclassFields.addNullPointer(PtrTy);
- // const char *name;
- metaclassFields.add(classNameConstant);
- // long version;
- metaclassFields.addInt(LongTy, 0);
- // unsigned long info;
- // objc_class_flag_meta
- metaclassFields.addInt(LongTy, 1);
- // long instance_size;
- // Setting this to zero is consistent with the older ABI, but it might be
- // more sensible to set this to sizeof(struct objc_class)
- metaclassFields.addInt(LongTy, 0);
- // struct objc_ivar_list *ivars;
- metaclassFields.addNullPointer(PtrTy);
- // struct objc_method_list *methods
- // FIXME: Almost identical code is copied and pasted below for the
- // class, but refactoring it cleanly requires C++14 generic lambdas.
- if (OID->classmeth_begin() == OID->classmeth_end())
- metaclassFields.addNullPointer(PtrTy);
- else {
- SmallVector<ObjCMethodDecl*, 16> ClassMethods;
- ClassMethods.insert(ClassMethods.begin(), OID->classmeth_begin(),
- OID->classmeth_end());
- metaclassFields.addBitCast(
- GenerateMethodList(className, "", ClassMethods, true),
- PtrTy);
- }
- // void *dtable;
- metaclassFields.addNullPointer(PtrTy);
- // IMP cxx_construct;
- metaclassFields.addNullPointer(PtrTy);
- // IMP cxx_destruct;
- metaclassFields.addNullPointer(PtrTy);
- // struct objc_class *subclass_list
- metaclassFields.addNullPointer(PtrTy);
- // struct objc_class *sibling_class
- metaclassFields.addNullPointer(PtrTy);
- // struct objc_protocol_list *protocols;
- metaclassFields.addNullPointer(PtrTy);
- // struct reference_list *extra_data;
- metaclassFields.addNullPointer(PtrTy);
- // long abi_version;
- metaclassFields.addInt(LongTy, 0);
- // struct objc_property_list *properties
- metaclassFields.add(GeneratePropertyList(OID, classDecl, /*isClassProperty*/true));
-
- auto *metaclass = metaclassFields.finishAndCreateGlobal("._OBJC_METACLASS_"
- + className, CGM.getPointerAlign());
-
- auto classFields = builder.beginStruct();
- // struct objc_class *isa;
- classFields.add(metaclass);
- // struct objc_class *super_class;
- // Get the superclass name.
- const ObjCInterfaceDecl * SuperClassDecl =
- OID->getClassInterface()->getSuperClass();
- if (SuperClassDecl) {
- auto SuperClassName = SymbolForClass(SuperClassDecl->getNameAsString());
- llvm::Constant *SuperClass = TheModule.getNamedGlobal(SuperClassName);
- if (!SuperClass)
- {
- SuperClass = new llvm::GlobalVariable(TheModule, PtrTy, false,
- llvm::GlobalValue::ExternalLinkage, nullptr, SuperClassName);
- }
- classFields.add(llvm::ConstantExpr::getBitCast(SuperClass, PtrTy));
- } else
- classFields.addNullPointer(PtrTy);
- // const char *name;
- classFields.add(classNameConstant);
- // long version;
- classFields.addInt(LongTy, 0);
- // unsigned long info;
- // !objc_class_flag_meta
- classFields.addInt(LongTy, 0);
- // long instance_size;
- int superInstanceSize = !SuperClassDecl ? 0 :
- Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity();
- // Instance size is negative for classes that have not yet had their ivar
- // layout calculated.
- classFields.addInt(LongTy,
- 0 - (Context.getASTObjCImplementationLayout(OID).getSize().getQuantity() -
- superInstanceSize));
-
- if (classDecl->all_declared_ivar_begin() == nullptr)
- classFields.addNullPointer(PtrTy);
- else {
- int ivar_count = 0;
- for (const ObjCIvarDecl *IVD = classDecl->all_declared_ivar_begin(); IVD;
- IVD = IVD->getNextIvar()) ivar_count++;
- llvm::DataLayout td(&TheModule);
- // struct objc_ivar_list *ivars;
- ConstantInitBuilder b(CGM);
- auto ivarListBuilder = b.beginStruct();
- // int count;
- ivarListBuilder.addInt(IntTy, ivar_count);
- // size_t size;
- llvm::StructType *ObjCIvarTy = llvm::StructType::get(
- PtrToInt8Ty,
- PtrToInt8Ty,
- PtrToInt8Ty,
- Int32Ty,
- Int32Ty);
- ivarListBuilder.addInt(SizeTy, td.getTypeSizeInBits(ObjCIvarTy) /
- CGM.getContext().getCharWidth());
- // struct objc_ivar ivars[]
- auto ivarArrayBuilder = ivarListBuilder.beginArray();
- CodeGenTypes &Types = CGM.getTypes();
- for (const ObjCIvarDecl *IVD = classDecl->all_declared_ivar_begin(); IVD;
- IVD = IVD->getNextIvar()) {
- auto ivarTy = IVD->getType();
- auto ivarBuilder = ivarArrayBuilder.beginStruct();
- // const char *name;
- ivarBuilder.add(MakeConstantString(IVD->getNameAsString()));
- // const char *type;
- std::string TypeStr;
- //Context.getObjCEncodingForType(ivarTy, TypeStr, IVD, true);
- Context.getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, ivarTy, TypeStr, true);
- ivarBuilder.add(MakeConstantString(TypeStr));
- // int *offset;
- uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
- uint64_t Offset = BaseOffset - superInstanceSize;
- llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset);
- std::string OffsetName = GetIVarOffsetVariableName(classDecl, IVD);
- llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName);
- if (OffsetVar)
- OffsetVar->setInitializer(OffsetValue);
- else
- OffsetVar = new llvm::GlobalVariable(TheModule, IntTy,
- false, llvm::GlobalValue::ExternalLinkage,
- OffsetValue, OffsetName);
- auto ivarVisibility =
- (IVD->getAccessControl() == ObjCIvarDecl::Private ||
- IVD->getAccessControl() == ObjCIvarDecl::Package ||
- classDecl->getVisibility() == HiddenVisibility) ?
- llvm::GlobalValue::HiddenVisibility :
- llvm::GlobalValue::DefaultVisibility;
- OffsetVar->setVisibility(ivarVisibility);
- ivarBuilder.add(OffsetVar);
- // Ivar size
- ivarBuilder.addInt(Int32Ty,
- td.getTypeSizeInBits(Types.ConvertType(ivarTy)) /
- CGM.getContext().getCharWidth());
- // Alignment will be stored as a base-2 log of the alignment.
- int align = llvm::Log2_32(Context.getTypeAlignInChars(ivarTy).getQuantity());
- // Objects that require more than 2^64-byte alignment should be impossible!
- assert(align < 64);
- // uint32_t flags;
- // Bits 0-1 are ownership.
- // Bit 2 indicates an extended type encoding
- // Bits 3-8 contain log2(aligment)
- ivarBuilder.addInt(Int32Ty,
- (align << 3) | (1<<2) |
- FlagsForOwnership(ivarTy.getQualifiers().getObjCLifetime()));
- ivarBuilder.finishAndAddTo(ivarArrayBuilder);
- }
- ivarArrayBuilder.finishAndAddTo(ivarListBuilder);
- auto ivarList = ivarListBuilder.finishAndCreateGlobal(".objc_ivar_list",
- CGM.getPointerAlign(), /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- classFields.add(ivarList);
- }
- // struct objc_method_list *methods
- SmallVector<const ObjCMethodDecl*, 16> InstanceMethods;
- InstanceMethods.insert(InstanceMethods.begin(), OID->instmeth_begin(),
- OID->instmeth_end());
- for (auto *propImpl : OID->property_impls())
- if (propImpl->getPropertyImplementation() ==
- ObjCPropertyImplDecl::Synthesize) {
- ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
- auto addIfExists = [&](const ObjCMethodDecl* OMD) {
- if (OMD)
- InstanceMethods.push_back(OMD);
- };
- addIfExists(prop->getGetterMethodDecl());
- addIfExists(prop->getSetterMethodDecl());
- }
-
- if (InstanceMethods.size() == 0)
- classFields.addNullPointer(PtrTy);
- else
- classFields.addBitCast(
- GenerateMethodList(className, "", InstanceMethods, false),
- PtrTy);
- // void *dtable;
- classFields.addNullPointer(PtrTy);
- // IMP cxx_construct;
- classFields.addNullPointer(PtrTy);
- // IMP cxx_destruct;
- classFields.addNullPointer(PtrTy);
- // struct objc_class *subclass_list
- classFields.addNullPointer(PtrTy);
- // struct objc_class *sibling_class
- classFields.addNullPointer(PtrTy);
- // struct objc_protocol_list *protocols;
- SmallVector<llvm::Constant*, 16> Protocols;
- for (const auto *I : classDecl->protocols())
- Protocols.push_back(
- llvm::ConstantExpr::getBitCast(GenerateProtocolRef(I),
- ProtocolPtrTy));
- if (Protocols.empty())
- classFields.addNullPointer(PtrTy);
- else
- classFields.add(GenerateProtocolList(Protocols));
- // struct reference_list *extra_data;
- classFields.addNullPointer(PtrTy);
- // long abi_version;
- classFields.addInt(LongTy, 0);
- // struct objc_property_list *properties
- classFields.add(GeneratePropertyList(OID, classDecl));
-
- auto *classStruct =
- classFields.finishAndCreateGlobal(SymbolForClass(className),
- CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage);
-
- if (CGM.getTriple().isOSBinFormatCOFF()) {
- auto Storage = llvm::GlobalValue::DefaultStorageClass;
- if (OID->getClassInterface()->hasAttr<DLLImportAttr>())
- Storage = llvm::GlobalValue::DLLImportStorageClass;
- else if (OID->getClassInterface()->hasAttr<DLLExportAttr>())
- Storage = llvm::GlobalValue::DLLExportStorageClass;
- cast<llvm::GlobalValue>(classStruct)->setDLLStorageClass(Storage);
- }
-
- auto *classRefSymbol = GetClassVar(className);
- classRefSymbol->setSection(sectionName<ClassReferenceSection>());
- classRefSymbol->setInitializer(llvm::ConstantExpr::getBitCast(classStruct, IdTy));
-
-
- // Resolve the class aliases, if they exist.
- // FIXME: Class pointer aliases shouldn't exist!
- if (ClassPtrAlias) {
- ClassPtrAlias->replaceAllUsesWith(
- llvm::ConstantExpr::getBitCast(classStruct, IdTy));
- ClassPtrAlias->eraseFromParent();
- ClassPtrAlias = nullptr;
- }
- if (auto Placeholder =
- TheModule.getNamedGlobal(SymbolForClass(className)))
- if (Placeholder != classStruct) {
- Placeholder->replaceAllUsesWith(
- llvm::ConstantExpr::getBitCast(classStruct, Placeholder->getType()));
- Placeholder->eraseFromParent();
- classStruct->setName(SymbolForClass(className));
- }
- if (MetaClassPtrAlias) {
- MetaClassPtrAlias->replaceAllUsesWith(
- llvm::ConstantExpr::getBitCast(metaclass, IdTy));
- MetaClassPtrAlias->eraseFromParent();
- MetaClassPtrAlias = nullptr;
- }
- assert(classStruct->getName() == SymbolForClass(className));
-
- auto classInitRef = new llvm::GlobalVariable(TheModule,
- classStruct->getType(), false, llvm::GlobalValue::ExternalLinkage,
- classStruct, "._OBJC_INIT_CLASS_" + className);
- classInitRef->setSection(sectionName<ClassSection>());
- CGM.addUsedGlobal(classInitRef);
-
- EmittedClass = true;
- }
- public:
- CGObjCGNUstep2(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 10, 4, 2) {
- MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy);
- // struct objc_property
- // {
- // const char *name;
- // const char *attributes;
- // const char *type;
- // SEL getter;
- // SEL setter;
- // }
- PropertyMetadataTy =
- llvm::StructType::get(CGM.getLLVMContext(),
- { PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty });
- }
-
-};
-
-const char *const CGObjCGNUstep2::SectionsBaseNames[8] =
-{
-"__objc_selectors",
-"__objc_classes",
-"__objc_class_refs",
-"__objc_cats",
-"__objc_protocols",
-"__objc_protocol_refs",
-"__objc_class_aliases",
-"__objc_constant_string"
-};
-
-/// Support for the ObjFW runtime.
-class CGObjCObjFW: public CGObjCGNU {
-protected:
- /// The GCC ABI message lookup function. Returns an IMP pointing to the
- /// method implementation for this message.
- LazyRuntimeFunction MsgLookupFn;
- /// stret lookup function. While this does not seem to make sense at the
- /// first look, this is required to call the correct forwarding function.
- LazyRuntimeFunction MsgLookupFnSRet;
- /// The GCC ABI superclass message lookup function. Takes a pointer to a
- /// structure describing the receiver and the class, and a selector as
- /// arguments. Returns the IMP for the corresponding method.
- LazyRuntimeFunction MsgLookupSuperFn, MsgLookupSuperFnSRet;
-
- llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver,
- llvm::Value *cmd, llvm::MDNode *node,
- MessageSendInfo &MSI) override {
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *args[] = {
- EnforceType(Builder, Receiver, IdTy),
- EnforceType(Builder, cmd, SelectorTy) };
-
- llvm::CallSite imp;
- if (CGM.ReturnTypeUsesSRet(MSI.CallInfo))
- imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFnSRet, args);
- else
- imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
-
- imp->setMetadata(msgSendMDKind, node);
- return imp.getInstruction();
- }
-
- llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper,
- llvm::Value *cmd, MessageSendInfo &MSI) override {
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *lookupArgs[] = {
- EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd,
- };
-
- if (CGM.ReturnTypeUsesSRet(MSI.CallInfo))
- return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFnSRet, lookupArgs);
- else
- return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
- }
-
- llvm::Value *GetClassNamed(CodeGenFunction &CGF, const std::string &Name,
- bool isWeak) override {
- if (isWeak)
- return CGObjCGNU::GetClassNamed(CGF, Name, isWeak);
-
- EmitClassRef(Name);
- std::string SymbolName = "_OBJC_CLASS_" + Name;
- llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(SymbolName);
- if (!ClassSymbol)
- ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
- llvm::GlobalValue::ExternalLinkage,
- nullptr, SymbolName);
- return ClassSymbol;
- }
-
-public:
- CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
- // IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy);
- MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy,
- SelectorTy);
- // IMP objc_msg_lookup_super(struct objc_super*, SEL);
- MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy);
- MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy,
- PtrToObjCSuperTy, SelectorTy);
- }
-};
-} // end anonymous namespace
-
-/// Emits a reference to a dummy variable which is emitted with each class.
-/// This ensures that a linker error will be generated when trying to link
-/// together modules where a referenced class is not defined.
-void CGObjCGNU::EmitClassRef(const std::string &className) {
- std::string symbolRef = "__objc_class_ref_" + className;
- // Don't emit two copies of the same symbol
- if (TheModule.getGlobalVariable(symbolRef))
- return;
- std::string symbolName = "__objc_class_name_" + className;
- llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName);
- if (!ClassSymbol) {
- ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
- llvm::GlobalValue::ExternalLinkage,
- nullptr, symbolName);
- }
- new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true,
- llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
-}
-
-CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
- unsigned protocolClassVersion, unsigned classABI)
- : CGObjCRuntime(cgm), TheModule(CGM.getModule()),
- VMContext(cgm.getLLVMContext()), ClassPtrAlias(nullptr),
- MetaClassPtrAlias(nullptr), RuntimeVersion(runtimeABIVersion),
- ProtocolVersion(protocolClassVersion), ClassABIVersion(classABI) {
-
- msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
- usesSEHExceptions =
- cgm.getContext().getTargetInfo().getTriple().isWindowsMSVCEnvironment();
-
- CodeGenTypes &Types = CGM.getTypes();
- IntTy = cast<llvm::IntegerType>(
- Types.ConvertType(CGM.getContext().IntTy));
- LongTy = cast<llvm::IntegerType>(
- Types.ConvertType(CGM.getContext().LongTy));
- SizeTy = cast<llvm::IntegerType>(
- Types.ConvertType(CGM.getContext().getSizeType()));
- PtrDiffTy = cast<llvm::IntegerType>(
- Types.ConvertType(CGM.getContext().getPointerDiffType()));
- BoolTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
-
- Int8Ty = llvm::Type::getInt8Ty(VMContext);
- // C string type. Used in lots of places.
- PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
- ProtocolPtrTy = llvm::PointerType::getUnqual(
- Types.ConvertType(CGM.getContext().getObjCProtoType()));
-
- Zeros[0] = llvm::ConstantInt::get(LongTy, 0);
- Zeros[1] = Zeros[0];
- NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty);
- // Get the selector Type.
- QualType selTy = CGM.getContext().getObjCSelType();
- if (QualType() == selTy) {
- SelectorTy = PtrToInt8Ty;
- } else {
- SelectorTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(selTy));
- }
-
- PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
- PtrTy = PtrToInt8Ty;
-
- Int32Ty = llvm::Type::getInt32Ty(VMContext);
- Int64Ty = llvm::Type::getInt64Ty(VMContext);
-
- IntPtrTy =
- CGM.getDataLayout().getPointerSizeInBits() == 32 ? Int32Ty : Int64Ty;
-
- // Object type
- QualType UnqualIdTy = CGM.getContext().getObjCIdType();
- ASTIdTy = CanQualType();
- if (UnqualIdTy != QualType()) {
- ASTIdTy = CGM.getContext().getCanonicalType(UnqualIdTy);
- IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
- } else {
- IdTy = PtrToInt8Ty;
- }
- PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
- ProtocolTy = llvm::StructType::get(IdTy,
- PtrToInt8Ty, // name
- PtrToInt8Ty, // protocols
- PtrToInt8Ty, // instance methods
- PtrToInt8Ty, // class methods
- PtrToInt8Ty, // optional instance methods
- PtrToInt8Ty, // optional class methods
- PtrToInt8Ty, // properties
- PtrToInt8Ty);// optional properties
-
- // struct objc_property_gsv1
- // {
- // const char *name;
- // char attributes;
- // char attributes2;
- // char unused1;
- // char unused2;
- // const char *getter_name;
- // const char *getter_types;
- // const char *setter_name;
- // const char *setter_types;
- // }
- PropertyMetadataTy = llvm::StructType::get(CGM.getLLVMContext(), {
- PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty,
- PtrToInt8Ty, PtrToInt8Ty });
-
- ObjCSuperTy = llvm::StructType::get(IdTy, IdTy);
- PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy);
-
- llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
-
- // void objc_exception_throw(id);
- ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
- ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
- // int objc_sync_enter(id);
- SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy);
- // int objc_sync_exit(id);
- SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy);
-
- // void objc_enumerationMutation (id)
- EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy, IdTy);
-
- // id objc_getProperty(id, SEL, ptrdiff_t, BOOL)
- GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy,
- PtrDiffTy, BoolTy);
- // void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL)
- SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy,
- PtrDiffTy, IdTy, BoolTy, BoolTy);
- // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
- GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy);
- // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
- SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy);
-
- // IMP type
- llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
- IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs,
- true));
-
- const LangOptions &Opts = CGM.getLangOpts();
- if ((Opts.getGC() != LangOptions::NonGC) || Opts.ObjCAutoRefCount)
- RuntimeVersion = 10;
-
- // Don't bother initialising the GC stuff unless we're compiling in GC mode
- if (Opts.getGC() != LangOptions::NonGC) {
- // This is a bit of an hack. We should sort this out by having a proper
- // CGObjCGNUstep subclass for GC, but we may want to really support the old
- // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now
- // Get selectors needed in GC mode
- RetainSel = GetNullarySelector("retain", CGM.getContext());
- ReleaseSel = GetNullarySelector("release", CGM.getContext());
- AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext());
-
- // Get functions needed in GC mode
-
- // id objc_assign_ivar(id, id, ptrdiff_t);
- IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy);
- // id objc_assign_strongCast (id, id*)
- StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy,
- PtrToIdTy);
- // id objc_assign_global(id, id*);
- GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy);
- // id objc_assign_weak(id, id*);
- WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy);
- // id objc_read_weak(id*);
- WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy);
- // void *objc_memmove_collectable(void*, void *, size_t);
- MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy,
- SizeTy);
- }
-}
-
-llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF,
- const std::string &Name, bool isWeak) {
- llvm::Constant *ClassName = MakeConstantString(Name);
- // With the incompatible ABI, this will need to be replaced with a direct
- // reference to the class symbol. For the compatible nonfragile ABI we are
- // still performing this lookup at run time but emitting the symbol for the
- // class externally so that we can make the switch later.
- //
- // Libobjc2 contains an LLVM pass that replaces calls to objc_lookup_class
- // with memoized versions or with static references if it's safe to do so.
- if (!isWeak)
- EmitClassRef(Name);
-
- llvm::Constant *ClassLookupFn =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
- "objc_lookup_class");
- return CGF.EmitNounwindRuntimeCall(ClassLookupFn, ClassName);
-}
-
-// This has to perform the lookup every time, since posing and related
-// techniques can modify the name -> class mapping.
-llvm::Value *CGObjCGNU::GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *OID) {
- auto *Value =
- GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported());
- if (auto *ClassSymbol = dyn_cast<llvm::GlobalVariable>(Value))
- CGM.setGVProperties(ClassSymbol, OID);
- return Value;
-}
-
-llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
- auto *Value = GetClassNamed(CGF, "NSAutoreleasePool", false);
- if (CGM.getTriple().isOSBinFormatCOFF()) {
- if (auto *ClassSymbol = dyn_cast<llvm::GlobalVariable>(Value)) {
- IdentifierInfo &II = CGF.CGM.getContext().Idents.get("NSAutoreleasePool");
- TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl();
- DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
-
- const VarDecl *VD = nullptr;
- for (const auto &Result : DC->lookup(&II))
- if ((VD = dyn_cast<VarDecl>(Result)))
- break;
-
- CGM.setGVProperties(ClassSymbol, VD);
- }
- }
- return Value;
-}
-
-llvm::Value *CGObjCGNU::GetTypedSelector(CodeGenFunction &CGF, Selector Sel,
- const std::string &TypeEncoding) {
- SmallVectorImpl<TypedSelector> &Types = SelectorTable[Sel];
- llvm::GlobalAlias *SelValue = nullptr;
-
- for (SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
- e = Types.end() ; i!=e ; i++) {
- if (i->first == TypeEncoding) {
- SelValue = i->second;
- break;
- }
- }
- if (!SelValue) {
- SelValue = llvm::GlobalAlias::create(
- SelectorTy->getElementType(), 0, llvm::GlobalValue::PrivateLinkage,
- ".objc_selector_" + Sel.getAsString(), &TheModule);
- Types.emplace_back(TypeEncoding, SelValue);
- }
-
- return SelValue;
-}
-
-Address CGObjCGNU::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) {
- llvm::Value *SelValue = GetSelector(CGF, Sel);
-
- // Store it to a temporary. Does this satisfy the semantics of
- // GetAddrOfSelector? Hopefully.
- Address tmp = CGF.CreateTempAlloca(SelValue->getType(),
- CGF.getPointerAlign());
- CGF.Builder.CreateStore(SelValue, tmp);
- return tmp;
-}
-
-llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel) {
- return GetTypedSelector(CGF, Sel, std::string());
-}
-
-llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF,
- const ObjCMethodDecl *Method) {
- std::string SelTypes = CGM.getContext().getObjCEncodingForMethodDecl(Method);
- return GetTypedSelector(CGF, Method->getSelector(), SelTypes);
-}
-
-llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
- if (T->isObjCIdType() || T->isObjCQualifiedIdType()) {
- // With the old ABI, there was only one kind of catchall, which broke
- // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as
- // a pointer indicating object catchalls, and NULL to indicate real
- // catchalls
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- return MakeConstantString("@id");
- } else {
- return nullptr;
- }
- }
-
- // All other types should be Objective-C interface pointer types.
- const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>();
- assert(OPT && "Invalid @catch type.");
- const ObjCInterfaceDecl *IDecl = OPT->getObjectType()->getInterface();
- assert(IDecl && "Invalid @catch type.");
- return MakeConstantString(IDecl->getIdentifier()->getName());
-}
-
-llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
- if (usesSEHExceptions)
- return CGM.getCXXABI().getAddrOfRTTIDescriptor(T);
-
- if (!CGM.getLangOpts().CPlusPlus)
- return CGObjCGNU::GetEHType(T);
-
- // For Objective-C++, we want to provide the ability to catch both C++ and
- // Objective-C objects in the same function.
-
- // There's a particular fixed type info for 'id'.
- if (T->isObjCIdType() ||
- T->isObjCQualifiedIdType()) {
- llvm::Constant *IDEHType =
- CGM.getModule().getGlobalVariable("__objc_id_type_info");
- if (!IDEHType)
- IDEHType =
- new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty,
- false,
- llvm::GlobalValue::ExternalLinkage,
- nullptr, "__objc_id_type_info");
- return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty);
- }
-
- const ObjCObjectPointerType *PT =
- T->getAs<ObjCObjectPointerType>();
- assert(PT && "Invalid @catch type.");
- const ObjCInterfaceType *IT = PT->getInterfaceType();
- assert(IT && "Invalid @catch type.");
- std::string className = IT->getDecl()->getIdentifier()->getName();
-
- std::string typeinfoName = "__objc_eh_typeinfo_" + className;
-
- // Return the existing typeinfo if it exists
- llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName);
- if (typeinfo)
- return llvm::ConstantExpr::getBitCast(typeinfo, PtrToInt8Ty);
-
- // Otherwise create it.
-
- // vtable for gnustep::libobjc::__objc_class_type_info
- // It's quite ugly hard-coding this. Ideally we'd generate it using the host
- // platform's name mangling.
- const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE";
- auto *Vtable = TheModule.getGlobalVariable(vtableName);
- if (!Vtable) {
- Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true,
- llvm::GlobalValue::ExternalLinkage,
- nullptr, vtableName);
- }
- llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2);
- auto *BVtable = llvm::ConstantExpr::getBitCast(
- llvm::ConstantExpr::getGetElementPtr(Vtable->getValueType(), Vtable, Two),
- PtrToInt8Ty);
-
- llvm::Constant *typeName =
- ExportUniqueString(className, "__objc_eh_typename_");
-
- ConstantInitBuilder builder(CGM);
- auto fields = builder.beginStruct();
- fields.add(BVtable);
- fields.add(typeName);
- llvm::Constant *TI =
- fields.finishAndCreateGlobal("__objc_eh_typeinfo_" + className,
- CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::LinkOnceODRLinkage);
- return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty);
-}
-
-/// Generate an NSConstantString object.
-ConstantAddress CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
-
- std::string Str = SL->getString().str();
- CharUnits Align = CGM.getPointerAlign();
-
- // Look for an existing one
- llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str);
- if (old != ObjCStrings.end())
- return ConstantAddress(old->getValue(), Align);
-
- StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass;
-
- if (StringClass.empty()) StringClass = "NSConstantString";
-
- std::string Sym = "_OBJC_CLASS_";
- Sym += StringClass;
-
- llvm::Constant *isa = TheModule.getNamedGlobal(Sym);
-
- if (!isa)
- isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false,
- llvm::GlobalValue::ExternalWeakLinkage, nullptr, Sym);
- else if (isa->getType() != PtrToIdTy)
- isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy);
-
- ConstantInitBuilder Builder(CGM);
- auto Fields = Builder.beginStruct();
- Fields.add(isa);
- Fields.add(MakeConstantString(Str));
- Fields.addInt(IntTy, Str.size());
- llvm::Constant *ObjCStr =
- Fields.finishAndCreateGlobal(".objc_str", Align);
- ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty);
- ObjCStrings[Str] = ObjCStr;
- ConstantStrings.push_back(ObjCStr);
- return ConstantAddress(ObjCStr, Align);
-}
-
-///Generates a message send where the super is the receiver. This is a message
-///send to self with special delivery semantics indicating which class's method
-///should be called.
-RValue
-CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- const ObjCInterfaceDecl *Class,
- bool isCategoryImpl,
- llvm::Value *Receiver,
- bool IsClassMessage,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method) {
- CGBuilderTy &Builder = CGF.Builder;
- if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
- if (Sel == RetainSel || Sel == AutoreleaseSel) {
- return RValue::get(EnforceType(Builder, Receiver,
- CGM.getTypes().ConvertType(ResultType)));
- }
- if (Sel == ReleaseSel) {
- return RValue::get(nullptr);
- }
- }
-
- llvm::Value *cmd = GetSelector(CGF, Sel);
- CallArgList ActualArgs;
-
- ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy);
- ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
- ActualArgs.addFrom(CallArgs);
-
- MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
-
- llvm::Value *ReceiverClass = nullptr;
- bool isV2ABI = isRuntime(ObjCRuntime::GNUstep, 2);
- if (isV2ABI) {
- ReceiverClass = GetClassNamed(CGF,
- Class->getSuperClass()->getNameAsString(), /*isWeak*/false);
- if (IsClassMessage) {
- // Load the isa pointer of the superclass is this is a class method.
- ReceiverClass = Builder.CreateBitCast(ReceiverClass,
- llvm::PointerType::getUnqual(IdTy));
- ReceiverClass =
- Builder.CreateAlignedLoad(ReceiverClass, CGF.getPointerAlign());
- }
- ReceiverClass = EnforceType(Builder, ReceiverClass, IdTy);
- } else {
- if (isCategoryImpl) {
- llvm::Constant *classLookupFunction = nullptr;
- if (IsClassMessage) {
- classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, PtrTy, true), "objc_get_meta_class");
- } else {
- classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, PtrTy, true), "objc_get_class");
- }
- ReceiverClass = Builder.CreateCall(classLookupFunction,
- MakeConstantString(Class->getNameAsString()));
- } else {
- // Set up global aliases for the metaclass or class pointer if they do not
- // already exist. These will are forward-references which will be set to
- // pointers to the class and metaclass structure created for the runtime
- // load function. To send a message to super, we look up the value of the
- // super_class pointer from either the class or metaclass structure.
- if (IsClassMessage) {
- if (!MetaClassPtrAlias) {
- MetaClassPtrAlias = llvm::GlobalAlias::create(
- IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
- ".objc_metaclass_ref" + Class->getNameAsString(), &TheModule);
- }
- ReceiverClass = MetaClassPtrAlias;
- } else {
- if (!ClassPtrAlias) {
- ClassPtrAlias = llvm::GlobalAlias::create(
- IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
- ".objc_class_ref" + Class->getNameAsString(), &TheModule);
- }
- ReceiverClass = ClassPtrAlias;
- }
- }
- // Cast the pointer to a simplified version of the class structure
- llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy);
- ReceiverClass = Builder.CreateBitCast(ReceiverClass,
- llvm::PointerType::getUnqual(CastTy));
- // Get the superclass pointer
- ReceiverClass = Builder.CreateStructGEP(CastTy, ReceiverClass, 1);
- // Load the superclass pointer
- ReceiverClass =
- Builder.CreateAlignedLoad(ReceiverClass, CGF.getPointerAlign());
- }
- // Construct the structure used to look up the IMP
- llvm::StructType *ObjCSuperTy =
- llvm::StructType::get(Receiver->getType(), IdTy);
-
- Address ObjCSuper = CGF.CreateTempAlloca(ObjCSuperTy,
- CGF.getPointerAlign());
-
- Builder.CreateStore(Receiver,
- Builder.CreateStructGEP(ObjCSuper, 0, CharUnits::Zero()));
- Builder.CreateStore(ReceiverClass,
- Builder.CreateStructGEP(ObjCSuper, 1, CGF.getPointerSize()));
-
- ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
-
- // Get the IMP
- llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd, MSI);
- imp = EnforceType(Builder, imp, MSI.MessengerType);
-
- llvm::Metadata *impMD[] = {
- llvm::MDString::get(VMContext, Sel.getAsString()),
- llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::Type::getInt1Ty(VMContext), IsClassMessage))};
- llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
-
- CGCallee callee(CGCalleeInfo(), imp);
-
- llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call);
- call->setMetadata(msgSendMDKind, node);
- return msgRet;
-}
-
-/// Generate code for a message send expression.
-RValue
-CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method) {
- CGBuilderTy &Builder = CGF.Builder;
-
- // Strip out message sends to retain / release in GC mode
- if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
- if (Sel == RetainSel || Sel == AutoreleaseSel) {
- return RValue::get(EnforceType(Builder, Receiver,
- CGM.getTypes().ConvertType(ResultType)));
- }
- if (Sel == ReleaseSel) {
- return RValue::get(nullptr);
- }
- }
-
- // If the return type is something that goes in an integer register, the
- // runtime will handle 0 returns. For other cases, we fill in the 0 value
- // ourselves.
- //
- // The language spec says the result of this kind of message send is
- // undefined, but lots of people seem to have forgotten to read that
- // paragraph and insist on sending messages to nil that have structure
- // returns. With GCC, this generates a random return value (whatever happens
- // to be on the stack / in those registers at the time) on most platforms,
- // and generates an illegal instruction trap on SPARC. With LLVM it corrupts
- // the stack.
- bool isPointerSizedReturn = (ResultType->isAnyPointerType() ||
- ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType());
-
- llvm::BasicBlock *startBB = nullptr;
- llvm::BasicBlock *messageBB = nullptr;
- llvm::BasicBlock *continueBB = nullptr;
-
- if (!isPointerSizedReturn) {
- startBB = Builder.GetInsertBlock();
- messageBB = CGF.createBasicBlock("msgSend");
- continueBB = CGF.createBasicBlock("continue");
-
- llvm::Value *isNil = Builder.CreateICmpEQ(Receiver,
- llvm::Constant::getNullValue(Receiver->getType()));
- Builder.CreateCondBr(isNil, continueBB, messageBB);
- CGF.EmitBlock(messageBB);
- }
-
- IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
- llvm::Value *cmd;
- if (Method)
- cmd = GetSelector(CGF, Method);
- else
- cmd = GetSelector(CGF, Sel);
- cmd = EnforceType(Builder, cmd, SelectorTy);
- Receiver = EnforceType(Builder, Receiver, IdTy);
-
- llvm::Metadata *impMD[] = {
- llvm::MDString::get(VMContext, Sel.getAsString()),
- llvm::MDString::get(VMContext, Class ? Class->getNameAsString() : ""),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::Type::getInt1Ty(VMContext), Class != nullptr))};
- llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
-
- CallArgList ActualArgs;
- ActualArgs.add(RValue::get(Receiver), ASTIdTy);
- ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
- ActualArgs.addFrom(CallArgs);
-
- MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
-
- // Get the IMP to call
- llvm::Value *imp;
-
- // If we have non-legacy dispatch specified, we try using the objc_msgSend()
- // functions. These are not supported on all platforms (or all runtimes on a
- // given platform), so we
- switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
- case CodeGenOptions::Legacy:
- imp = LookupIMP(CGF, Receiver, cmd, node, MSI);
- break;
- case CodeGenOptions::Mixed:
- case CodeGenOptions::NonLegacy:
- if (CGM.ReturnTypeUsesFPRet(ResultType)) {
- imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
- "objc_msgSend_fpret");
- } else if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
- // The actual types here don't matter - we're going to bitcast the
- // function anyway
- imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
- "objc_msgSend_stret");
- } else {
- imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
- "objc_msgSend");
- }
- }
-
- // Reset the receiver in case the lookup modified it
- ActualArgs[0] = CallArg(RValue::get(Receiver), ASTIdTy);
-
- imp = EnforceType(Builder, imp, MSI.MessengerType);
-
- llvm::Instruction *call;
- CGCallee callee(CGCalleeInfo(), imp);
- RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call);
- call->setMetadata(msgSendMDKind, node);
-
-
- if (!isPointerSizedReturn) {
- messageBB = CGF.Builder.GetInsertBlock();
- CGF.Builder.CreateBr(continueBB);
- CGF.EmitBlock(continueBB);
- if (msgRet.isScalar()) {
- llvm::Value *v = msgRet.getScalarVal();
- llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
- phi->addIncoming(v, messageBB);
- phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB);
- msgRet = RValue::get(phi);
- } else if (msgRet.isAggregate()) {
- Address v = msgRet.getAggregateAddress();
- llvm::PHINode *phi = Builder.CreatePHI(v.getType(), 2);
- llvm::Type *RetTy = v.getElementType();
- Address NullVal = CGF.CreateTempAlloca(RetTy, v.getAlignment(), "null");
- CGF.InitTempAlloca(NullVal, llvm::Constant::getNullValue(RetTy));
- phi->addIncoming(v.getPointer(), messageBB);
- phi->addIncoming(NullVal.getPointer(), startBB);
- msgRet = RValue::getAggregate(Address(phi, v.getAlignment()));
- } else /* isComplex() */ {
- std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal();
- llvm::PHINode *phi = Builder.CreatePHI(v.first->getType(), 2);
- phi->addIncoming(v.first, messageBB);
- phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()),
- startBB);
- llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType(), 2);
- phi2->addIncoming(v.second, messageBB);
- phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()),
- startBB);
- msgRet = RValue::getComplex(phi, phi2);
- }
- }
- return msgRet;
-}
-
-/// Generates a MethodList. Used in construction of a objc_class and
-/// objc_category structures.
-llvm::Constant *CGObjCGNU::
-GenerateMethodList(StringRef ClassName,
- StringRef CategoryName,
- ArrayRef<const ObjCMethodDecl*> Methods,
- bool isClassMethodList) {
- if (Methods.empty())
- return NULLPtr;
-
- ConstantInitBuilder Builder(CGM);
-
- auto MethodList = Builder.beginStruct();
- MethodList.addNullPointer(CGM.Int8PtrTy);
- MethodList.addInt(Int32Ty, Methods.size());
-
- // Get the method structure type.
- llvm::StructType *ObjCMethodTy =
- llvm::StructType::get(CGM.getLLVMContext(), {
- PtrToInt8Ty, // Really a selector, but the runtime creates it us.
- PtrToInt8Ty, // Method types
- IMPTy // Method pointer
- });
- bool isV2ABI = isRuntime(ObjCRuntime::GNUstep, 2);
- if (isV2ABI) {
- // size_t size;
- llvm::DataLayout td(&TheModule);
- MethodList.addInt(SizeTy, td.getTypeSizeInBits(ObjCMethodTy) /
- CGM.getContext().getCharWidth());
- ObjCMethodTy =
- llvm::StructType::get(CGM.getLLVMContext(), {
- IMPTy, // Method pointer
- PtrToInt8Ty, // Selector
- PtrToInt8Ty // Extended type encoding
- });
- } else {
- ObjCMethodTy =
- llvm::StructType::get(CGM.getLLVMContext(), {
- PtrToInt8Ty, // Really a selector, but the runtime creates it us.
- PtrToInt8Ty, // Method types
- IMPTy // Method pointer
- });
- }
- auto MethodArray = MethodList.beginArray();
- ASTContext &Context = CGM.getContext();
- for (const auto *OMD : Methods) {
- llvm::Constant *FnPtr =
- TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
- OMD->getSelector(),
- isClassMethodList));
- assert(FnPtr && "Can't generate metadata for method that doesn't exist");
- auto Method = MethodArray.beginStruct(ObjCMethodTy);
- if (isV2ABI) {
- Method.addBitCast(FnPtr, IMPTy);
- Method.add(GetConstantSelector(OMD->getSelector(),
- Context.getObjCEncodingForMethodDecl(OMD)));
- Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(OMD, true)));
- } else {
- Method.add(MakeConstantString(OMD->getSelector().getAsString()));
- Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(OMD)));
- Method.addBitCast(FnPtr, IMPTy);
- }
- Method.finishAndAddTo(MethodArray);
- }
- MethodArray.finishAndAddTo(MethodList);
-
- // Create an instance of the structure
- return MethodList.finishAndCreateGlobal(".objc_method_list",
- CGM.getPointerAlign());
-}
-
-/// Generates an IvarList. Used in construction of a objc_class.
-llvm::Constant *CGObjCGNU::
-GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
- ArrayRef<llvm::Constant *> IvarTypes,
- ArrayRef<llvm::Constant *> IvarOffsets,
- ArrayRef<llvm::Constant *> IvarAlign,
- ArrayRef<Qualifiers::ObjCLifetime> IvarOwnership) {
- if (IvarNames.empty())
- return NULLPtr;
-
- ConstantInitBuilder Builder(CGM);
-
- // Structure containing array count followed by array.
- auto IvarList = Builder.beginStruct();
- IvarList.addInt(IntTy, (int)IvarNames.size());
-
- // Get the ivar structure type.
- llvm::StructType *ObjCIvarTy =
- llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy);
-
- // Array of ivar structures.
- auto Ivars = IvarList.beginArray(ObjCIvarTy);
- for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) {
- auto Ivar = Ivars.beginStruct(ObjCIvarTy);
- Ivar.add(IvarNames[i]);
- Ivar.add(IvarTypes[i]);
- Ivar.add(IvarOffsets[i]);
- Ivar.finishAndAddTo(Ivars);
- }
- Ivars.finishAndAddTo(IvarList);
-
- // Create an instance of the structure
- return IvarList.finishAndCreateGlobal(".objc_ivar_list",
- CGM.getPointerAlign());
-}
-
-/// Generate a class structure
-llvm::Constant *CGObjCGNU::GenerateClassStructure(
- llvm::Constant *MetaClass,
- llvm::Constant *SuperClass,
- unsigned info,
- const char *Name,
- llvm::Constant *Version,
- llvm::Constant *InstanceSize,
- llvm::Constant *IVars,
- llvm::Constant *Methods,
- llvm::Constant *Protocols,
- llvm::Constant *IvarOffsets,
- llvm::Constant *Properties,
- llvm::Constant *StrongIvarBitmap,
- llvm::Constant *WeakIvarBitmap,
- bool isMeta) {
- // Set up the class structure
- // Note: Several of these are char*s when they should be ids. This is
- // because the runtime performs this translation on load.
- //
- // Fields marked New ABI are part of the GNUstep runtime. We emit them
- // anyway; the classes will still work with the GNU runtime, they will just
- // be ignored.
- llvm::StructType *ClassTy = llvm::StructType::get(
- PtrToInt8Ty, // isa
- PtrToInt8Ty, // super_class
- PtrToInt8Ty, // name
- LongTy, // version
- LongTy, // info
- LongTy, // instance_size
- IVars->getType(), // ivars
- Methods->getType(), // methods
- // These are all filled in by the runtime, so we pretend
- PtrTy, // dtable
- PtrTy, // subclass_list
- PtrTy, // sibling_class
- PtrTy, // protocols
- PtrTy, // gc_object_type
- // New ABI:
- LongTy, // abi_version
- IvarOffsets->getType(), // ivar_offsets
- Properties->getType(), // properties
- IntPtrTy, // strong_pointers
- IntPtrTy // weak_pointers
- );
-
- ConstantInitBuilder Builder(CGM);
- auto Elements = Builder.beginStruct(ClassTy);
-
- // Fill in the structure
-
- // isa
- Elements.addBitCast(MetaClass, PtrToInt8Ty);
- // super_class
- Elements.add(SuperClass);
- // name
- Elements.add(MakeConstantString(Name, ".class_name"));
- // version
- Elements.addInt(LongTy, 0);
- // info
- Elements.addInt(LongTy, info);
- // instance_size
- if (isMeta) {
- llvm::DataLayout td(&TheModule);
- Elements.addInt(LongTy,
- td.getTypeSizeInBits(ClassTy) /
- CGM.getContext().getCharWidth());
- } else
- Elements.add(InstanceSize);
- // ivars
- Elements.add(IVars);
- // methods
- Elements.add(Methods);
- // These are all filled in by the runtime, so we pretend
- // dtable
- Elements.add(NULLPtr);
- // subclass_list
- Elements.add(NULLPtr);
- // sibling_class
- Elements.add(NULLPtr);
- // protocols
- Elements.addBitCast(Protocols, PtrTy);
- // gc_object_type
- Elements.add(NULLPtr);
- // abi_version
- Elements.addInt(LongTy, ClassABIVersion);
- // ivar_offsets
- Elements.add(IvarOffsets);
- // properties
- Elements.add(Properties);
- // strong_pointers
- Elements.add(StrongIvarBitmap);
- // weak_pointers
- Elements.add(WeakIvarBitmap);
- // Create an instance of the structure
- // This is now an externally visible symbol, so that we can speed up class
- // messages in the next ABI. We may already have some weak references to
- // this, so check and fix them properly.
- std::string ClassSym((isMeta ? "_OBJC_METACLASS_": "_OBJC_CLASS_") +
- std::string(Name));
- llvm::GlobalVariable *ClassRef = TheModule.getNamedGlobal(ClassSym);
- llvm::Constant *Class =
- Elements.finishAndCreateGlobal(ClassSym, CGM.getPointerAlign(), false,
- llvm::GlobalValue::ExternalLinkage);
- if (ClassRef) {
- ClassRef->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(Class,
- ClassRef->getType()));
- ClassRef->removeFromParent();
- Class->setName(ClassSym);
- }
- return Class;
-}
-
-llvm::Constant *CGObjCGNU::
-GenerateProtocolMethodList(ArrayRef<const ObjCMethodDecl*> Methods) {
- // Get the method structure type.
- llvm::StructType *ObjCMethodDescTy =
- llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, PtrToInt8Ty });
- ASTContext &Context = CGM.getContext();
- ConstantInitBuilder Builder(CGM);
- auto MethodList = Builder.beginStruct();
- MethodList.addInt(IntTy, Methods.size());
- auto MethodArray = MethodList.beginArray(ObjCMethodDescTy);
- for (auto *M : Methods) {
- auto Method = MethodArray.beginStruct(ObjCMethodDescTy);
- Method.add(MakeConstantString(M->getSelector().getAsString()));
- Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(M)));
- Method.finishAndAddTo(MethodArray);
- }
- MethodArray.finishAndAddTo(MethodList);
- return MethodList.finishAndCreateGlobal(".objc_method_list",
- CGM.getPointerAlign());
-}
-
-// Create the protocol list structure used in classes, categories and so on
-llvm::Constant *
-CGObjCGNU::GenerateProtocolList(ArrayRef<std::string> Protocols) {
-
- ConstantInitBuilder Builder(CGM);
- auto ProtocolList = Builder.beginStruct();
- ProtocolList.add(NULLPtr);
- ProtocolList.addInt(LongTy, Protocols.size());
-
- auto Elements = ProtocolList.beginArray(PtrToInt8Ty);
- for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end();
- iter != endIter ; iter++) {
- llvm::Constant *protocol = nullptr;
- llvm::StringMap<llvm::Constant*>::iterator value =
- ExistingProtocols.find(*iter);
- if (value == ExistingProtocols.end()) {
- protocol = GenerateEmptyProtocol(*iter);
- } else {
- protocol = value->getValue();
- }
- Elements.addBitCast(protocol, PtrToInt8Ty);
- }
- Elements.finishAndAddTo(ProtocolList);
- return ProtocolList.finishAndCreateGlobal(".objc_protocol_list",
- CGM.getPointerAlign());
-}
-
-llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD) {
- llvm::Constant *&protocol = ExistingProtocols[PD->getNameAsString()];
- if (!protocol)
- GenerateProtocol(PD);
- llvm::Type *T =
- CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
- return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
-}
-
-llvm::Constant *
-CGObjCGNU::GenerateEmptyProtocol(StringRef ProtocolName) {
- llvm::Constant *ProtocolList = GenerateProtocolList({});
- llvm::Constant *MethodList = GenerateProtocolMethodList({});
- MethodList = llvm::ConstantExpr::getBitCast(MethodList, PtrToInt8Ty);
- // Protocols are objects containing lists of the methods implemented and
- // protocols adopted.
- ConstantInitBuilder Builder(CGM);
- auto Elements = Builder.beginStruct();
-
- // The isa pointer must be set to a magic number so the runtime knows it's
- // the correct layout.
- Elements.add(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
-
- Elements.add(MakeConstantString(ProtocolName, ".objc_protocol_name"));
- Elements.add(ProtocolList); /* .protocol_list */
- Elements.add(MethodList); /* .instance_methods */
- Elements.add(MethodList); /* .class_methods */
- Elements.add(MethodList); /* .optional_instance_methods */
- Elements.add(MethodList); /* .optional_class_methods */
- Elements.add(NULLPtr); /* .properties */
- Elements.add(NULLPtr); /* .optional_properties */
- return Elements.finishAndCreateGlobal(SymbolForProtocol(ProtocolName),
- CGM.getPointerAlign());
-}
-
-void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
- std::string ProtocolName = PD->getNameAsString();
-
- // Use the protocol definition, if there is one.
- if (const ObjCProtocolDecl *Def = PD->getDefinition())
- PD = Def;
-
- SmallVector<std::string, 16> Protocols;
- for (const auto *PI : PD->protocols())
- Protocols.push_back(PI->getNameAsString());
- SmallVector<const ObjCMethodDecl*, 16> InstanceMethods;
- SmallVector<const ObjCMethodDecl*, 16> OptionalInstanceMethods;
- for (const auto *I : PD->instance_methods())
- if (I->isOptional())
- OptionalInstanceMethods.push_back(I);
- else
- InstanceMethods.push_back(I);
- // Collect information about class methods:
- SmallVector<const ObjCMethodDecl*, 16> ClassMethods;
- SmallVector<const ObjCMethodDecl*, 16> OptionalClassMethods;
- for (const auto *I : PD->class_methods())
- if (I->isOptional())
- OptionalClassMethods.push_back(I);
- else
- ClassMethods.push_back(I);
-
- llvm::Constant *ProtocolList = GenerateProtocolList(Protocols);
- llvm::Constant *InstanceMethodList =
- GenerateProtocolMethodList(InstanceMethods);
- llvm::Constant *ClassMethodList =
- GenerateProtocolMethodList(ClassMethods);
- llvm::Constant *OptionalInstanceMethodList =
- GenerateProtocolMethodList(OptionalInstanceMethods);
- llvm::Constant *OptionalClassMethodList =
- GenerateProtocolMethodList(OptionalClassMethods);
-
- // Property metadata: name, attributes, isSynthesized, setter name, setter
- // types, getter name, getter types.
- // The isSynthesized value is always set to 0 in a protocol. It exists to
- // simplify the runtime library by allowing it to use the same data
- // structures for protocol metadata everywhere.
-
- llvm::Constant *PropertyList =
- GeneratePropertyList(nullptr, PD, false, false);
- llvm::Constant *OptionalPropertyList =
- GeneratePropertyList(nullptr, PD, false, true);
-
- // Protocols are objects containing lists of the methods implemented and
- // protocols adopted.
- // The isa pointer must be set to a magic number so the runtime knows it's
- // the correct layout.
- ConstantInitBuilder Builder(CGM);
- auto Elements = Builder.beginStruct();
- Elements.add(
- llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
- Elements.add(MakeConstantString(ProtocolName));
- Elements.add(ProtocolList);
- Elements.add(InstanceMethodList);
- Elements.add(ClassMethodList);
- Elements.add(OptionalInstanceMethodList);
- Elements.add(OptionalClassMethodList);
- Elements.add(PropertyList);
- Elements.add(OptionalPropertyList);
- ExistingProtocols[ProtocolName] =
- llvm::ConstantExpr::getBitCast(
- Elements.finishAndCreateGlobal(".objc_protocol", CGM.getPointerAlign()),
- IdTy);
-}
-void CGObjCGNU::GenerateProtocolHolderCategory() {
- // Collect information about instance methods
-
- ConstantInitBuilder Builder(CGM);
- auto Elements = Builder.beginStruct();
-
- const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack";
- const std::string CategoryName = "AnotherHack";
- Elements.add(MakeConstantString(CategoryName));
- Elements.add(MakeConstantString(ClassName));
- // Instance method list
- Elements.addBitCast(GenerateMethodList(
- ClassName, CategoryName, {}, false), PtrTy);
- // Class method list
- Elements.addBitCast(GenerateMethodList(
- ClassName, CategoryName, {}, true), PtrTy);
-
- // Protocol list
- ConstantInitBuilder ProtocolListBuilder(CGM);
- auto ProtocolList = ProtocolListBuilder.beginStruct();
- ProtocolList.add(NULLPtr);
- ProtocolList.addInt(LongTy, ExistingProtocols.size());
- auto ProtocolElements = ProtocolList.beginArray(PtrTy);
- for (auto iter = ExistingProtocols.begin(), endIter = ExistingProtocols.end();
- iter != endIter ; iter++) {
- ProtocolElements.addBitCast(iter->getValue(), PtrTy);
- }
- ProtocolElements.finishAndAddTo(ProtocolList);
- Elements.addBitCast(
- ProtocolList.finishAndCreateGlobal(".objc_protocol_list",
- CGM.getPointerAlign()),
- PtrTy);
- Categories.push_back(llvm::ConstantExpr::getBitCast(
- Elements.finishAndCreateGlobal("", CGM.getPointerAlign()),
- PtrTy));
-}
-
-/// Libobjc2 uses a bitfield representation where small(ish) bitfields are
-/// stored in a 64-bit value with the low bit set to 1 and the remaining 63
-/// bits set to their values, LSB first, while larger ones are stored in a
-/// structure of this / form:
-///
-/// struct { int32_t length; int32_t values[length]; };
-///
-/// The values in the array are stored in host-endian format, with the least
-/// significant bit being assumed to come first in the bitfield. Therefore, a
-/// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a
-/// bitfield / with the 63rd bit set will be 1<<64.
-llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
- int bitCount = bits.size();
- int ptrBits = CGM.getDataLayout().getPointerSizeInBits();
- if (bitCount < ptrBits) {
- uint64_t val = 1;
- for (int i=0 ; i<bitCount ; ++i) {
- if (bits[i]) val |= 1ULL<<(i+1);
- }
- return llvm::ConstantInt::get(IntPtrTy, val);
- }
- SmallVector<llvm::Constant *, 8> values;
- int v=0;
- while (v < bitCount) {
- int32_t word = 0;
- for (int i=0 ; (i<32) && (v<bitCount) ; ++i) {
- if (bits[v]) word |= 1<<i;
- v++;
- }
- values.push_back(llvm::ConstantInt::get(Int32Ty, word));
- }
-
- ConstantInitBuilder builder(CGM);
- auto fields = builder.beginStruct();
- fields.addInt(Int32Ty, values.size());
- auto array = fields.beginArray();
- for (auto v : values) array.add(v);
- array.finishAndAddTo(fields);
-
- llvm::Constant *GS =
- fields.finishAndCreateGlobal("", CharUnits::fromQuantity(4));
- llvm::Constant *ptr = llvm::ConstantExpr::getPtrToInt(GS, IntPtrTy);
- return ptr;
-}
-
-llvm::Constant *CGObjCGNU::GenerateCategoryProtocolList(const
- ObjCCategoryDecl *OCD) {
- SmallVector<std::string, 16> Protocols;
- for (const auto *PD : OCD->getReferencedProtocols())
- Protocols.push_back(PD->getNameAsString());
- return GenerateProtocolList(Protocols);
-}
-
-void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
- const ObjCInterfaceDecl *Class = OCD->getClassInterface();
- std::string ClassName = Class->getNameAsString();
- std::string CategoryName = OCD->getNameAsString();
-
- // Collect the names of referenced protocols
- const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl();
-
- ConstantInitBuilder Builder(CGM);
- auto Elements = Builder.beginStruct();
- Elements.add(MakeConstantString(CategoryName));
- Elements.add(MakeConstantString(ClassName));
- // Instance method list
- SmallVector<ObjCMethodDecl*, 16> InstanceMethods;
- InstanceMethods.insert(InstanceMethods.begin(), OCD->instmeth_begin(),
- OCD->instmeth_end());
- Elements.addBitCast(
- GenerateMethodList(ClassName, CategoryName, InstanceMethods, false),
- PtrTy);
- // Class method list
-
- SmallVector<ObjCMethodDecl*, 16> ClassMethods;
- ClassMethods.insert(ClassMethods.begin(), OCD->classmeth_begin(),
- OCD->classmeth_end());
- Elements.addBitCast(
- GenerateMethodList(ClassName, CategoryName, ClassMethods, true),
- PtrTy);
- // Protocol list
- Elements.addBitCast(GenerateCategoryProtocolList(CatDecl), PtrTy);
- if (isRuntime(ObjCRuntime::GNUstep, 2)) {
- const ObjCCategoryDecl *Category =
- Class->FindCategoryDeclaration(OCD->getIdentifier());
- if (Category) {
- // Instance properties
- Elements.addBitCast(GeneratePropertyList(OCD, Category, false), PtrTy);
- // Class properties
- Elements.addBitCast(GeneratePropertyList(OCD, Category, true), PtrTy);
- } else {
- Elements.addNullPointer(PtrTy);
- Elements.addNullPointer(PtrTy);
- }
- }
-
- Categories.push_back(llvm::ConstantExpr::getBitCast(
- Elements.finishAndCreateGlobal(
- std::string(".objc_category_")+ClassName+CategoryName,
- CGM.getPointerAlign()),
- PtrTy));
-}
-
-llvm::Constant *CGObjCGNU::GeneratePropertyList(const Decl *Container,
- const ObjCContainerDecl *OCD,
- bool isClassProperty,
- bool protocolOptionalProperties) {
-
- SmallVector<const ObjCPropertyDecl *, 16> Properties;
- llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
- bool isProtocol = isa<ObjCProtocolDecl>(OCD);
- ASTContext &Context = CGM.getContext();
-
- std::function<void(const ObjCProtocolDecl *Proto)> collectProtocolProperties
- = [&](const ObjCProtocolDecl *Proto) {
- for (const auto *P : Proto->protocols())
- collectProtocolProperties(P);
- for (const auto *PD : Proto->properties()) {
- if (isClassProperty != PD->isClassProperty())
- continue;
- // Skip any properties that are declared in protocols that this class
- // conforms to but are not actually implemented by this class.
- if (!isProtocol && !Context.getObjCPropertyImplDeclForPropertyDecl(PD, Container))
- continue;
- if (!PropertySet.insert(PD->getIdentifier()).second)
- continue;
- Properties.push_back(PD);
- }
- };
-
- if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
- for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
- for (auto *PD : ClassExt->properties()) {
- if (isClassProperty != PD->isClassProperty())
- continue;
- PropertySet.insert(PD->getIdentifier());
- Properties.push_back(PD);
- }
-
- for (const auto *PD : OCD->properties()) {
- if (isClassProperty != PD->isClassProperty())
- continue;
- // If we're generating a list for a protocol, skip optional / required ones
- // when generating the other list.
- if (isProtocol && (protocolOptionalProperties != PD->isOptional()))
- continue;
- // Don't emit duplicate metadata for properties that were already in a
- // class extension.
- if (!PropertySet.insert(PD->getIdentifier()).second)
- continue;
-
- Properties.push_back(PD);
- }
-
- if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
- for (const auto *P : OID->all_referenced_protocols())
- collectProtocolProperties(P);
- else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD))
- for (const auto *P : CD->protocols())
- collectProtocolProperties(P);
-
- auto numProperties = Properties.size();
-
- if (numProperties == 0)
- return NULLPtr;
-
- ConstantInitBuilder builder(CGM);
- auto propertyList = builder.beginStruct();
- auto properties = PushPropertyListHeader(propertyList, numProperties);
-
- // Add all of the property methods need adding to the method list and to the
- // property metadata list.
- for (auto *property : Properties) {
- bool isSynthesized = false;
- bool isDynamic = false;
- if (!isProtocol) {
- auto *propertyImpl = Context.getObjCPropertyImplDeclForPropertyDecl(property, Container);
- if (propertyImpl) {
- isSynthesized = (propertyImpl->getPropertyImplementation() ==
- ObjCPropertyImplDecl::Synthesize);
- isDynamic = (propertyImpl->getPropertyImplementation() ==
- ObjCPropertyImplDecl::Dynamic);
- }
- }
- PushProperty(properties, property, Container, isSynthesized, isDynamic);
- }
- properties.finishAndAddTo(propertyList);
-
- return propertyList.finishAndCreateGlobal(".objc_property_list",
- CGM.getPointerAlign());
-}
-
-void CGObjCGNU::RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {
- // Get the class declaration for which the alias is specified.
- ObjCInterfaceDecl *ClassDecl =
- const_cast<ObjCInterfaceDecl *>(OAD->getClassInterface());
- ClassAliases.emplace_back(ClassDecl->getNameAsString(),
- OAD->getNameAsString());
-}
-
-void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
- ASTContext &Context = CGM.getContext();
-
- // Get the superclass name.
- const ObjCInterfaceDecl * SuperClassDecl =
- OID->getClassInterface()->getSuperClass();
- std::string SuperClassName;
- if (SuperClassDecl) {
- SuperClassName = SuperClassDecl->getNameAsString();
- EmitClassRef(SuperClassName);
- }
-
- // Get the class name
- ObjCInterfaceDecl *ClassDecl =
- const_cast<ObjCInterfaceDecl *>(OID->getClassInterface());
- std::string ClassName = ClassDecl->getNameAsString();
-
- // Emit the symbol that is used to generate linker errors if this class is
- // referenced in other modules but not declared.
- std::string classSymbolName = "__objc_class_name_" + ClassName;
- if (auto *symbol = TheModule.getGlobalVariable(classSymbolName)) {
- symbol->setInitializer(llvm::ConstantInt::get(LongTy, 0));
- } else {
- new llvm::GlobalVariable(TheModule, LongTy, false,
- llvm::GlobalValue::ExternalLinkage,
- llvm::ConstantInt::get(LongTy, 0),
- classSymbolName);
- }
-
- // Get the size of instances.
- int instanceSize =
- Context.getASTObjCImplementationLayout(OID).getSize().getQuantity();
-
- // Collect information about instance variables.
- SmallVector<llvm::Constant*, 16> IvarNames;
- SmallVector<llvm::Constant*, 16> IvarTypes;
- SmallVector<llvm::Constant*, 16> IvarOffsets;
- SmallVector<llvm::Constant*, 16> IvarAligns;
- SmallVector<Qualifiers::ObjCLifetime, 16> IvarOwnership;
-
- ConstantInitBuilder IvarOffsetBuilder(CGM);
- auto IvarOffsetValues = IvarOffsetBuilder.beginArray(PtrToIntTy);
- SmallVector<bool, 16> WeakIvars;
- SmallVector<bool, 16> StrongIvars;
-
- int superInstanceSize = !SuperClassDecl ? 0 :
- Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity();
- // For non-fragile ivars, set the instance size to 0 - {the size of just this
- // class}. The runtime will then set this to the correct value on load.
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- instanceSize = 0 - (instanceSize - superInstanceSize);
- }
-
- for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD;
- IVD = IVD->getNextIvar()) {
- // Store the name
- IvarNames.push_back(MakeConstantString(IVD->getNameAsString()));
- // Get the type encoding for this ivar
- std::string TypeStr;
- Context.getObjCEncodingForType(IVD->getType(), TypeStr, IVD);
- IvarTypes.push_back(MakeConstantString(TypeStr));
- IvarAligns.push_back(llvm::ConstantInt::get(IntTy,
- Context.getTypeSize(IVD->getType())));
- // Get the offset
- uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
- uint64_t Offset = BaseOffset;
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- Offset = BaseOffset - superInstanceSize;
- }
- llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset);
- // Create the direct offset value
- std::string OffsetName = "__objc_ivar_offset_value_" + ClassName +"." +
- IVD->getNameAsString();
-
- llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName);
- if (OffsetVar) {
- OffsetVar->setInitializer(OffsetValue);
- // If this is the real definition, change its linkage type so that
- // different modules will use this one, rather than their private
- // copy.
- OffsetVar->setLinkage(llvm::GlobalValue::ExternalLinkage);
- } else
- OffsetVar = new llvm::GlobalVariable(TheModule, Int32Ty,
- false, llvm::GlobalValue::ExternalLinkage,
- OffsetValue, OffsetName);
- IvarOffsets.push_back(OffsetValue);
- IvarOffsetValues.add(OffsetVar);
- Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime();
- IvarOwnership.push_back(lt);
- switch (lt) {
- case Qualifiers::OCL_Strong:
- StrongIvars.push_back(true);
- WeakIvars.push_back(false);
- break;
- case Qualifiers::OCL_Weak:
- StrongIvars.push_back(false);
- WeakIvars.push_back(true);
- break;
- default:
- StrongIvars.push_back(false);
- WeakIvars.push_back(false);
- }
- }
- llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars);
- llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars);
- llvm::GlobalVariable *IvarOffsetArray =
- IvarOffsetValues.finishAndCreateGlobal(".ivar.offsets",
- CGM.getPointerAlign());
-
- // Collect information about instance methods
- SmallVector<const ObjCMethodDecl*, 16> InstanceMethods;
- InstanceMethods.insert(InstanceMethods.begin(), OID->instmeth_begin(),
- OID->instmeth_end());
-
- SmallVector<const ObjCMethodDecl*, 16> ClassMethods;
- ClassMethods.insert(ClassMethods.begin(), OID->classmeth_begin(),
- OID->classmeth_end());
-
- // Collect the same information about synthesized properties, which don't
- // show up in the instance method lists.
- for (auto *propertyImpl : OID->property_impls())
- if (propertyImpl->getPropertyImplementation() ==
- ObjCPropertyImplDecl::Synthesize) {
- ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
- auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
- if (accessor)
- InstanceMethods.push_back(accessor);
- };
- addPropertyMethod(property->getGetterMethodDecl());
- addPropertyMethod(property->getSetterMethodDecl());
- }
-
- llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl);
-
- // Collect the names of referenced protocols
- SmallVector<std::string, 16> Protocols;
- for (const auto *I : ClassDecl->protocols())
- Protocols.push_back(I->getNameAsString());
-
- // Get the superclass pointer.
- llvm::Constant *SuperClass;
- if (!SuperClassName.empty()) {
- SuperClass = MakeConstantString(SuperClassName, ".super_class_name");
- } else {
- SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty);
- }
- // Empty vector used to construct empty method lists
- SmallVector<llvm::Constant*, 1> empty;
- // Generate the method and instance variable lists
- llvm::Constant *MethodList = GenerateMethodList(ClassName, "",
- InstanceMethods, false);
- llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "",
- ClassMethods, true);
- llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
- IvarOffsets, IvarAligns, IvarOwnership);
- // Irrespective of whether we are compiling for a fragile or non-fragile ABI,
- // we emit a symbol containing the offset for each ivar in the class. This
- // allows code compiled for the non-Fragile ABI to inherit from code compiled
- // for the legacy ABI, without causing problems. The converse is also
- // possible, but causes all ivar accesses to be fragile.
-
- // Offset pointer for getting at the correct field in the ivar list when
- // setting up the alias. These are: The base address for the global, the
- // ivar array (second field), the ivar in this list (set for each ivar), and
- // the offset (third field in ivar structure)
- llvm::Type *IndexTy = Int32Ty;
- llvm::Constant *offsetPointerIndexes[] = {Zeros[0],
- llvm::ConstantInt::get(IndexTy, ClassABIVersion > 1 ? 2 : 1), nullptr,
- llvm::ConstantInt::get(IndexTy, ClassABIVersion > 1 ? 3 : 2) };
-
- unsigned ivarIndex = 0;
- for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD;
- IVD = IVD->getNextIvar()) {
- const std::string Name = GetIVarOffsetVariableName(ClassDecl, IVD);
- offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, ivarIndex);
- // Get the correct ivar field
- llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr(
- cast<llvm::GlobalVariable>(IvarList)->getValueType(), IvarList,
- offsetPointerIndexes);
- // Get the existing variable, if one exists.
- llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name);
- if (offset) {
- offset->setInitializer(offsetValue);
- // If this is the real definition, change its linkage type so that
- // different modules will use this one, rather than their private
- // copy.
- offset->setLinkage(llvm::GlobalValue::ExternalLinkage);
- } else
- // Add a new alias if there isn't one already.
- new llvm::GlobalVariable(TheModule, offsetValue->getType(),
- false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name);
- ++ivarIndex;
- }
- llvm::Constant *ZeroPtr = llvm::ConstantInt::get(IntPtrTy, 0);
-
- //Generate metaclass for class methods
- llvm::Constant *MetaClassStruct = GenerateClassStructure(
- NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), nullptr, Zeros[0],
- NULLPtr, ClassMethodList, NULLPtr, NULLPtr,
- GeneratePropertyList(OID, ClassDecl, true), ZeroPtr, ZeroPtr, true);
- CGM.setGVProperties(cast<llvm::GlobalValue>(MetaClassStruct),
- OID->getClassInterface());
-
- // Generate the class structure
- llvm::Constant *ClassStruct = GenerateClassStructure(
- MetaClassStruct, SuperClass, 0x11L, ClassName.c_str(), nullptr,
- llvm::ConstantInt::get(LongTy, instanceSize), IvarList, MethodList,
- GenerateProtocolList(Protocols), IvarOffsetArray, Properties,
- StrongIvarBitmap, WeakIvarBitmap);
- CGM.setGVProperties(cast<llvm::GlobalValue>(ClassStruct),
- OID->getClassInterface());
-
- // Resolve the class aliases, if they exist.
- if (ClassPtrAlias) {
- ClassPtrAlias->replaceAllUsesWith(
- llvm::ConstantExpr::getBitCast(ClassStruct, IdTy));
- ClassPtrAlias->eraseFromParent();
- ClassPtrAlias = nullptr;
- }
- if (MetaClassPtrAlias) {
- MetaClassPtrAlias->replaceAllUsesWith(
- llvm::ConstantExpr::getBitCast(MetaClassStruct, IdTy));
- MetaClassPtrAlias->eraseFromParent();
- MetaClassPtrAlias = nullptr;
- }
-
- // Add class structure to list to be added to the symtab later
- ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty);
- Classes.push_back(ClassStruct);
-}
-
-llvm::Function *CGObjCGNU::ModuleInitFunction() {
- // Only emit an ObjC load function if no Objective-C stuff has been called
- if (Classes.empty() && Categories.empty() && ConstantStrings.empty() &&
- ExistingProtocols.empty() && SelectorTable.empty())
- return nullptr;
-
- // Add all referenced protocols to a category.
- GenerateProtocolHolderCategory();
-
- llvm::StructType *selStructTy =
- dyn_cast<llvm::StructType>(SelectorTy->getElementType());
- llvm::Type *selStructPtrTy = SelectorTy;
- if (!selStructTy) {
- selStructTy = llvm::StructType::get(CGM.getLLVMContext(),
- { PtrToInt8Ty, PtrToInt8Ty });
- selStructPtrTy = llvm::PointerType::getUnqual(selStructTy);
- }
-
- // Generate statics list:
- llvm::Constant *statics = NULLPtr;
- if (!ConstantStrings.empty()) {
- llvm::GlobalVariable *fileStatics = [&] {
- ConstantInitBuilder builder(CGM);
- auto staticsStruct = builder.beginStruct();
-
- StringRef stringClass = CGM.getLangOpts().ObjCConstantStringClass;
- if (stringClass.empty()) stringClass = "NXConstantString";
- staticsStruct.add(MakeConstantString(stringClass,
- ".objc_static_class_name"));
-
- auto array = staticsStruct.beginArray();
- array.addAll(ConstantStrings);
- array.add(NULLPtr);
- array.finishAndAddTo(staticsStruct);
-
- return staticsStruct.finishAndCreateGlobal(".objc_statics",
- CGM.getPointerAlign());
- }();
-
- ConstantInitBuilder builder(CGM);
- auto allStaticsArray = builder.beginArray(fileStatics->getType());
- allStaticsArray.add(fileStatics);
- allStaticsArray.addNullPointer(fileStatics->getType());
-
- statics = allStaticsArray.finishAndCreateGlobal(".objc_statics_ptr",
- CGM.getPointerAlign());
- statics = llvm::ConstantExpr::getBitCast(statics, PtrTy);
- }
-
- // Array of classes, categories, and constant objects.
-
- SmallVector<llvm::GlobalAlias*, 16> selectorAliases;
- unsigned selectorCount;
-
- // Pointer to an array of selectors used in this module.
- llvm::GlobalVariable *selectorList = [&] {
- ConstantInitBuilder builder(CGM);
- auto selectors = builder.beginArray(selStructTy);
- auto &table = SelectorTable; // MSVC workaround
- std::vector<Selector> allSelectors;
- for (auto &entry : table)
- allSelectors.push_back(entry.first);
- llvm::sort(allSelectors);
-
- for (auto &untypedSel : allSelectors) {
- std::string selNameStr = untypedSel.getAsString();
- llvm::Constant *selName = ExportUniqueString(selNameStr, ".objc_sel_name");
-
- for (TypedSelector &sel : table[untypedSel]) {
- llvm::Constant *selectorTypeEncoding = NULLPtr;
- if (!sel.first.empty())
- selectorTypeEncoding =
- MakeConstantString(sel.first, ".objc_sel_types");
-
- auto selStruct = selectors.beginStruct(selStructTy);
- selStruct.add(selName);
- selStruct.add(selectorTypeEncoding);
- selStruct.finishAndAddTo(selectors);
-
- // Store the selector alias for later replacement
- selectorAliases.push_back(sel.second);
- }
- }
-
- // Remember the number of entries in the selector table.
- selectorCount = selectors.size();
-
- // NULL-terminate the selector list. This should not actually be required,
- // because the selector list has a length field. Unfortunately, the GCC
- // runtime decides to ignore the length field and expects a NULL terminator,
- // and GCC cooperates with this by always setting the length to 0.
- auto selStruct = selectors.beginStruct(selStructTy);
- selStruct.add(NULLPtr);
- selStruct.add(NULLPtr);
- selStruct.finishAndAddTo(selectors);
-
- return selectors.finishAndCreateGlobal(".objc_selector_list",
- CGM.getPointerAlign());
- }();
-
- // Now that all of the static selectors exist, create pointers to them.
- for (unsigned i = 0; i < selectorCount; ++i) {
- llvm::Constant *idxs[] = {
- Zeros[0],
- llvm::ConstantInt::get(Int32Ty, i)
- };
- // FIXME: We're generating redundant loads and stores here!
- llvm::Constant *selPtr = llvm::ConstantExpr::getGetElementPtr(
- selectorList->getValueType(), selectorList, idxs);
- // If selectors are defined as an opaque type, cast the pointer to this
- // type.
- selPtr = llvm::ConstantExpr::getBitCast(selPtr, SelectorTy);
- selectorAliases[i]->replaceAllUsesWith(selPtr);
- selectorAliases[i]->eraseFromParent();
- }
-
- llvm::GlobalVariable *symtab = [&] {
- ConstantInitBuilder builder(CGM);
- auto symtab = builder.beginStruct();
-
- // Number of static selectors
- symtab.addInt(LongTy, selectorCount);
-
- symtab.addBitCast(selectorList, selStructPtrTy);
-
- // Number of classes defined.
- symtab.addInt(CGM.Int16Ty, Classes.size());
- // Number of categories defined
- symtab.addInt(CGM.Int16Ty, Categories.size());
-
- // Create an array of classes, then categories, then static object instances
- auto classList = symtab.beginArray(PtrToInt8Ty);
- classList.addAll(Classes);
- classList.addAll(Categories);
- // NULL-terminated list of static object instances (mainly constant strings)
- classList.add(statics);
- classList.add(NULLPtr);
- classList.finishAndAddTo(symtab);
-
- // Construct the symbol table.
- return symtab.finishAndCreateGlobal("", CGM.getPointerAlign());
- }();
-
- // The symbol table is contained in a module which has some version-checking
- // constants
- llvm::Constant *module = [&] {
- llvm::Type *moduleEltTys[] = {
- LongTy, LongTy, PtrToInt8Ty, symtab->getType(), IntTy
- };
- llvm::StructType *moduleTy =
- llvm::StructType::get(CGM.getLLVMContext(),
- makeArrayRef(moduleEltTys).drop_back(unsigned(RuntimeVersion < 10)));
-
- ConstantInitBuilder builder(CGM);
- auto module = builder.beginStruct(moduleTy);
- // Runtime version, used for ABI compatibility checking.
- module.addInt(LongTy, RuntimeVersion);
- // sizeof(ModuleTy)
- module.addInt(LongTy, CGM.getDataLayout().getTypeStoreSize(moduleTy));
-
- // The path to the source file where this module was declared
- SourceManager &SM = CGM.getContext().getSourceManager();
- const FileEntry *mainFile = SM.getFileEntryForID(SM.getMainFileID());
- std::string path =
- (Twine(mainFile->getDir()->getName()) + "/" + mainFile->getName()).str();
- module.add(MakeConstantString(path, ".objc_source_file_name"));
- module.add(symtab);
-
- if (RuntimeVersion >= 10) {
- switch (CGM.getLangOpts().getGC()) {
- case LangOptions::GCOnly:
- module.addInt(IntTy, 2);
- break;
- case LangOptions::NonGC:
- if (CGM.getLangOpts().ObjCAutoRefCount)
- module.addInt(IntTy, 1);
- else
- module.addInt(IntTy, 0);
- break;
- case LangOptions::HybridGC:
- module.addInt(IntTy, 1);
- break;
- }
- }
-
- return module.finishAndCreateGlobal("", CGM.getPointerAlign());
- }();
-
- // Create the load function calling the runtime entry point with the module
- // structure
- llvm::Function * LoadFunction = llvm::Function::Create(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false),
- llvm::GlobalValue::InternalLinkage, ".objc_load_function",
- &TheModule);
- llvm::BasicBlock *EntryBB =
- llvm::BasicBlock::Create(VMContext, "entry", LoadFunction);
- CGBuilderTy Builder(CGM, VMContext);
- Builder.SetInsertPoint(EntryBB);
-
- llvm::FunctionType *FT =
- llvm::FunctionType::get(Builder.getVoidTy(), module->getType(), true);
- llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class");
- Builder.CreateCall(Register, module);
-
- if (!ClassAliases.empty()) {
- llvm::Type *ArgTypes[2] = {PtrTy, PtrToInt8Ty};
- llvm::FunctionType *RegisterAliasTy =
- llvm::FunctionType::get(Builder.getVoidTy(),
- ArgTypes, false);
- llvm::Function *RegisterAlias = llvm::Function::Create(
- RegisterAliasTy,
- llvm::GlobalValue::ExternalWeakLinkage, "class_registerAlias_np",
- &TheModule);
- llvm::BasicBlock *AliasBB =
- llvm::BasicBlock::Create(VMContext, "alias", LoadFunction);
- llvm::BasicBlock *NoAliasBB =
- llvm::BasicBlock::Create(VMContext, "no_alias", LoadFunction);
-
- // Branch based on whether the runtime provided class_registerAlias_np()
- llvm::Value *HasRegisterAlias = Builder.CreateICmpNE(RegisterAlias,
- llvm::Constant::getNullValue(RegisterAlias->getType()));
- Builder.CreateCondBr(HasRegisterAlias, AliasBB, NoAliasBB);
-
- // The true branch (has alias registration function):
- Builder.SetInsertPoint(AliasBB);
- // Emit alias registration calls:
- for (std::vector<ClassAliasPair>::iterator iter = ClassAliases.begin();
- iter != ClassAliases.end(); ++iter) {
- llvm::Constant *TheClass =
- TheModule.getGlobalVariable("_OBJC_CLASS_" + iter->first, true);
- if (TheClass) {
- TheClass = llvm::ConstantExpr::getBitCast(TheClass, PtrTy);
- Builder.CreateCall(RegisterAlias,
- {TheClass, MakeConstantString(iter->second)});
- }
- }
- // Jump to end:
- Builder.CreateBr(NoAliasBB);
-
- // Missing alias registration function, just return from the function:
- Builder.SetInsertPoint(NoAliasBB);
- }
- Builder.CreateRetVoid();
-
- return LoadFunction;
-}
-
-llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) {
- const ObjCCategoryImplDecl *OCD =
- dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
- StringRef CategoryName = OCD ? OCD->getName() : "";
- StringRef ClassName = CD->getName();
- Selector MethodName = OMD->getSelector();
- bool isClassMethod = !OMD->isInstanceMethod();
-
- CodeGenTypes &Types = CGM.getTypes();
- llvm::FunctionType *MethodTy =
- Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
- std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
- MethodName, isClassMethod);
-
- llvm::Function *Method
- = llvm::Function::Create(MethodTy,
- llvm::GlobalValue::InternalLinkage,
- FunctionName,
- &TheModule);
- return Method;
-}
-
-llvm::Constant *CGObjCGNU::GetPropertyGetFunction() {
- return GetPropertyFn;
-}
-
-llvm::Constant *CGObjCGNU::GetPropertySetFunction() {
- return SetPropertyFn;
-}
-
-llvm::Constant *CGObjCGNU::GetOptimizedPropertySetFunction(bool atomic,
- bool copy) {
- return nullptr;
-}
-
-llvm::Constant *CGObjCGNU::GetGetStructFunction() {
- return GetStructPropertyFn;
-}
-
-llvm::Constant *CGObjCGNU::GetSetStructFunction() {
- return SetStructPropertyFn;
-}
-
-llvm::Constant *CGObjCGNU::GetCppAtomicObjectGetFunction() {
- return nullptr;
-}
-
-llvm::Constant *CGObjCGNU::GetCppAtomicObjectSetFunction() {
- return nullptr;
-}
-
-llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
- return EnumerationMutationFn;
-}
-
-void CGObjCGNU::EmitSynchronizedStmt(CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S) {
- EmitAtSynchronizedStmt(CGF, S, SyncEnterFn, SyncExitFn);
-}
-
-
-void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF,
- const ObjCAtTryStmt &S) {
- // Unlike the Apple non-fragile runtimes, which also uses
- // unwind-based zero cost exceptions, the GNU Objective C runtime's
- // EH support isn't a veneer over C++ EH. Instead, exception
- // objects are created by objc_exception_throw and destroyed by
- // the personality function; this avoids the need for bracketing
- // catch handlers with calls to __blah_begin_catch/__blah_end_catch
- // (or even _Unwind_DeleteException), but probably doesn't
- // interoperate very well with foreign exceptions.
- //
- // In Objective-C++ mode, we actually emit something equivalent to the C++
- // exception handler.
- EmitTryCatchStmt(CGF, S, EnterCatchFn, ExitCatchFn, ExceptionReThrowFn);
-}
-
-void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint) {
- llvm::Value *ExceptionAsObject;
- bool isRethrow = false;
-
- if (const Expr *ThrowExpr = S.getThrowExpr()) {
- llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
- ExceptionAsObject = Exception;
- } else {
- assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
- "Unexpected rethrow outside @catch block.");
- ExceptionAsObject = CGF.ObjCEHValueStack.back();
- isRethrow = true;
- }
- if (isRethrow && usesSEHExceptions) {
- // For SEH, ExceptionAsObject may be undef, because the catch handler is
- // not passed it for catchalls and so it is not visible to the catch
- // funclet. The real thrown object will still be live on the stack at this
- // point and will be rethrown. If we are explicitly rethrowing the object
- // that was passed into the `@catch` block, then this code path is not
- // reached and we will instead call `objc_exception_throw` with an explicit
- // argument.
- CGF.EmitRuntimeCallOrInvoke(ExceptionReThrowFn).setDoesNotReturn();
- }
- else {
- ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
- llvm::CallSite Throw =
- CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
- Throw.setDoesNotReturn();
- }
- CGF.Builder.CreateUnreachable();
- if (ClearInsertionPoint)
- CGF.Builder.ClearInsertionPoint();
-}
-
-llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF,
- Address AddrWeakObj) {
- CGBuilderTy &B = CGF.Builder;
- AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy);
- return B.CreateCall(WeakReadFn.getType(), WeakReadFn,
- AddrWeakObj.getPointer());
-}
-
-void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
- llvm::Value *src, Address dst) {
- CGBuilderTy &B = CGF.Builder;
- src = EnforceType(B, src, IdTy);
- dst = EnforceType(B, dst, PtrToIdTy);
- B.CreateCall(WeakAssignFn.getType(), WeakAssignFn,
- {src, dst.getPointer()});
-}
-
-void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
- llvm::Value *src, Address dst,
- bool threadlocal) {
- CGBuilderTy &B = CGF.Builder;
- src = EnforceType(B, src, IdTy);
- dst = EnforceType(B, dst, PtrToIdTy);
- // FIXME. Add threadloca assign API
- assert(!threadlocal && "EmitObjCGlobalAssign - Threal Local API NYI");
- B.CreateCall(GlobalAssignFn.getType(), GlobalAssignFn,
- {src, dst.getPointer()});
-}
-
-void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
- llvm::Value *src, Address dst,
- llvm::Value *ivarOffset) {
- CGBuilderTy &B = CGF.Builder;
- src = EnforceType(B, src, IdTy);
- dst = EnforceType(B, dst, IdTy);
- B.CreateCall(IvarAssignFn.getType(), IvarAssignFn,
- {src, dst.getPointer(), ivarOffset});
-}
-
-void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF,
- llvm::Value *src, Address dst) {
- CGBuilderTy &B = CGF.Builder;
- src = EnforceType(B, src, IdTy);
- dst = EnforceType(B, dst, PtrToIdTy);
- B.CreateCall(StrongCastAssignFn.getType(), StrongCastAssignFn,
- {src, dst.getPointer()});
-}
-
-void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF,
- Address DestPtr,
- Address SrcPtr,
- llvm::Value *Size) {
- CGBuilderTy &B = CGF.Builder;
- DestPtr = EnforceType(B, DestPtr, PtrTy);
- SrcPtr = EnforceType(B, SrcPtr, PtrTy);
-
- B.CreateCall(MemMoveFn.getType(), MemMoveFn,
- {DestPtr.getPointer(), SrcPtr.getPointer(), Size});
-}
-
-llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
- const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar) {
- const std::string Name = GetIVarOffsetVariableName(ID, Ivar);
- // Emit the variable and initialize it with what we think the correct value
- // is. This allows code compiled with non-fragile ivars to work correctly
- // when linked against code which isn't (most of the time).
- llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name);
- if (!IvarOffsetPointer)
- IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
- llvm::Type::getInt32PtrTy(VMContext), false,
- llvm::GlobalValue::ExternalLinkage, nullptr, Name);
- return IvarOffsetPointer;
-}
-
-LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) {
- const ObjCInterfaceDecl *ID =
- ObjectTy->getAs<ObjCObjectType>()->getInterface();
- return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
- EmitIvarOffset(CGF, ID, Ivar));
-}
-
-static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
- const ObjCInterfaceDecl *OID,
- const ObjCIvarDecl *OIVD) {
- for (const ObjCIvarDecl *next = OID->all_declared_ivar_begin(); next;
- next = next->getNextIvar()) {
- if (OIVD == next)
- return OID;
- }
-
- // Otherwise check in the super class.
- if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
- return FindIvarInterface(Context, Super, OIVD);
-
- return nullptr;
-}
-
-llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) {
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
-
- // The MSVC linker cannot have a single global defined as LinkOnceAnyLinkage
- // and ExternalLinkage, so create a reference to the ivar global and rely on
- // the definition being created as part of GenerateClass.
- if (RuntimeVersion < 10 ||
- CGF.CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment())
- return CGF.Builder.CreateZExtOrBitCast(
- CGF.Builder.CreateAlignedLoad(
- Int32Ty, CGF.Builder.CreateAlignedLoad(
- ObjCIvarOffsetVariable(Interface, Ivar),
- CGF.getPointerAlign(), "ivar"),
- CharUnits::fromQuantity(4)),
- PtrDiffTy);
- std::string name = "__objc_ivar_offset_value_" +
- Interface->getNameAsString() +"." + Ivar->getNameAsString();
- CharUnits Align = CGM.getIntAlign();
- llvm::Value *Offset = TheModule.getGlobalVariable(name);
- if (!Offset) {
- auto GV = new llvm::GlobalVariable(TheModule, IntTy,
- false, llvm::GlobalValue::LinkOnceAnyLinkage,
- llvm::Constant::getNullValue(IntTy), name);
- GV->setAlignment(Align.getQuantity());
- Offset = GV;
- }
- Offset = CGF.Builder.CreateAlignedLoad(Offset, Align);
- if (Offset->getType() != PtrDiffTy)
- Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy);
- return Offset;
- }
- uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
- return llvm::ConstantInt::get(PtrDiffTy, Offset, /*isSigned*/true);
-}
-
-CGObjCRuntime *
-clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) {
- auto Runtime = CGM.getLangOpts().ObjCRuntime;
- switch (Runtime.getKind()) {
- case ObjCRuntime::GNUstep:
- if (Runtime.getVersion() >= VersionTuple(2, 0))
- return new CGObjCGNUstep2(CGM);
- return new CGObjCGNUstep(CGM);
-
- case ObjCRuntime::GCC:
- return new CGObjCGCC(CGM);
-
- case ObjCRuntime::ObjFW:
- return new CGObjCObjFW(CGM);
-
- case ObjCRuntime::FragileMacOSX:
- case ObjCRuntime::MacOSX:
- case ObjCRuntime::iOS:
- case ObjCRuntime::WatchOS:
- llvm_unreachable("these runtimes are not GNU runtimes");
- }
- llvm_unreachable("bad runtime");
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
deleted file mode 100644
index d91eb43ca32..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
+++ /dev/null
@@ -1,7663 +0,0 @@
-//===------- CGObjCMac.cpp - Interface to Apple Objective-C Runtime -------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides Objective-C code generation targeting the Apple runtime.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGBlocks.h"
-#include "CGCleanup.h"
-#include "CGObjCRuntime.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/ADT/CachedHashString.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cstdio>
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-
-// FIXME: We should find a nicer way to make the labels for metadata, string
-// concatenation is lame.
-
-class ObjCCommonTypesHelper {
-protected:
- llvm::LLVMContext &VMContext;
-
-private:
- // The types of these functions don't really matter because we
- // should always bitcast before calling them.
-
- /// id objc_msgSend (id, SEL, ...)
- ///
- /// The default messenger, used for sends whose ABI is unchanged from
- /// the all-integer/pointer case.
- llvm::Constant *getMessageSendFn() const {
- // Add the non-lazy-bind attribute, since objc_msgSend is likely to
- // be called a lot.
- llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(ObjectPtrTy, params, true), "objc_msgSend",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NonLazyBind));
- }
-
- /// void objc_msgSend_stret (id, SEL, ...)
- ///
- /// The messenger used when the return value is an aggregate returned
- /// by indirect reference in the first argument, and therefore the
- /// self and selector parameters are shifted over by one.
- llvm::Constant *getMessageSendStretFn() const {
- llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
- params, true),
- "objc_msgSend_stret");
-
- }
-
- /// [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
- ///
- /// The messenger used when the return value is returned on the x87
- /// floating-point stack; without a special entrypoint, the nil case
- /// would be unbalanced.
- llvm::Constant *getMessageSendFpretFn() const {
- llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.DoubleTy,
- params, true),
- "objc_msgSend_fpret");
-
- }
-
- /// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
- ///
- /// The messenger used when the return value is returned in two values on the
- /// x87 floating point stack; without a special entrypoint, the nil case
- /// would be unbalanced. Only used on 64-bit X86.
- llvm::Constant *getMessageSendFp2retFn() const {
- llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
- llvm::Type *resultType =
- llvm::StructType::get(longDoubleType, longDoubleType);
-
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
- params, true),
- "objc_msgSend_fp2ret");
- }
-
- /// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
- ///
- /// The messenger used for super calls, which have different dispatch
- /// semantics. The class passed is the superclass of the current
- /// class.
- llvm::Constant *getMessageSendSuperFn() const {
- llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSendSuper");
- }
-
- /// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
- ///
- /// A slightly different messenger used for super calls. The class
- /// passed is the current class.
- llvm::Constant *getMessageSendSuperFn2() const {
- llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSendSuper2");
- }
-
- /// void objc_msgSendSuper_stret(void *stretAddr, struct objc_super *super,
- /// SEL op, ...)
- ///
- /// The messenger used for super calls which return an aggregate indirectly.
- llvm::Constant *getMessageSendSuperStretFn() const {
- llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGM.VoidTy, params, true),
- "objc_msgSendSuper_stret");
- }
-
- /// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
- /// SEL op, ...)
- ///
- /// objc_msgSendSuper_stret with the super2 semantics.
- llvm::Constant *getMessageSendSuperStretFn2() const {
- llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGM.VoidTy, params, true),
- "objc_msgSendSuper2_stret");
- }
-
- llvm::Constant *getMessageSendSuperFpretFn() const {
- // There is no objc_msgSendSuper_fpret? How can that work?
- return getMessageSendSuperFn();
- }
-
- llvm::Constant *getMessageSendSuperFpretFn2() const {
- // There is no objc_msgSendSuper_fpret? How can that work?
- return getMessageSendSuperFn2();
- }
-
-protected:
- CodeGen::CodeGenModule &CGM;
-
-public:
- llvm::IntegerType *ShortTy, *IntTy, *LongTy;
- llvm::PointerType *Int8PtrTy, *Int8PtrPtrTy;
- llvm::Type *IvarOffsetVarTy;
-
- /// ObjectPtrTy - LLVM type for object handles (typeof(id))
- llvm::PointerType *ObjectPtrTy;
-
- /// PtrObjectPtrTy - LLVM type for id *
- llvm::PointerType *PtrObjectPtrTy;
-
- /// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
- llvm::PointerType *SelectorPtrTy;
-
-private:
- /// ProtocolPtrTy - LLVM type for external protocol handles
- /// (typeof(Protocol))
- llvm::Type *ExternalProtocolPtrTy;
-
-public:
- llvm::Type *getExternalProtocolPtrTy() {
- if (!ExternalProtocolPtrTy) {
- // FIXME: It would be nice to unify this with the opaque type, so that the
- // IR comes out a bit cleaner.
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
- ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
- }
-
- return ExternalProtocolPtrTy;
- }
-
- // SuperCTy - clang type for struct objc_super.
- QualType SuperCTy;
- // SuperPtrCTy - clang type for struct objc_super *.
- QualType SuperPtrCTy;
-
- /// SuperTy - LLVM type for struct objc_super.
- llvm::StructType *SuperTy;
- /// SuperPtrTy - LLVM type for struct objc_super *.
- llvm::PointerType *SuperPtrTy;
-
- /// PropertyTy - LLVM type for struct objc_property (struct _prop_t
- /// in GCC parlance).
- llvm::StructType *PropertyTy;
-
- /// PropertyListTy - LLVM type for struct objc_property_list
- /// (_prop_list_t in GCC parlance).
- llvm::StructType *PropertyListTy;
- /// PropertyListPtrTy - LLVM type for struct objc_property_list*.
- llvm::PointerType *PropertyListPtrTy;
-
- // MethodTy - LLVM type for struct objc_method.
- llvm::StructType *MethodTy;
-
- /// CacheTy - LLVM type for struct objc_cache.
- llvm::Type *CacheTy;
- /// CachePtrTy - LLVM type for struct objc_cache *.
- llvm::PointerType *CachePtrTy;
-
- llvm::Constant *getGetPropertyFn() {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- // id objc_getProperty (id, SEL, ptrdiff_t, bool)
- CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
- CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
- CanQualType Params[] = {
- IdType, SelType,
- Ctx.getPointerDiffType()->getCanonicalTypeUnqualified(), Ctx.BoolTy};
- llvm::FunctionType *FTy =
- Types.GetFunctionType(
- Types.arrangeBuiltinFunctionDeclaration(IdType, Params));
- return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
- }
-
- llvm::Constant *getSetPropertyFn() {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
- CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
- CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
- CanQualType Params[] = {
- IdType,
- SelType,
- Ctx.getPointerDiffType()->getCanonicalTypeUnqualified(),
- IdType,
- Ctx.BoolTy,
- Ctx.BoolTy};
- llvm::FunctionType *FTy =
- Types.GetFunctionType(
- Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
- return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
- }
-
- llvm::Constant *getOptimizedSetPropertyFn(bool atomic, bool copy) {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- // void objc_setProperty_atomic(id self, SEL _cmd,
- // id newValue, ptrdiff_t offset);
- // void objc_setProperty_nonatomic(id self, SEL _cmd,
- // id newValue, ptrdiff_t offset);
- // void objc_setProperty_atomic_copy(id self, SEL _cmd,
- // id newValue, ptrdiff_t offset);
- // void objc_setProperty_nonatomic_copy(id self, SEL _cmd,
- // id newValue, ptrdiff_t offset);
-
- SmallVector<CanQualType,4> Params;
- CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
- CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
- Params.push_back(IdType);
- Params.push_back(SelType);
- Params.push_back(IdType);
- Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
- llvm::FunctionType *FTy =
- Types.GetFunctionType(
- Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
- const char *name;
- if (atomic && copy)
- name = "objc_setProperty_atomic_copy";
- else if (atomic && !copy)
- name = "objc_setProperty_atomic";
- else if (!atomic && copy)
- name = "objc_setProperty_nonatomic_copy";
- else
- name = "objc_setProperty_nonatomic";
-
- return CGM.CreateRuntimeFunction(FTy, name);
- }
-
- llvm::Constant *getCopyStructFn() {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- // void objc_copyStruct (void *, const void *, size_t, bool, bool)
- SmallVector<CanQualType,5> Params;
- Params.push_back(Ctx.VoidPtrTy);
- Params.push_back(Ctx.VoidPtrTy);
- Params.push_back(Ctx.getSizeType());
- Params.push_back(Ctx.BoolTy);
- Params.push_back(Ctx.BoolTy);
- llvm::FunctionType *FTy =
- Types.GetFunctionType(
- Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
- return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
- }
-
- /// This routine declares and returns address of:
- /// void objc_copyCppObjectAtomic(
- /// void *dest, const void *src,
- /// void (*copyHelper) (void *dest, const void *source));
- llvm::Constant *getCppAtomicObjectFunction() {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- /// void objc_copyCppObjectAtomic(void *dest, const void *src, void *helper);
- SmallVector<CanQualType,3> Params;
- Params.push_back(Ctx.VoidPtrTy);
- Params.push_back(Ctx.VoidPtrTy);
- Params.push_back(Ctx.VoidPtrTy);
- llvm::FunctionType *FTy =
- Types.GetFunctionType(
- Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
- return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
- }
-
- llvm::Constant *getEnumerationMutationFn() {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- // void objc_enumerationMutation (id)
- SmallVector<CanQualType,1> Params;
- Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
- llvm::FunctionType *FTy =
- Types.GetFunctionType(
- Types.arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Params));
- return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
- }
-
- llvm::Constant *getLookUpClassFn() {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- // Class objc_lookUpClass (const char *)
- SmallVector<CanQualType,1> Params;
- Params.push_back(
- Ctx.getCanonicalType(Ctx.getPointerType(Ctx.CharTy.withConst())));
- llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeBuiltinFunctionDeclaration(
- Ctx.getCanonicalType(Ctx.getObjCClassType()),
- Params));
- return CGM.CreateRuntimeFunction(FTy, "objc_lookUpClass");
- }
-
- /// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
- llvm::Constant *getGcReadWeakFn() {
- // id objc_read_weak (id *)
- llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
- }
-
- /// GcAssignWeakFn -- LLVM objc_assign_weak function.
- llvm::Constant *getGcAssignWeakFn() {
- // id objc_assign_weak (id, id *)
- llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
- }
-
- /// GcAssignGlobalFn -- LLVM objc_assign_global function.
- llvm::Constant *getGcAssignGlobalFn() {
- // id objc_assign_global(id, id *)
- llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
- }
-
- /// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
- llvm::Constant *getGcAssignThreadLocalFn() {
- // id objc_assign_threadlocal(id src, id * dest)
- llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
- }
-
- /// GcAssignIvarFn -- LLVM objc_assign_ivar function.
- llvm::Constant *getGcAssignIvarFn() {
- // id objc_assign_ivar(id, id *, ptrdiff_t)
- llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
- CGM.PtrDiffTy };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
- }
-
- /// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
- llvm::Constant *GcMemmoveCollectableFn() {
- // void *objc_memmove_collectable(void *dst, const void *src, size_t size)
- llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
- llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
- }
-
- /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
- llvm::Constant *getGcAssignStrongCastFn() {
- // id objc_assign_strongCast(id, id *)
- llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
- }
-
- /// ExceptionThrowFn - LLVM objc_exception_throw function.
- llvm::Constant *getExceptionThrowFn() {
- // void objc_exception_throw(id)
- llvm::Type *args[] = { ObjectPtrTy };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
- }
-
- /// ExceptionRethrowFn - LLVM objc_exception_rethrow function.
- llvm::Constant *getExceptionRethrowFn() {
- // void objc_exception_rethrow(void)
- llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow");
- }
-
- /// SyncEnterFn - LLVM object_sync_enter function.
- llvm::Constant *getSyncEnterFn() {
- // int objc_sync_enter (id)
- llvm::Type *args[] = { ObjectPtrTy };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.IntTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
- }
-
- /// SyncExitFn - LLVM object_sync_exit function.
- llvm::Constant *getSyncExitFn() {
- // int objc_sync_exit (id)
- llvm::Type *args[] = { ObjectPtrTy };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.IntTy, args, false);
- return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
- }
-
- llvm::Constant *getSendFn(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperFn() : getMessageSendFn();
- }
-
- llvm::Constant *getSendFn2(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperFn2() : getMessageSendFn();
- }
-
- llvm::Constant *getSendStretFn(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn();
- }
-
- llvm::Constant *getSendStretFn2(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperStretFn2() : getMessageSendStretFn();
- }
-
- llvm::Constant *getSendFpretFn(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn();
- }
-
- llvm::Constant *getSendFpretFn2(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn();
- }
-
- llvm::Constant *getSendFp2retFn(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperFn() : getMessageSendFp2retFn();
- }
-
- llvm::Constant *getSendFp2RetFn2(bool IsSuper) const {
- return IsSuper ? getMessageSendSuperFn2() : getMessageSendFp2retFn();
- }
-
- ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
-};
-
-/// ObjCTypesHelper - Helper class that encapsulates lazy
-/// construction of varies types used during ObjC generation.
-class ObjCTypesHelper : public ObjCCommonTypesHelper {
-public:
- /// SymtabTy - LLVM type for struct objc_symtab.
- llvm::StructType *SymtabTy;
- /// SymtabPtrTy - LLVM type for struct objc_symtab *.
- llvm::PointerType *SymtabPtrTy;
- /// ModuleTy - LLVM type for struct objc_module.
- llvm::StructType *ModuleTy;
-
- /// ProtocolTy - LLVM type for struct objc_protocol.
- llvm::StructType *ProtocolTy;
- /// ProtocolPtrTy - LLVM type for struct objc_protocol *.
- llvm::PointerType *ProtocolPtrTy;
- /// ProtocolExtensionTy - LLVM type for struct
- /// objc_protocol_extension.
- llvm::StructType *ProtocolExtensionTy;
- /// ProtocolExtensionTy - LLVM type for struct
- /// objc_protocol_extension *.
- llvm::PointerType *ProtocolExtensionPtrTy;
- /// MethodDescriptionTy - LLVM type for struct
- /// objc_method_description.
- llvm::StructType *MethodDescriptionTy;
- /// MethodDescriptionListTy - LLVM type for struct
- /// objc_method_description_list.
- llvm::StructType *MethodDescriptionListTy;
- /// MethodDescriptionListPtrTy - LLVM type for struct
- /// objc_method_description_list *.
- llvm::PointerType *MethodDescriptionListPtrTy;
- /// ProtocolListTy - LLVM type for struct objc_property_list.
- llvm::StructType *ProtocolListTy;
- /// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
- llvm::PointerType *ProtocolListPtrTy;
- /// CategoryTy - LLVM type for struct objc_category.
- llvm::StructType *CategoryTy;
- /// ClassTy - LLVM type for struct objc_class.
- llvm::StructType *ClassTy;
- /// ClassPtrTy - LLVM type for struct objc_class *.
- llvm::PointerType *ClassPtrTy;
- /// ClassExtensionTy - LLVM type for struct objc_class_ext.
- llvm::StructType *ClassExtensionTy;
- /// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *.
- llvm::PointerType *ClassExtensionPtrTy;
- // IvarTy - LLVM type for struct objc_ivar.
- llvm::StructType *IvarTy;
- /// IvarListTy - LLVM type for struct objc_ivar_list.
- llvm::StructType *IvarListTy;
- /// IvarListPtrTy - LLVM type for struct objc_ivar_list *.
- llvm::PointerType *IvarListPtrTy;
- /// MethodListTy - LLVM type for struct objc_method_list.
- llvm::StructType *MethodListTy;
- /// MethodListPtrTy - LLVM type for struct objc_method_list *.
- llvm::PointerType *MethodListPtrTy;
-
- /// ExceptionDataTy - LLVM type for struct _objc_exception_data.
- llvm::StructType *ExceptionDataTy;
-
- /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
- llvm::Constant *getExceptionTryEnterFn() {
- llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGM.VoidTy, params, false),
- "objc_exception_try_enter");
- }
-
- /// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
- llvm::Constant *getExceptionTryExitFn() {
- llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGM.VoidTy, params, false),
- "objc_exception_try_exit");
- }
-
- /// ExceptionExtractFn - LLVM objc_exception_extract function.
- llvm::Constant *getExceptionExtractFn() {
- llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, false),
- "objc_exception_extract");
- }
-
- /// ExceptionMatchFn - LLVM objc_exception_match function.
- llvm::Constant *getExceptionMatchFn() {
- llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGM.Int32Ty, params, false),
- "objc_exception_match");
- }
-
- /// SetJmpFn - LLVM _setjmp function.
- llvm::Constant *getSetJmpFn() {
- // This is specifically the prototype for x86.
- llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
- return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGM.Int32Ty, params, false), "_setjmp",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NonLazyBind));
- }
-
-public:
- ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
-};
-
-/// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's
-/// modern abi
-class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
-public:
- // MethodListnfABITy - LLVM for struct _method_list_t
- llvm::StructType *MethodListnfABITy;
-
- // MethodListnfABIPtrTy - LLVM for struct _method_list_t*
- llvm::PointerType *MethodListnfABIPtrTy;
-
- // ProtocolnfABITy = LLVM for struct _protocol_t
- llvm::StructType *ProtocolnfABITy;
-
- // ProtocolnfABIPtrTy = LLVM for struct _protocol_t*
- llvm::PointerType *ProtocolnfABIPtrTy;
-
- // ProtocolListnfABITy - LLVM for struct _objc_protocol_list
- llvm::StructType *ProtocolListnfABITy;
-
- // ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list*
- llvm::PointerType *ProtocolListnfABIPtrTy;
-
- // ClassnfABITy - LLVM for struct _class_t
- llvm::StructType *ClassnfABITy;
-
- // ClassnfABIPtrTy - LLVM for struct _class_t*
- llvm::PointerType *ClassnfABIPtrTy;
-
- // IvarnfABITy - LLVM for struct _ivar_t
- llvm::StructType *IvarnfABITy;
-
- // IvarListnfABITy - LLVM for struct _ivar_list_t
- llvm::StructType *IvarListnfABITy;
-
- // IvarListnfABIPtrTy = LLVM for struct _ivar_list_t*
- llvm::PointerType *IvarListnfABIPtrTy;
-
- // ClassRonfABITy - LLVM for struct _class_ro_t
- llvm::StructType *ClassRonfABITy;
-
- // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
- llvm::PointerType *ImpnfABITy;
-
- // CategorynfABITy - LLVM for struct _category_t
- llvm::StructType *CategorynfABITy;
-
- // New types for nonfragile abi messaging.
-
- // MessageRefTy - LLVM for:
- // struct _message_ref_t {
- // IMP messenger;
- // SEL name;
- // };
- llvm::StructType *MessageRefTy;
- // MessageRefCTy - clang type for struct _message_ref_t
- QualType MessageRefCTy;
-
- // MessageRefPtrTy - LLVM for struct _message_ref_t*
- llvm::Type *MessageRefPtrTy;
- // MessageRefCPtrTy - clang type for struct _message_ref_t*
- QualType MessageRefCPtrTy;
-
- // SuperMessageRefTy - LLVM for:
- // struct _super_message_ref_t {
- // SUPER_IMP messenger;
- // SEL name;
- // };
- llvm::StructType *SuperMessageRefTy;
-
- // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
- llvm::PointerType *SuperMessageRefPtrTy;
-
- llvm::Constant *getMessageSendFixupFn() {
- // id objc_msgSend_fixup(id, struct message_ref_t*, ...)
- llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSend_fixup");
- }
-
- llvm::Constant *getMessageSendFpretFixupFn() {
- // id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
- llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSend_fpret_fixup");
- }
-
- llvm::Constant *getMessageSendStretFixupFn() {
- // id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
- llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSend_stret_fixup");
- }
-
- llvm::Constant *getMessageSendSuper2FixupFn() {
- // id objc_msgSendSuper2_fixup (struct objc_super *,
- // struct _super_message_ref_t*, ...)
- llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSendSuper2_fixup");
- }
-
- llvm::Constant *getMessageSendSuper2StretFixupFn() {
- // id objc_msgSendSuper2_stret_fixup(struct objc_super *,
- // struct _super_message_ref_t*, ...)
- llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSendSuper2_stret_fixup");
- }
-
- llvm::Constant *getObjCEndCatchFn() {
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, false),
- "objc_end_catch");
-
- }
-
- llvm::Constant *getObjCBeginCatchFn() {
- llvm::Type *params[] = { Int8PtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
- params, false),
- "objc_begin_catch");
- }
-
- llvm::StructType *EHTypeTy;
- llvm::Type *EHTypePtrTy;
-
- ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
-};
-
-enum class ObjCLabelType {
- ClassName,
- MethodVarName,
- MethodVarType,
- PropertyName,
-};
-
-class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
-public:
- class SKIP_SCAN {
- public:
- unsigned skip;
- unsigned scan;
- SKIP_SCAN(unsigned _skip = 0, unsigned _scan = 0)
- : skip(_skip), scan(_scan) {}
- };
-
- /// opcode for captured block variables layout 'instructions'.
- /// In the following descriptions, 'I' is the value of the immediate field.
- /// (field following the opcode).
- ///
- enum BLOCK_LAYOUT_OPCODE {
- /// An operator which affects how the following layout should be
- /// interpreted.
- /// I == 0: Halt interpretation and treat everything else as
- /// a non-pointer. Note that this instruction is equal
- /// to '\0'.
- /// I != 0: Currently unused.
- BLOCK_LAYOUT_OPERATOR = 0,
-
- /// The next I+1 bytes do not contain a value of object pointer type.
- /// Note that this can leave the stream unaligned, meaning that
- /// subsequent word-size instructions do not begin at a multiple of
- /// the pointer size.
- BLOCK_LAYOUT_NON_OBJECT_BYTES = 1,
-
- /// The next I+1 words do not contain a value of object pointer type.
- /// This is simply an optimized version of BLOCK_LAYOUT_BYTES for
- /// when the required skip quantity is a multiple of the pointer size.
- BLOCK_LAYOUT_NON_OBJECT_WORDS = 2,
-
- /// The next I+1 words are __strong pointers to Objective-C
- /// objects or blocks.
- BLOCK_LAYOUT_STRONG = 3,
-
- /// The next I+1 words are pointers to __block variables.
- BLOCK_LAYOUT_BYREF = 4,
-
- /// The next I+1 words are __weak pointers to Objective-C
- /// objects or blocks.
- BLOCK_LAYOUT_WEAK = 5,
-
- /// The next I+1 words are __unsafe_unretained pointers to
- /// Objective-C objects or blocks.
- BLOCK_LAYOUT_UNRETAINED = 6
-
- /// The next I+1 words are block or object pointers with some
- /// as-yet-unspecified ownership semantics. If we add more
- /// flavors of ownership semantics, values will be taken from
- /// this range.
- ///
- /// This is included so that older tools can at least continue
- /// processing the layout past such things.
- //BLOCK_LAYOUT_OWNERSHIP_UNKNOWN = 7..10,
-
- /// All other opcodes are reserved. Halt interpretation and
- /// treat everything else as opaque.
- };
-
- class RUN_SKIP {
- public:
- enum BLOCK_LAYOUT_OPCODE opcode;
- CharUnits block_var_bytepos;
- CharUnits block_var_size;
- RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR,
- CharUnits BytePos = CharUnits::Zero(),
- CharUnits Size = CharUnits::Zero())
- : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {}
-
- // Allow sorting based on byte pos.
- bool operator<(const RUN_SKIP &b) const {
- return block_var_bytepos < b.block_var_bytepos;
- }
- };
-
-protected:
- llvm::LLVMContext &VMContext;
- // FIXME! May not be needing this after all.
- unsigned ObjCABI;
-
- // arc/mrr layout of captured block literal variables.
- SmallVector<RUN_SKIP, 16> RunSkipBlockVars;
-
- /// LazySymbols - Symbols to generate a lazy reference for. See
- /// DefinedSymbols and FinishModule().
- llvm::SetVector<IdentifierInfo*> LazySymbols;
-
- /// DefinedSymbols - External symbols which are defined by this
- /// module. The symbols in this list and LazySymbols are used to add
- /// special linker symbols which ensure that Objective-C modules are
- /// linked properly.
- llvm::SetVector<IdentifierInfo*> DefinedSymbols;
-
- /// ClassNames - uniqued class names.
- llvm::StringMap<llvm::GlobalVariable*> ClassNames;
-
- /// MethodVarNames - uniqued method variable names.
- llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
-
- /// DefinedCategoryNames - list of category names in form Class_Category.
- llvm::SmallSetVector<llvm::CachedHashString, 16> DefinedCategoryNames;
-
- /// MethodVarTypes - uniqued method type signatures. We have to use
- /// a StringMap here because have no other unique reference.
- llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
-
- /// MethodDefinitions - map of methods which have been defined in
- /// this translation unit.
- llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
-
- /// PropertyNames - uniqued method variable names.
- llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
-
- /// ClassReferences - uniqued class references.
- llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
-
- /// SelectorReferences - uniqued selector references.
- llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
-
- /// Protocols - Protocols for which an objc_protocol structure has
- /// been emitted. Forward declarations are handled by creating an
- /// empty structure whose initializer is filled in when/if defined.
- llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
-
- /// DefinedProtocols - Protocols which have actually been
- /// defined. We should not need this, see FIXME in GenerateProtocol.
- llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
-
- /// DefinedClasses - List of defined classes.
- SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
-
- /// ImplementedClasses - List of @implemented classes.
- SmallVector<const ObjCInterfaceDecl*, 16> ImplementedClasses;
-
- /// DefinedNonLazyClasses - List of defined "non-lazy" classes.
- SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
-
- /// DefinedCategories - List of defined categories.
- SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
-
- /// DefinedNonLazyCategories - List of defined "non-lazy" categories.
- SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
-
- /// Cached reference to the class for constant strings. This value has type
- /// int * but is actually an Obj-C class pointer.
- llvm::WeakTrackingVH ConstantStringClassRef;
-
- /// The LLVM type corresponding to NSConstantString.
- llvm::StructType *NSConstantStringType = nullptr;
-
- llvm::StringMap<llvm::GlobalVariable *> NSConstantStringMap;
-
- /// GetNameForMethod - Return a name for the given method.
- /// \param[out] NameOut - The return value.
- void GetNameForMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD,
- SmallVectorImpl<char> &NameOut);
-
- /// GetMethodVarName - Return a unique constant for the given
- /// selector's name. The return value has type char *.
- llvm::Constant *GetMethodVarName(Selector Sel);
- llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
-
- /// GetMethodVarType - Return a unique constant for the given
- /// method's type encoding string. The return value has type char *.
-
- // FIXME: This is a horrible name.
- llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D,
- bool Extended = false);
- llvm::Constant *GetMethodVarType(const FieldDecl *D);
-
- /// GetPropertyName - Return a unique constant for the given
- /// name. The return value has type char *.
- llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
-
- // FIXME: This can be dropped once string functions are unified.
- llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
- const Decl *Container);
-
- /// GetClassName - Return a unique constant for the given selector's
- /// runtime name (which may change via use of objc_runtime_name attribute on
- /// class or protocol definition. The return value has type char *.
- llvm::Constant *GetClassName(StringRef RuntimeName);
-
- llvm::Function *GetMethodDefinition(const ObjCMethodDecl *MD);
-
- /// BuildIvarLayout - Builds ivar layout bitmap for the class
- /// implementation for the __strong or __weak case.
- ///
- /// \param hasMRCWeakIvars - Whether we are compiling in MRC and there
- /// are any weak ivars defined directly in the class. Meaningless unless
- /// building a weak layout. Does not guarantee that the layout will
- /// actually have any entries, because the ivar might be under-aligned.
- llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI,
- CharUnits beginOffset,
- CharUnits endOffset,
- bool forStrongLayout,
- bool hasMRCWeakIvars);
-
- llvm::Constant *BuildStrongIvarLayout(const ObjCImplementationDecl *OI,
- CharUnits beginOffset,
- CharUnits endOffset) {
- return BuildIvarLayout(OI, beginOffset, endOffset, true, false);
- }
-
- llvm::Constant *BuildWeakIvarLayout(const ObjCImplementationDecl *OI,
- CharUnits beginOffset,
- CharUnits endOffset,
- bool hasMRCWeakIvars) {
- return BuildIvarLayout(OI, beginOffset, endOffset, false, hasMRCWeakIvars);
- }
-
- Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout);
-
- void UpdateRunSkipBlockVars(bool IsByref,
- Qualifiers::ObjCLifetime LifeTime,
- CharUnits FieldOffset,
- CharUnits FieldSize);
-
- void BuildRCBlockVarRecordLayout(const RecordType *RT,
- CharUnits BytePos, bool &HasUnion,
- bool ByrefLayout=false);
-
- void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
- const RecordDecl *RD,
- ArrayRef<const FieldDecl*> RecFields,
- CharUnits BytePos, bool &HasUnion,
- bool ByrefLayout);
-
- uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
-
- llvm::Constant *getBitmapBlockLayout(bool ComputeByrefLayout);
-
- /// GetIvarLayoutName - Returns a unique constant for the given
- /// ivar layout bitmap.
- llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident,
- const ObjCCommonTypesHelper &ObjCTypes);
-
- /// EmitPropertyList - Emit the given property list. The return
- /// value has type PropertyListPtrTy.
- llvm::Constant *EmitPropertyList(Twine Name,
- const Decl *Container,
- const ObjCContainerDecl *OCD,
- const ObjCCommonTypesHelper &ObjCTypes,
- bool IsClassProperty);
-
- /// EmitProtocolMethodTypes - Generate the array of extended method type
- /// strings. The return value has type Int8PtrPtrTy.
- llvm::Constant *EmitProtocolMethodTypes(Twine Name,
- ArrayRef<llvm::Constant*> MethodTypes,
- const ObjCCommonTypesHelper &ObjCTypes);
-
- /// GetProtocolRef - Return a reference to the internal protocol
- /// description, creating an empty one if it has not been
- /// defined. The return value has type ProtocolPtrTy.
- llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
-
- /// Return a reference to the given Class using runtime calls rather than
- /// by a symbol reference.
- llvm::Value *EmitClassRefViaRuntime(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID,
- ObjCCommonTypesHelper &ObjCTypes);
-
- std::string GetSectionName(StringRef Section, StringRef MachOAttributes);
-
-public:
- /// CreateMetadataVar - Create a global variable with internal
- /// linkage for use by the Objective-C runtime.
- ///
- /// This is a convenience wrapper which not only creates the
- /// variable, but also sets the section and alignment and adds the
- /// global to the "llvm.used" list.
- ///
- /// \param Name - The variable name.
- /// \param Init - The variable initializer; this is also used to
- /// define the type of the variable.
- /// \param Section - The section the variable should go into, or empty.
- /// \param Align - The alignment for the variable, or 0.
- /// \param AddToUsed - Whether the variable should be added to
- /// "llvm.used".
- llvm::GlobalVariable *CreateMetadataVar(Twine Name,
- ConstantStructBuilder &Init,
- StringRef Section, CharUnits Align,
- bool AddToUsed);
- llvm::GlobalVariable *CreateMetadataVar(Twine Name,
- llvm::Constant *Init,
- StringRef Section, CharUnits Align,
- bool AddToUsed);
-
- llvm::GlobalVariable *CreateCStringLiteral(StringRef Name,
- ObjCLabelType LabelType,
- bool ForceNonFragileABI = false,
- bool NullTerminate = true);
-
-protected:
- CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- llvm::Value *Sel,
- llvm::Value *Arg0,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *OMD,
- const ObjCInterfaceDecl *ClassReceiver,
- const ObjCCommonTypesHelper &ObjCTypes);
-
- /// EmitImageInfo - Emit the image info marker used to encode some module
- /// level information.
- void EmitImageInfo();
-
-public:
- CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
- CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) { }
-
- bool isNonFragileABI() const {
- return ObjCABI == 2;
- }
-
- ConstantAddress GenerateConstantString(const StringLiteral *SL) override;
- ConstantAddress GenerateConstantNSString(const StringLiteral *SL);
-
- llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD=nullptr) override;
-
- void GenerateProtocol(const ObjCProtocolDecl *PD) override;
-
- /// GetOrEmitProtocol - Get the protocol object for the given
- /// declaration, emitting it if necessary. The return value has type
- /// ProtocolPtrTy.
- virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD)=0;
-
- /// GetOrEmitProtocolRef - Get a forward reference to the protocol
- /// object for the given declaration, emitting it if needed. These
- /// forward references will be filled in with empty bodies if no
- /// definition is seen. The return value has type ProtocolPtrTy.
- virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
-
- virtual llvm::Constant *getNSConstantStringClassRef() = 0;
-
- llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) override;
- llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) override;
- std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) override;
-
- llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
- QualType T) override;
-
-private:
- void fillRunSkipBlockVars(CodeGenModule &CGM, const CGBlockInfo &blockInfo);
-};
-
-namespace {
-
-enum class MethodListType {
- CategoryInstanceMethods,
- CategoryClassMethods,
- InstanceMethods,
- ClassMethods,
- ProtocolInstanceMethods,
- ProtocolClassMethods,
- OptionalProtocolInstanceMethods,
- OptionalProtocolClassMethods,
-};
-
-/// A convenience class for splitting the methods of a protocol into
-/// the four interesting groups.
-class ProtocolMethodLists {
-public:
- enum Kind {
- RequiredInstanceMethods,
- RequiredClassMethods,
- OptionalInstanceMethods,
- OptionalClassMethods
- };
- enum {
- NumProtocolMethodLists = 4
- };
-
- static MethodListType getMethodListKind(Kind kind) {
- switch (kind) {
- case RequiredInstanceMethods:
- return MethodListType::ProtocolInstanceMethods;
- case RequiredClassMethods:
- return MethodListType::ProtocolClassMethods;
- case OptionalInstanceMethods:
- return MethodListType::OptionalProtocolInstanceMethods;
- case OptionalClassMethods:
- return MethodListType::OptionalProtocolClassMethods;
- }
- llvm_unreachable("bad kind");
- }
-
- SmallVector<const ObjCMethodDecl *, 4> Methods[NumProtocolMethodLists];
-
- static ProtocolMethodLists get(const ObjCProtocolDecl *PD) {
- ProtocolMethodLists result;
-
- for (auto MD : PD->methods()) {
- size_t index = (2 * size_t(MD->isOptional()))
- + (size_t(MD->isClassMethod()));
- result.Methods[index].push_back(MD);
- }
-
- return result;
- }
-
- template <class Self>
- SmallVector<llvm::Constant*, 8> emitExtendedTypesArray(Self *self) const {
- // In both ABIs, the method types list is parallel with the
- // concatenation of the methods arrays in the following order:
- // instance methods
- // class methods
- // optional instance methods
- // optional class methods
- SmallVector<llvm::Constant*, 8> result;
-
- // Methods is already in the correct order for both ABIs.
- for (auto &list : Methods) {
- for (auto MD : list) {
- result.push_back(self->GetMethodVarType(MD, true));
- }
- }
-
- return result;
- }
-
- template <class Self>
- llvm::Constant *emitMethodList(Self *self, const ObjCProtocolDecl *PD,
- Kind kind) const {
- return self->emitMethodList(PD->getObjCRuntimeNameAsString(),
- getMethodListKind(kind), Methods[kind]);
- }
-};
-
-} // end anonymous namespace
-
-class CGObjCMac : public CGObjCCommonMac {
-private:
- friend ProtocolMethodLists;
-
- ObjCTypesHelper ObjCTypes;
-
- /// EmitModuleInfo - Another marker encoding module level
- /// information.
- void EmitModuleInfo();
-
- /// EmitModuleSymols - Emit module symbols, the list of defined
- /// classes and categories. The result has type SymtabPtrTy.
- llvm::Constant *EmitModuleSymbols();
-
- /// FinishModule - Write out global data structures at the end of
- /// processing a translation unit.
- void FinishModule();
-
- /// EmitClassExtension - Generate the class extension structure used
- /// to store the weak ivar layout and properties. The return value
- /// has type ClassExtensionPtrTy.
- llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID,
- CharUnits instanceSize,
- bool hasMRCWeakIvars,
- bool isMetaclass);
-
- /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
- /// for the given class.
- llvm::Value *EmitClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID);
-
- llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
- IdentifierInfo *II);
-
- llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
-
- /// EmitSuperClassRef - Emits reference to class's main metadata class.
- llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
-
- /// EmitIvarList - Emit the ivar list for the given
- /// implementation. If ForClass is true the list of class ivars
- /// (i.e. metaclass ivars) is emitted, otherwise the list of
- /// interface ivars will be emitted. The return value has type
- /// IvarListPtrTy.
- llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID,
- bool ForClass);
-
- /// EmitMetaClass - Emit a forward reference to the class structure
- /// for the metaclass of the given interface. The return value has
- /// type ClassPtrTy.
- llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);
-
- /// EmitMetaClass - Emit a class structure for the metaclass of the
- /// given implementation. The return value has type ClassPtrTy.
- llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
- llvm::Constant *Protocols,
- ArrayRef<const ObjCMethodDecl *> Methods);
-
- void emitMethodConstant(ConstantArrayBuilder &builder,
- const ObjCMethodDecl *MD);
-
- void emitMethodDescriptionConstant(ConstantArrayBuilder &builder,
- const ObjCMethodDecl *MD);
-
- /// EmitMethodList - Emit the method list for the given
- /// implementation. The return value has type MethodListPtrTy.
- llvm::Constant *emitMethodList(Twine Name, MethodListType MLT,
- ArrayRef<const ObjCMethodDecl *> Methods);
-
- /// GetOrEmitProtocol - Get the protocol object for the given
- /// declaration, emitting it if necessary. The return value has type
- /// ProtocolPtrTy.
- llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
-
- /// GetOrEmitProtocolRef - Get a forward reference to the protocol
- /// object for the given declaration, emitting it if needed. These
- /// forward references will be filled in with empty bodies if no
- /// definition is seen. The return value has type ProtocolPtrTy.
- llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
-
- /// EmitProtocolExtension - Generate the protocol extension
- /// structure used to store optional instance and class methods, and
- /// protocol properties. The return value has type
- /// ProtocolExtensionPtrTy.
- llvm::Constant *
- EmitProtocolExtension(const ObjCProtocolDecl *PD,
- const ProtocolMethodLists &methodLists);
-
- /// EmitProtocolList - Generate the list of referenced
- /// protocols. The return value has type ProtocolListPtrTy.
- llvm::Constant *EmitProtocolList(Twine Name,
- ObjCProtocolDecl::protocol_iterator begin,
- ObjCProtocolDecl::protocol_iterator end);
-
- /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
- /// for the given selector.
- llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
- Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel);
-
-public:
- CGObjCMac(CodeGen::CodeGenModule &cgm);
-
- llvm::Constant *getNSConstantStringClassRef() override;
-
- llvm::Function *ModuleInitFunction() override;
-
- CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel, llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method) override;
-
- CodeGen::RValue
- GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return, QualType ResultType,
- Selector Sel, const ObjCInterfaceDecl *Class,
- bool isCategoryImpl, llvm::Value *Receiver,
- bool IsClassMessage, const CallArgList &CallArgs,
- const ObjCMethodDecl *Method) override;
-
- llvm::Value *GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) override;
-
- llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override;
- Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override;
-
- /// The NeXT/Apple runtimes do not support typed selectors; just emit an
- /// untyped one.
- llvm::Value *GetSelector(CodeGenFunction &CGF,
- const ObjCMethodDecl *Method) override;
-
- llvm::Constant *GetEHType(QualType T) override;
-
- void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
-
- void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
-
- void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
-
- llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD) override;
-
- llvm::Constant *GetPropertyGetFunction() override;
- llvm::Constant *GetPropertySetFunction() override;
- llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy) override;
- llvm::Constant *GetGetStructFunction() override;
- llvm::Constant *GetSetStructFunction() override;
- llvm::Constant *GetCppAtomicObjectGetFunction() override;
- llvm::Constant *GetCppAtomicObjectSetFunction() override;
- llvm::Constant *EnumerationMutationFunction() override;
-
- void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtTryStmt &S) override;
- void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S) override;
- void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S);
- void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint=true) override;
- llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- Address AddrWeakObj) override;
- void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst) override;
- void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest,
- bool threadlocal = false) override;
- void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest,
- llvm::Value *ivarOffset) override;
- void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest) override;
- void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- Address dest, Address src,
- llvm::Value *size) override;
-
- LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
- llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) override;
- llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) override;
-};
-
-class CGObjCNonFragileABIMac : public CGObjCCommonMac {
-private:
- friend ProtocolMethodLists;
- ObjCNonFragileABITypesHelper ObjCTypes;
- llvm::GlobalVariable* ObjCEmptyCacheVar;
- llvm::Constant* ObjCEmptyVtableVar;
-
- /// SuperClassReferences - uniqued super class references.
- llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> SuperClassReferences;
-
- /// MetaClassReferences - uniqued meta class references.
- llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> MetaClassReferences;
-
- /// EHTypeReferences - uniqued class ehtype references.
- llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
-
- /// VTableDispatchMethods - List of methods for which we generate
- /// vtable-based message dispatch.
- llvm::DenseSet<Selector> VTableDispatchMethods;
-
- /// DefinedMetaClasses - List of defined meta-classes.
- std::vector<llvm::GlobalValue*> DefinedMetaClasses;
-
- /// isVTableDispatchedSelector - Returns true if SEL is a
- /// vtable-based selector.
- bool isVTableDispatchedSelector(Selector Sel);
-
- /// FinishNonFragileABIModule - Write out global data structures at the end of
- /// processing a translation unit.
- void FinishNonFragileABIModule();
-
- /// AddModuleClassList - Add the given list of class pointers to the
- /// module with the provided symbol and section names.
- void AddModuleClassList(ArrayRef<llvm::GlobalValue *> Container,
- StringRef SymbolName, StringRef SectionName);
-
- llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags,
- unsigned InstanceStart,
- unsigned InstanceSize,
- const ObjCImplementationDecl *ID);
- llvm::GlobalVariable *BuildClassObject(const ObjCInterfaceDecl *CI,
- bool isMetaclass,
- llvm::Constant *IsAGV,
- llvm::Constant *SuperClassGV,
- llvm::Constant *ClassRoGV,
- bool HiddenVisibility);
-
- void emitMethodConstant(ConstantArrayBuilder &builder,
- const ObjCMethodDecl *MD,
- bool forProtocol);
-
- /// Emit the method list for the given implementation. The return value
- /// has type MethodListnfABITy.
- llvm::Constant *emitMethodList(Twine Name, MethodListType MLT,
- ArrayRef<const ObjCMethodDecl *> Methods);
-
- /// EmitIvarList - Emit the ivar list for the given
- /// implementation. If ForClass is true the list of class ivars
- /// (i.e. metaclass ivars) is emitted, otherwise the list of
- /// interface ivars will be emitted. The return value has type
- /// IvarListnfABIPtrTy.
- llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID);
-
- llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar,
- unsigned long int offset);
-
- /// GetOrEmitProtocol - Get the protocol object for the given
- /// declaration, emitting it if necessary. The return value has type
- /// ProtocolPtrTy.
- llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
-
- /// GetOrEmitProtocolRef - Get a forward reference to the protocol
- /// object for the given declaration, emitting it if needed. These
- /// forward references will be filled in with empty bodies if no
- /// definition is seen. The return value has type ProtocolPtrTy.
- llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
-
- /// EmitProtocolList - Generate the list of referenced
- /// protocols. The return value has type ProtocolListPtrTy.
- llvm::Constant *EmitProtocolList(Twine Name,
- ObjCProtocolDecl::protocol_iterator begin,
- ObjCProtocolDecl::protocol_iterator end);
-
- CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method);
-
- /// GetClassGlobal - Return the global variable for the Objective-C
- /// class of the given name.
- llvm::Constant *GetClassGlobal(StringRef Name,
- ForDefinition_t IsForDefinition,
- bool Weak = false, bool DLLImport = false);
- llvm::Constant *GetClassGlobal(const ObjCInterfaceDecl *ID,
- bool isMetaclass,
- ForDefinition_t isForDefinition);
-
- /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
- /// for the given class reference.
- llvm::Value *EmitClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID);
-
- llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
- IdentifierInfo *II,
- const ObjCInterfaceDecl *ID);
-
- llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
-
- /// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
- /// for the given super class reference.
- llvm::Value *EmitSuperClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID);
-
- /// EmitMetaClassRef - Return a Value * of the address of _class_t
- /// meta-data
- llvm::Value *EmitMetaClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID, bool Weak);
-
- /// ObjCIvarOffsetVariable - Returns the ivar offset variable for
- /// the given ivar.
- ///
- llvm::GlobalVariable * ObjCIvarOffsetVariable(
- const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar);
-
- /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
- /// for the given selector.
- llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
- Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel);
-
- /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
- /// interface. The return value has type EHTypePtrTy.
- llvm::Constant *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
- ForDefinition_t IsForDefinition);
-
- StringRef getMetaclassSymbolPrefix() const { return "OBJC_METACLASS_$_"; }
-
- StringRef getClassSymbolPrefix() const { return "OBJC_CLASS_$_"; }
-
- void GetClassSizeInfo(const ObjCImplementationDecl *OID,
- uint32_t &InstanceStart,
- uint32_t &InstanceSize);
-
- // Shamelessly stolen from Analysis/CFRefCount.cpp
- Selector GetNullarySelector(const char* name) const {
- IdentifierInfo* II = &CGM.getContext().Idents.get(name);
- return CGM.getContext().Selectors.getSelector(0, &II);
- }
-
- Selector GetUnarySelector(const char* name) const {
- IdentifierInfo* II = &CGM.getContext().Idents.get(name);
- return CGM.getContext().Selectors.getSelector(1, &II);
- }
-
- /// ImplementationIsNonLazy - Check whether the given category or
- /// class implementation is "non-lazy".
- bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
-
- bool IsIvarOffsetKnownIdempotent(const CodeGen::CodeGenFunction &CGF,
- const ObjCIvarDecl *IV) {
- // Annotate the load as an invariant load iff inside an instance method
- // and ivar belongs to instance method's class and one of its super class.
- // This check is needed because the ivar offset is a lazily
- // initialised value that may depend on objc_msgSend to perform a fixup on
- // the first message dispatch.
- //
- // An additional opportunity to mark the load as invariant arises when the
- // base of the ivar access is a parameter to an Objective C method.
- // However, because the parameters are not available in the current
- // interface, we cannot perform this check.
- if (const ObjCMethodDecl *MD =
- dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
- if (MD->isInstanceMethod())
- if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
- return IV->getContainingInterface()->isSuperClassOf(ID);
- return false;
- }
-
-public:
- CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
-
- llvm::Constant *getNSConstantStringClassRef() override;
-
- llvm::Function *ModuleInitFunction() override;
-
- CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType, Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method) override;
-
- CodeGen::RValue
- GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return, QualType ResultType,
- Selector Sel, const ObjCInterfaceDecl *Class,
- bool isCategoryImpl, llvm::Value *Receiver,
- bool IsClassMessage, const CallArgList &CallArgs,
- const ObjCMethodDecl *Method) override;
-
- llvm::Value *GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) override;
-
- llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override
- { return EmitSelector(CGF, Sel); }
- Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override
- { return EmitSelectorAddr(CGF, Sel); }
-
- /// The NeXT/Apple runtimes do not support typed selectors; just emit an
- /// untyped one.
- llvm::Value *GetSelector(CodeGenFunction &CGF,
- const ObjCMethodDecl *Method) override
- { return EmitSelector(CGF, Method->getSelector()); }
-
- void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
-
- void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
-
- void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
-
- llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD) override;
-
- llvm::Constant *GetEHType(QualType T) override;
-
- llvm::Constant *GetPropertyGetFunction() override {
- return ObjCTypes.getGetPropertyFn();
- }
- llvm::Constant *GetPropertySetFunction() override {
- return ObjCTypes.getSetPropertyFn();
- }
-
- llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy) override {
- return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
- }
-
- llvm::Constant *GetSetStructFunction() override {
- return ObjCTypes.getCopyStructFn();
- }
-
- llvm::Constant *GetGetStructFunction() override {
- return ObjCTypes.getCopyStructFn();
- }
-
- llvm::Constant *GetCppAtomicObjectSetFunction() override {
- return ObjCTypes.getCppAtomicObjectFunction();
- }
-
- llvm::Constant *GetCppAtomicObjectGetFunction() override {
- return ObjCTypes.getCppAtomicObjectFunction();
- }
-
- llvm::Constant *EnumerationMutationFunction() override {
- return ObjCTypes.getEnumerationMutationFn();
- }
-
- void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtTryStmt &S) override;
- void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S) override;
- void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint=true) override;
- llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- Address AddrWeakObj) override;
- void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address edst) override;
- void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest,
- bool threadlocal = false) override;
- void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest,
- llvm::Value *ivarOffset) override;
- void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest) override;
- void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- Address dest, Address src,
- llvm::Value *size) override;
- LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
- llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) override;
- llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) override;
-};
-
-/// A helper class for performing the null-initialization of a return
-/// value.
-struct NullReturnState {
- llvm::BasicBlock *NullBB;
- NullReturnState() : NullBB(nullptr) {}
-
- /// Perform a null-check of the given receiver.
- void init(CodeGenFunction &CGF, llvm::Value *receiver) {
- // Make blocks for the null-receiver and call edges.
- NullBB = CGF.createBasicBlock("msgSend.null-receiver");
- llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
-
- // Check for a null receiver and, if there is one, jump to the
- // null-receiver block. There's no point in trying to avoid it:
- // we're always going to put *something* there, because otherwise
- // we shouldn't have done this null-check in the first place.
- llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
- CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
-
- // Otherwise, start performing the call.
- CGF.EmitBlock(callBB);
- }
-
- /// Complete the null-return operation. It is valid to call this
- /// regardless of whether 'init' has been called.
- RValue complete(CodeGenFunction &CGF,
- ReturnValueSlot returnSlot,
- RValue result,
- QualType resultType,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method) {
- // If we never had to do a null-check, just use the raw result.
- if (!NullBB) return result;
-
- // The continuation block. This will be left null if we don't have an
- // IP, which can happen if the method we're calling is marked noreturn.
- llvm::BasicBlock *contBB = nullptr;
-
- // Finish the call path.
- llvm::BasicBlock *callBB = CGF.Builder.GetInsertBlock();
- if (callBB) {
- contBB = CGF.createBasicBlock("msgSend.cont");
- CGF.Builder.CreateBr(contBB);
- }
-
- // Okay, start emitting the null-receiver block.
- CGF.EmitBlock(NullBB);
-
- // Release any consumed arguments we've got.
- if (Method) {
- CallArgList::const_iterator I = CallArgs.begin();
- for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
- e = Method->param_end(); i != e; ++i, ++I) {
- const ParmVarDecl *ParamDecl = (*i);
- if (ParamDecl->hasAttr<NSConsumedAttr>()) {
- RValue RV = I->getRValue(CGF);
- assert(RV.isScalar() &&
- "NullReturnState::complete - arg not on object");
- CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime);
- }
- }
- }
-
- // The phi code below assumes that we haven't needed any control flow yet.
- assert(CGF.Builder.GetInsertBlock() == NullBB);
-
- // If we've got a void return, just jump to the continuation block.
- if (result.isScalar() && resultType->isVoidType()) {
- // No jumps required if the message-send was noreturn.
- if (contBB) CGF.EmitBlock(contBB);
- return result;
- }
-
- // If we've got a scalar return, build a phi.
- if (result.isScalar()) {
- // Derive the null-initialization value.
- llvm::Constant *null = CGF.CGM.EmitNullConstant(resultType);
-
- // If no join is necessary, just flow out.
- if (!contBB) return RValue::get(null);
-
- // Otherwise, build a phi.
- CGF.EmitBlock(contBB);
- llvm::PHINode *phi = CGF.Builder.CreatePHI(null->getType(), 2);
- phi->addIncoming(result.getScalarVal(), callBB);
- phi->addIncoming(null, NullBB);
- return RValue::get(phi);
- }
-
- // If we've got an aggregate return, null the buffer out.
- // FIXME: maybe we should be doing things differently for all the
- // cases where the ABI has us returning (1) non-agg values in
- // memory or (2) agg values in registers.
- if (result.isAggregate()) {
- assert(result.isAggregate() && "null init of non-aggregate result?");
- if (!returnSlot.isUnused())
- CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
- if (contBB) CGF.EmitBlock(contBB);
- return result;
- }
-
- // Complex types.
- CGF.EmitBlock(contBB);
- CodeGenFunction::ComplexPairTy callResult = result.getComplexVal();
-
- // Find the scalar type and its zero value.
- llvm::Type *scalarTy = callResult.first->getType();
- llvm::Constant *scalarZero = llvm::Constant::getNullValue(scalarTy);
-
- // Build phis for both coordinates.
- llvm::PHINode *real = CGF.Builder.CreatePHI(scalarTy, 2);
- real->addIncoming(callResult.first, callBB);
- real->addIncoming(scalarZero, NullBB);
- llvm::PHINode *imag = CGF.Builder.CreatePHI(scalarTy, 2);
- imag->addIncoming(callResult.second, callBB);
- imag->addIncoming(scalarZero, NullBB);
- return RValue::getComplex(real, imag);
- }
-};
-
-} // end anonymous namespace
-
-/* *** Helper Functions *** */
-
-/// getConstantGEP() - Help routine to construct simple GEPs.
-static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext,
- llvm::GlobalVariable *C, unsigned idx0,
- unsigned idx1) {
- llvm::Value *Idxs[] = {
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0),
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1)
- };
- return llvm::ConstantExpr::getGetElementPtr(C->getValueType(), C, Idxs);
-}
-
-/// hasObjCExceptionAttribute - Return true if this class or any super
-/// class has the __objc_exception__ attribute.
-static bool hasObjCExceptionAttribute(ASTContext &Context,
- const ObjCInterfaceDecl *OID) {
- if (OID->hasAttr<ObjCExceptionAttr>())
- return true;
- if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
- return hasObjCExceptionAttribute(Context, Super);
- return false;
-}
-
-/* *** CGObjCMac Public Interface *** */
-
-CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
- ObjCTypes(cgm) {
- ObjCABI = 1;
- EmitImageInfo();
-}
-
-/// GetClass - Return a reference to the class for the given interface
-/// decl.
-llvm::Value *CGObjCMac::GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) {
- return EmitClassRef(CGF, ID);
-}
-
-/// GetSelector - Return the pointer to the unique'd string for this selector.
-llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel) {
- return EmitSelector(CGF, Sel);
-}
-Address CGObjCMac::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) {
- return EmitSelectorAddr(CGF, Sel);
-}
-llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
- *Method) {
- return EmitSelector(CGF, Method->getSelector());
-}
-
-llvm::Constant *CGObjCMac::GetEHType(QualType T) {
- if (T->isObjCIdType() ||
- T->isObjCQualifiedIdType()) {
- return CGM.GetAddrOfRTTIDescriptor(
- CGM.getContext().getObjCIdRedefinitionType(), /*ForEH=*/true);
- }
- if (T->isObjCClassType() ||
- T->isObjCQualifiedClassType()) {
- return CGM.GetAddrOfRTTIDescriptor(
- CGM.getContext().getObjCClassRedefinitionType(), /*ForEH=*/true);
- }
- if (T->isObjCObjectPointerType())
- return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true);
-
- llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
-}
-
-/// Generate a constant CFString object.
-/*
- struct __builtin_CFString {
- const int *isa; // point to __CFConstantStringClassReference
- int flags;
- const char *str;
- long length;
- };
-*/
-
-/// or Generate a constant NSString object.
-/*
- struct __builtin_NSString {
- const int *isa; // point to __NSConstantStringClassReference
- const char *str;
- unsigned int length;
- };
-*/
-
-ConstantAddress
-CGObjCCommonMac::GenerateConstantString(const StringLiteral *SL) {
- return (!CGM.getLangOpts().NoConstantCFStrings
- ? CGM.GetAddrOfConstantCFString(SL)
- : GenerateConstantNSString(SL));
-}
-
-static llvm::StringMapEntry<llvm::GlobalVariable *> &
-GetConstantStringEntry(llvm::StringMap<llvm::GlobalVariable *> &Map,
- const StringLiteral *Literal, unsigned &StringLength) {
- StringRef String = Literal->getString();
- StringLength = String.size();
- return *Map.insert(std::make_pair(String, nullptr)).first;
-}
-
-llvm::Constant *CGObjCMac::getNSConstantStringClassRef() {
- if (llvm::Value *V = ConstantStringClassRef)
- return cast<llvm::Constant>(V);
-
- auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass;
- std::string str =
- StringClass.empty() ? "_NSConstantStringClassReference"
- : "_" + StringClass + "ClassReference";
-
- llvm::Type *PTy = llvm::ArrayType::get(CGM.IntTy, 0);
- auto GV = CGM.CreateRuntimeVariable(PTy, str);
- auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo());
- ConstantStringClassRef = V;
- return V;
-}
-
-llvm::Constant *CGObjCNonFragileABIMac::getNSConstantStringClassRef() {
- if (llvm::Value *V = ConstantStringClassRef)
- return cast<llvm::Constant>(V);
-
- auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass;
- std::string str =
- StringClass.empty() ? "OBJC_CLASS_$_NSConstantString"
- : "OBJC_CLASS_$_" + StringClass;
- auto GV = GetClassGlobal(str, NotForDefinition);
-
- // Make sure the result is of the correct type.
- auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo());
-
- ConstantStringClassRef = V;
- return V;
-}
-
-ConstantAddress
-CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) {
- unsigned StringLength = 0;
- llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
- GetConstantStringEntry(NSConstantStringMap, Literal, StringLength);
-
- if (auto *C = Entry.second)
- return ConstantAddress(C, CharUnits::fromQuantity(C->getAlignment()));
-
- // If we don't already have it, get _NSConstantStringClassReference.
- llvm::Constant *Class = getNSConstantStringClassRef();
-
- // If we don't already have it, construct the type for a constant NSString.
- if (!NSConstantStringType) {
- NSConstantStringType =
- llvm::StructType::create({
- CGM.Int32Ty->getPointerTo(),
- CGM.Int8PtrTy,
- CGM.IntTy
- }, "struct.__builtin_NSString");
- }
-
- ConstantInitBuilder Builder(CGM);
- auto Fields = Builder.beginStruct(NSConstantStringType);
-
- // Class pointer.
- Fields.add(Class);
-
- // String pointer.
- llvm::Constant *C =
- llvm::ConstantDataArray::getString(VMContext, Entry.first());
-
- llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::PrivateLinkage;
- bool isConstant = !CGM.getLangOpts().WritableStrings;
-
- auto *GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), isConstant,
- Linkage, C, ".str");
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- // Don't enforce the target's minimum global alignment, since the only use
- // of the string is via this class initializer.
- GV->setAlignment(1);
- Fields.addBitCast(GV, CGM.Int8PtrTy);
-
- // String length.
- Fields.addInt(CGM.IntTy, StringLength);
-
- // The struct.
- CharUnits Alignment = CGM.getPointerAlign();
- GV = Fields.finishAndCreateGlobal("_unnamed_nsstring_", Alignment,
- /*constant*/ true,
- llvm::GlobalVariable::PrivateLinkage);
- const char *NSStringSection = "__OBJC,__cstring_object,regular,no_dead_strip";
- const char *NSStringNonFragileABISection =
- "__DATA,__objc_stringobj,regular,no_dead_strip";
- // FIXME. Fix section.
- GV->setSection(CGM.getLangOpts().ObjCRuntime.isNonFragile()
- ? NSStringNonFragileABISection
- : NSStringSection);
- Entry.second = GV;
-
- return ConstantAddress(GV, Alignment);
-}
-
-enum {
- kCFTaggedObjectID_Integer = (1 << 1) + 1
-};
-
-/// Generates a message send where the super is the receiver. This is
-/// a message send to self with special delivery semantics indicating
-/// which class's method should be called.
-CodeGen::RValue
-CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- const ObjCInterfaceDecl *Class,
- bool isCategoryImpl,
- llvm::Value *Receiver,
- bool IsClassMessage,
- const CodeGen::CallArgList &CallArgs,
- const ObjCMethodDecl *Method) {
- // Create and init a super structure; this is a (receiver, class)
- // pair we will pass to objc_msgSendSuper.
- Address ObjCSuper =
- CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
- "objc_super");
- llvm::Value *ReceiverAsObject =
- CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateStore(
- ReceiverAsObject,
- CGF.Builder.CreateStructGEP(ObjCSuper, 0, CharUnits::Zero()));
-
- // If this is a class message the metaclass is passed as the target.
- llvm::Value *Target;
- if (IsClassMessage) {
- if (isCategoryImpl) {
- // Message sent to 'super' in a class method defined in a category
- // implementation requires an odd treatment.
- // If we are in a class method, we must retrieve the
- // _metaclass_ for the current class, pointed at by
- // the class's "isa" pointer. The following assumes that
- // isa" is the first ivar in a class (which it must be).
- Target = EmitClassRef(CGF, Class->getSuperClass());
- Target = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, Target, 0);
- Target = CGF.Builder.CreateAlignedLoad(Target, CGF.getPointerAlign());
- } else {
- llvm::Constant *MetaClassPtr = EmitMetaClassRef(Class);
- llvm::Value *SuperPtr =
- CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, MetaClassPtr, 1);
- llvm::Value *Super =
- CGF.Builder.CreateAlignedLoad(SuperPtr, CGF.getPointerAlign());
- Target = Super;
- }
- } else if (isCategoryImpl)
- Target = EmitClassRef(CGF, Class->getSuperClass());
- else {
- llvm::Value *ClassPtr = EmitSuperClassRef(Class);
- ClassPtr = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, ClassPtr, 1);
- Target = CGF.Builder.CreateAlignedLoad(ClassPtr, CGF.getPointerAlign());
- }
- // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
- // ObjCTypes types.
- llvm::Type *ClassTy =
- CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
- Target = CGF.Builder.CreateBitCast(Target, ClassTy);
- CGF.Builder.CreateStore(Target,
- CGF.Builder.CreateStructGEP(ObjCSuper, 1, CGF.getPointerSize()));
- return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, Class, ObjCTypes);
-}
-
-/// Generate code for a message send expression.
-CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method) {
- return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, Class, ObjCTypes);
-}
-
-static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) {
- do {
- if (ID->isWeakImported())
- return true;
- } while ((ID = ID->getSuperClass()));
-
- return false;
-}
-
-CodeGen::RValue
-CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- llvm::Value *Sel,
- llvm::Value *Arg0,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method,
- const ObjCInterfaceDecl *ClassReceiver,
- const ObjCCommonTypesHelper &ObjCTypes) {
- CallArgList ActualArgs;
- if (!IsSuper)
- Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
- ActualArgs.add(RValue::get(Arg0), Arg0Ty);
- ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
- ActualArgs.addFrom(CallArgs);
-
- // If we're calling a method, use the formal signature.
- MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
-
- if (Method)
- assert(CGM.getContext().getCanonicalType(Method->getReturnType()) ==
- CGM.getContext().getCanonicalType(ResultType) &&
- "Result type mismatch!");
-
- bool ReceiverCanBeNull = true;
-
- // Super dispatch assumes that self is non-null; even the messenger
- // doesn't have a null check internally.
- if (IsSuper) {
- ReceiverCanBeNull = false;
-
- // If this is a direct dispatch of a class method, check whether the class,
- // or anything in its hierarchy, was weak-linked.
- } else if (ClassReceiver && Method && Method->isClassMethod()) {
- ReceiverCanBeNull = isWeakLinkedClass(ClassReceiver);
-
- // If we're emitting a method, and self is const (meaning just ARC, for now),
- // and the receiver is a load of self, then self is a valid object.
- } else if (auto CurMethod =
- dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl)) {
- auto Self = CurMethod->getSelfDecl();
- if (Self->getType().isConstQualified()) {
- if (auto LI = dyn_cast<llvm::LoadInst>(Arg0->stripPointerCasts())) {
- llvm::Value *SelfAddr = CGF.GetAddrOfLocalVar(Self).getPointer();
- if (SelfAddr == LI->getPointerOperand()) {
- ReceiverCanBeNull = false;
- }
- }
- }
- }
-
- bool RequiresNullCheck = false;
-
- llvm::Constant *Fn = nullptr;
- if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
- if (ReceiverCanBeNull) RequiresNullCheck = true;
- Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
- : ObjCTypes.getSendStretFn(IsSuper);
- } else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
- Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
- : ObjCTypes.getSendFpretFn(IsSuper);
- } else if (CGM.ReturnTypeUsesFP2Ret(ResultType)) {
- Fn = (ObjCABI == 2) ? ObjCTypes.getSendFp2RetFn2(IsSuper)
- : ObjCTypes.getSendFp2retFn(IsSuper);
- } else {
- // arm64 uses objc_msgSend for stret methods and yet null receiver check
- // must be made for it.
- if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
- RequiresNullCheck = true;
- Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
- : ObjCTypes.getSendFn(IsSuper);
- }
-
- // We don't need to emit a null check to zero out an indirect result if the
- // result is ignored.
- if (Return.isUnused())
- RequiresNullCheck = false;
-
- // Emit a null-check if there's a consumed argument other than the receiver.
- if (!RequiresNullCheck && CGM.getLangOpts().ObjCAutoRefCount && Method) {
- for (const auto *ParamDecl : Method->parameters()) {
- if (ParamDecl->hasAttr<NSConsumedAttr>()) {
- RequiresNullCheck = true;
- break;
- }
- }
- }
-
- NullReturnState nullReturn;
- if (RequiresNullCheck) {
- nullReturn.init(CGF, Arg0);
- }
-
- llvm::Instruction *CallSite;
- Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
- CGCallee Callee = CGCallee::forDirect(Fn);
- RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs,
- &CallSite);
-
- // Mark the call as noreturn if the method is marked noreturn and the
- // receiver cannot be null.
- if (Method && Method->hasAttr<NoReturnAttr>() && !ReceiverCanBeNull) {
- llvm::CallSite(CallSite).setDoesNotReturn();
- }
-
- return nullReturn.complete(CGF, Return, rvalue, ResultType, CallArgs,
- RequiresNullCheck ? Method : nullptr);
-}
-
-static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT,
- bool pointee = false) {
- // Note that GC qualification applies recursively to C pointer types
- // that aren't otherwise decorated. This is weird, but it's probably
- // an intentional workaround to the unreliable placement of GC qualifiers.
- if (FQT.isObjCGCStrong())
- return Qualifiers::Strong;
-
- if (FQT.isObjCGCWeak())
- return Qualifiers::Weak;
-
- if (auto ownership = FQT.getObjCLifetime()) {
- // Ownership does not apply recursively to C pointer types.
- if (pointee) return Qualifiers::GCNone;
- switch (ownership) {
- case Qualifiers::OCL_Weak: return Qualifiers::Weak;
- case Qualifiers::OCL_Strong: return Qualifiers::Strong;
- case Qualifiers::OCL_ExplicitNone: return Qualifiers::GCNone;
- case Qualifiers::OCL_Autoreleasing: llvm_unreachable("autoreleasing ivar?");
- case Qualifiers::OCL_None: llvm_unreachable("known nonzero");
- }
- llvm_unreachable("bad objc ownership");
- }
-
- // Treat unqualified retainable pointers as strong.
- if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
- return Qualifiers::Strong;
-
- // Walk into C pointer types, but only in GC.
- if (Ctx.getLangOpts().getGC() != LangOptions::NonGC) {
- if (const PointerType *PT = FQT->getAs<PointerType>())
- return GetGCAttrTypeForType(Ctx, PT->getPointeeType(), /*pointee*/ true);
- }
-
- return Qualifiers::GCNone;
-}
-
-namespace {
- struct IvarInfo {
- CharUnits Offset;
- uint64_t SizeInWords;
- IvarInfo(CharUnits offset, uint64_t sizeInWords)
- : Offset(offset), SizeInWords(sizeInWords) {}
-
- // Allow sorting based on byte pos.
- bool operator<(const IvarInfo &other) const {
- return Offset < other.Offset;
- }
- };
-
- /// A helper class for building GC layout strings.
- class IvarLayoutBuilder {
- CodeGenModule &CGM;
-
- /// The start of the layout. Offsets will be relative to this value,
- /// and entries less than this value will be silently discarded.
- CharUnits InstanceBegin;
-
- /// The end of the layout. Offsets will never exceed this value.
- CharUnits InstanceEnd;
-
- /// Whether we're generating the strong layout or the weak layout.
- bool ForStrongLayout;
-
- /// Whether the offsets in IvarsInfo might be out-of-order.
- bool IsDisordered = false;
-
- llvm::SmallVector<IvarInfo, 8> IvarsInfo;
-
- public:
- IvarLayoutBuilder(CodeGenModule &CGM, CharUnits instanceBegin,
- CharUnits instanceEnd, bool forStrongLayout)
- : CGM(CGM), InstanceBegin(instanceBegin), InstanceEnd(instanceEnd),
- ForStrongLayout(forStrongLayout) {
- }
-
- void visitRecord(const RecordType *RT, CharUnits offset);
-
- template <class Iterator, class GetOffsetFn>
- void visitAggregate(Iterator begin, Iterator end,
- CharUnits aggrOffset,
- const GetOffsetFn &getOffset);
-
- void visitField(const FieldDecl *field, CharUnits offset);
-
- /// Add the layout of a block implementation.
- void visitBlock(const CGBlockInfo &blockInfo);
-
- /// Is there any information for an interesting bitmap?
- bool hasBitmapData() const { return !IvarsInfo.empty(); }
-
- llvm::Constant *buildBitmap(CGObjCCommonMac &CGObjC,
- llvm::SmallVectorImpl<unsigned char> &buffer);
-
- static void dump(ArrayRef<unsigned char> buffer) {
- const unsigned char *s = buffer.data();
- for (unsigned i = 0, e = buffer.size(); i < e; i++)
- if (!(s[i] & 0xf0))
- printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
- else
- printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
- printf("\n");
- }
- };
-} // end anonymous namespace
-
-llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
-
- llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
- if (CGM.getLangOpts().getGC() == LangOptions::NonGC)
- return nullPtr;
-
- IvarLayoutBuilder builder(CGM, CharUnits::Zero(), blockInfo.BlockSize,
- /*for strong layout*/ true);
-
- builder.visitBlock(blockInfo);
-
- if (!builder.hasBitmapData())
- return nullPtr;
-
- llvm::SmallVector<unsigned char, 32> buffer;
- llvm::Constant *C = builder.buildBitmap(*this, buffer);
- if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
- printf("\n block variable layout for block: ");
- builder.dump(buffer);
- }
-
- return C;
-}
-
-void IvarLayoutBuilder::visitBlock(const CGBlockInfo &blockInfo) {
- // __isa is the first field in block descriptor and must assume by runtime's
- // convention that it is GC'able.
- IvarsInfo.push_back(IvarInfo(CharUnits::Zero(), 1));
-
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
- // Ignore the optional 'this' capture: C++ objects are not assumed
- // to be GC'ed.
-
- CharUnits lastFieldOffset;
-
- // Walk the captured variables.
- for (const auto &CI : blockDecl->captures()) {
- const VarDecl *variable = CI.getVariable();
- QualType type = variable->getType();
-
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
-
- // Ignore constant captures.
- if (capture.isConstant()) continue;
-
- CharUnits fieldOffset = capture.getOffset();
-
- // Block fields are not necessarily ordered; if we detect that we're
- // adding them out-of-order, make sure we sort later.
- if (fieldOffset < lastFieldOffset)
- IsDisordered = true;
- lastFieldOffset = fieldOffset;
-
- // __block variables are passed by their descriptor address.
- if (CI.isByRef()) {
- IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
- continue;
- }
-
- assert(!type->isArrayType() && "array variable should not be caught");
- if (const RecordType *record = type->getAs<RecordType>()) {
- visitRecord(record, fieldOffset);
- continue;
- }
-
- Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), type);
-
- if (GCAttr == Qualifiers::Strong) {
- assert(CGM.getContext().getTypeSize(type)
- == CGM.getTarget().getPointerWidth(0));
- IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
- }
- }
-}
-
-/// getBlockCaptureLifetime - This routine returns life time of the captured
-/// block variable for the purpose of block layout meta-data generation. FQT is
-/// the type of the variable captured in the block.
-Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT,
- bool ByrefLayout) {
- // If it has an ownership qualifier, we're done.
- if (auto lifetime = FQT.getObjCLifetime())
- return lifetime;
-
- // If it doesn't, and this is ARC, it has no ownership.
- if (CGM.getLangOpts().ObjCAutoRefCount)
- return Qualifiers::OCL_None;
-
- // In MRC, retainable pointers are owned by non-__block variables.
- if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
- return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong;
-
- return Qualifiers::OCL_None;
-}
-
-void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
- Qualifiers::ObjCLifetime LifeTime,
- CharUnits FieldOffset,
- CharUnits FieldSize) {
- // __block variables are passed by their descriptor address.
- if (IsByref)
- RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset,
- FieldSize));
- else if (LifeTime == Qualifiers::OCL_Strong)
- RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset,
- FieldSize));
- else if (LifeTime == Qualifiers::OCL_Weak)
- RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset,
- FieldSize));
- else if (LifeTime == Qualifiers::OCL_ExplicitNone)
- RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset,
- FieldSize));
- else
- RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES,
- FieldOffset,
- FieldSize));
-}
-
-void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
- const RecordDecl *RD,
- ArrayRef<const FieldDecl*> RecFields,
- CharUnits BytePos, bool &HasUnion,
- bool ByrefLayout) {
- bool IsUnion = (RD && RD->isUnion());
- CharUnits MaxUnionSize = CharUnits::Zero();
- const FieldDecl *MaxField = nullptr;
- const FieldDecl *LastFieldBitfieldOrUnnamed = nullptr;
- CharUnits MaxFieldOffset = CharUnits::Zero();
- CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero();
-
- if (RecFields.empty())
- return;
- unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
-
- for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
- const FieldDecl *Field = RecFields[i];
- // Note that 'i' here is actually the field index inside RD of Field,
- // although this dependency is hidden.
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- CharUnits FieldOffset =
- CGM.getContext().toCharUnitsFromBits(RL.getFieldOffset(i));
-
- // Skip over unnamed or bitfields
- if (!Field->getIdentifier() || Field->isBitField()) {
- LastFieldBitfieldOrUnnamed = Field;
- LastBitfieldOrUnnamedOffset = FieldOffset;
- continue;
- }
-
- LastFieldBitfieldOrUnnamed = nullptr;
- QualType FQT = Field->getType();
- if (FQT->isRecordType() || FQT->isUnionType()) {
- if (FQT->isUnionType())
- HasUnion = true;
-
- BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(),
- BytePos + FieldOffset, HasUnion);
- continue;
- }
-
- if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
- const ConstantArrayType *CArray =
- dyn_cast_or_null<ConstantArrayType>(Array);
- uint64_t ElCount = CArray->getSize().getZExtValue();
- assert(CArray && "only array with known element size is supported");
- FQT = CArray->getElementType();
- while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
- const ConstantArrayType *CArray =
- dyn_cast_or_null<ConstantArrayType>(Array);
- ElCount *= CArray->getSize().getZExtValue();
- FQT = CArray->getElementType();
- }
- if (FQT->isRecordType() && ElCount) {
- int OldIndex = RunSkipBlockVars.size() - 1;
- const RecordType *RT = FQT->getAs<RecordType>();
- BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset,
- HasUnion);
-
- // Replicate layout information for each array element. Note that
- // one element is already done.
- uint64_t ElIx = 1;
- for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) {
- CharUnits Size = CGM.getContext().getTypeSizeInChars(RT);
- for (int i = OldIndex+1; i <= FirstIndex; ++i)
- RunSkipBlockVars.push_back(
- RUN_SKIP(RunSkipBlockVars[i].opcode,
- RunSkipBlockVars[i].block_var_bytepos + Size*ElIx,
- RunSkipBlockVars[i].block_var_size));
- }
- continue;
- }
- }
- CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field->getType());
- if (IsUnion) {
- CharUnits UnionIvarSize = FieldSize;
- if (UnionIvarSize > MaxUnionSize) {
- MaxUnionSize = UnionIvarSize;
- MaxField = Field;
- MaxFieldOffset = FieldOffset;
- }
- } else {
- UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(FQT, ByrefLayout),
- BytePos + FieldOffset,
- FieldSize);
- }
- }
-
- if (LastFieldBitfieldOrUnnamed) {
- if (LastFieldBitfieldOrUnnamed->isBitField()) {
- // Last field was a bitfield. Must update the info.
- uint64_t BitFieldSize
- = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
- unsigned UnsSize = (BitFieldSize / ByteSizeInBits) +
- ((BitFieldSize % ByteSizeInBits) != 0);
- CharUnits Size = CharUnits::fromQuantity(UnsSize);
- Size += LastBitfieldOrUnnamedOffset;
- UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
- ByrefLayout),
- BytePos + LastBitfieldOrUnnamedOffset,
- Size);
- } else {
- assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
- // Last field was unnamed. Must update skip info.
- CharUnits FieldSize
- = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
- UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
- ByrefLayout),
- BytePos + LastBitfieldOrUnnamedOffset,
- FieldSize);
- }
- }
-
- if (MaxField)
- UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(MaxField->getType(), ByrefLayout),
- BytePos + MaxFieldOffset,
- MaxUnionSize);
-}
-
-void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
- CharUnits BytePos,
- bool &HasUnion,
- bool ByrefLayout) {
- const RecordDecl *RD = RT->getDecl();
- SmallVector<const FieldDecl*, 16> Fields(RD->fields());
- llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
- const llvm::StructLayout *RecLayout =
- CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
-
- BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion, ByrefLayout);
-}
-
-/// InlineLayoutInstruction - This routine produce an inline instruction for the
-/// block variable layout if it can. If not, it returns 0. Rules are as follow:
-/// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world,
-/// an inline layout of value 0x0000000000000xyz is interpreted as follows:
-/// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by
-/// y captured object of BLOCK_LAYOUT_BYREF. Followed by
-/// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero
-/// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no
-/// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured.
-uint64_t CGObjCCommonMac::InlineLayoutInstruction(
- SmallVectorImpl<unsigned char> &Layout) {
- uint64_t Result = 0;
- if (Layout.size() <= 3) {
- unsigned size = Layout.size();
- unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0;
- unsigned char inst;
- enum BLOCK_LAYOUT_OPCODE opcode ;
- switch (size) {
- case 3:
- inst = Layout[0];
- opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_STRONG)
- strong_word_count = (inst & 0xF)+1;
- else
- return 0;
- inst = Layout[1];
- opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_BYREF)
- byref_word_count = (inst & 0xF)+1;
- else
- return 0;
- inst = Layout[2];
- opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_WEAK)
- weak_word_count = (inst & 0xF)+1;
- else
- return 0;
- break;
-
- case 2:
- inst = Layout[0];
- opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_STRONG) {
- strong_word_count = (inst & 0xF)+1;
- inst = Layout[1];
- opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_BYREF)
- byref_word_count = (inst & 0xF)+1;
- else if (opcode == BLOCK_LAYOUT_WEAK)
- weak_word_count = (inst & 0xF)+1;
- else
- return 0;
- }
- else if (opcode == BLOCK_LAYOUT_BYREF) {
- byref_word_count = (inst & 0xF)+1;
- inst = Layout[1];
- opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_WEAK)
- weak_word_count = (inst & 0xF)+1;
- else
- return 0;
- }
- else
- return 0;
- break;
-
- case 1:
- inst = Layout[0];
- opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_STRONG)
- strong_word_count = (inst & 0xF)+1;
- else if (opcode == BLOCK_LAYOUT_BYREF)
- byref_word_count = (inst & 0xF)+1;
- else if (opcode == BLOCK_LAYOUT_WEAK)
- weak_word_count = (inst & 0xF)+1;
- else
- return 0;
- break;
-
- default:
- return 0;
- }
-
- // Cannot inline when any of the word counts is 15. Because this is one less
- // than the actual work count (so 15 means 16 actual word counts),
- // and we can only display 0 thru 15 word counts.
- if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16)
- return 0;
-
- unsigned count =
- (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0);
-
- if (size == count) {
- if (strong_word_count)
- Result = strong_word_count;
- Result <<= 4;
- if (byref_word_count)
- Result += byref_word_count;
- Result <<= 4;
- if (weak_word_count)
- Result += weak_word_count;
- }
- }
- return Result;
-}
-
-llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
- llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
- if (RunSkipBlockVars.empty())
- return nullPtr;
- unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
- unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
-
- // Sort on byte position; captures might not be allocated in order,
- // and unions can do funny things.
- llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end());
- SmallVector<unsigned char, 16> Layout;
-
- unsigned size = RunSkipBlockVars.size();
- for (unsigned i = 0; i < size; i++) {
- enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode;
- CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos;
- CharUnits end_byte_pos = start_byte_pos;
- unsigned j = i+1;
- while (j < size) {
- if (opcode == RunSkipBlockVars[j].opcode) {
- end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos;
- i++;
- }
- else
- break;
- }
- CharUnits size_in_bytes =
- end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
- if (j < size) {
- CharUnits gap =
- RunSkipBlockVars[j].block_var_bytepos -
- RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
- size_in_bytes += gap;
- }
- CharUnits residue_in_bytes = CharUnits::Zero();
- if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) {
- residue_in_bytes = size_in_bytes % WordSizeInBytes;
- size_in_bytes -= residue_in_bytes;
- opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS;
- }
-
- unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes;
- while (size_in_words >= 16) {
- // Note that value in imm. is one less that the actual
- // value. So, 0xf means 16 words follow!
- unsigned char inst = (opcode << 4) | 0xf;
- Layout.push_back(inst);
- size_in_words -= 16;
- }
- if (size_in_words > 0) {
- // Note that value in imm. is one less that the actual
- // value. So, we subtract 1 away!
- unsigned char inst = (opcode << 4) | (size_in_words-1);
- Layout.push_back(inst);
- }
- if (residue_in_bytes > CharUnits::Zero()) {
- unsigned char inst =
- (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
- Layout.push_back(inst);
- }
- }
-
- while (!Layout.empty()) {
- unsigned char inst = Layout.back();
- enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
- Layout.pop_back();
- else
- break;
- }
-
- uint64_t Result = InlineLayoutInstruction(Layout);
- if (Result != 0) {
- // Block variable layout instruction has been inlined.
- if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- if (ComputeByrefLayout)
- printf("\n Inline BYREF variable layout: ");
- else
- printf("\n Inline block variable layout: ");
- printf("0x0%" PRIx64 "", Result);
- if (auto numStrong = (Result & 0xF00) >> 8)
- printf(", BL_STRONG:%d", (int) numStrong);
- if (auto numByref = (Result & 0x0F0) >> 4)
- printf(", BL_BYREF:%d", (int) numByref);
- if (auto numWeak = (Result & 0x00F) >> 0)
- printf(", BL_WEAK:%d", (int) numWeak);
- printf(", BL_OPERATOR:0\n");
- }
- return llvm::ConstantInt::get(CGM.IntPtrTy, Result);
- }
-
- unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
- Layout.push_back(inst);
- std::string BitMap;
- for (unsigned i = 0, e = Layout.size(); i != e; i++)
- BitMap += Layout[i];
-
- if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- if (ComputeByrefLayout)
- printf("\n Byref variable layout: ");
- else
- printf("\n Block variable layout: ");
- for (unsigned i = 0, e = BitMap.size(); i != e; i++) {
- unsigned char inst = BitMap[i];
- enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- unsigned delta = 1;
- switch (opcode) {
- case BLOCK_LAYOUT_OPERATOR:
- printf("BL_OPERATOR:");
- delta = 0;
- break;
- case BLOCK_LAYOUT_NON_OBJECT_BYTES:
- printf("BL_NON_OBJECT_BYTES:");
- break;
- case BLOCK_LAYOUT_NON_OBJECT_WORDS:
- printf("BL_NON_OBJECT_WORD:");
- break;
- case BLOCK_LAYOUT_STRONG:
- printf("BL_STRONG:");
- break;
- case BLOCK_LAYOUT_BYREF:
- printf("BL_BYREF:");
- break;
- case BLOCK_LAYOUT_WEAK:
- printf("BL_WEAK:");
- break;
- case BLOCK_LAYOUT_UNRETAINED:
- printf("BL_UNRETAINED:");
- break;
- }
- // Actual value of word count is one more that what is in the imm.
- // field of the instruction
- printf("%d", (inst & 0xf) + delta);
- if (i < e-1)
- printf(", ");
- else
- printf("\n");
- }
- }
-
- auto *Entry = CreateCStringLiteral(BitMap, ObjCLabelType::ClassName,
- /*ForceNonFragileABI=*/true,
- /*NullTerminate=*/false);
- return getConstantGEP(VMContext, Entry, 0, 0);
-}
-
-static std::string getBlockLayoutInfoString(
- const SmallVectorImpl<CGObjCCommonMac::RUN_SKIP> &RunSkipBlockVars,
- bool HasCopyDisposeHelpers) {
- std::string Str;
- for (const CGObjCCommonMac::RUN_SKIP &R : RunSkipBlockVars) {
- if (R.opcode == CGObjCCommonMac::BLOCK_LAYOUT_UNRETAINED) {
- // Copy/dispose helpers don't have any information about
- // __unsafe_unretained captures, so unconditionally concatenate a string.
- Str += "u";
- } else if (HasCopyDisposeHelpers) {
- // Information about __strong, __weak, or byref captures has already been
- // encoded into the names of the copy/dispose helpers. We have to add a
- // string here only when the copy/dispose helpers aren't generated (which
- // happens when the block is non-escaping).
- continue;
- } else {
- switch (R.opcode) {
- case CGObjCCommonMac::BLOCK_LAYOUT_STRONG:
- Str += "s";
- break;
- case CGObjCCommonMac::BLOCK_LAYOUT_BYREF:
- Str += "r";
- break;
- case CGObjCCommonMac::BLOCK_LAYOUT_WEAK:
- Str += "w";
- break;
- default:
- continue;
- }
- }
- Str += llvm::to_string(R.block_var_bytepos.getQuantity());
- Str += "l" + llvm::to_string(R.block_var_size.getQuantity());
- }
- return Str;
-}
-
-void CGObjCCommonMac::fillRunSkipBlockVars(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
-
- RunSkipBlockVars.clear();
- bool hasUnion = false;
-
- unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
- unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
-
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
- // Calculate the basic layout of the block structure.
- const llvm::StructLayout *layout =
- CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
-
- // Ignore the optional 'this' capture: C++ objects are not assumed
- // to be GC'ed.
- if (blockInfo.BlockHeaderForcedGapSize != CharUnits::Zero())
- UpdateRunSkipBlockVars(false, Qualifiers::OCL_None,
- blockInfo.BlockHeaderForcedGapOffset,
- blockInfo.BlockHeaderForcedGapSize);
- // Walk the captured variables.
- for (const auto &CI : blockDecl->captures()) {
- const VarDecl *variable = CI.getVariable();
- QualType type = variable->getType();
-
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
-
- // Ignore constant captures.
- if (capture.isConstant()) continue;
-
- CharUnits fieldOffset =
- CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
-
- assert(!type->isArrayType() && "array variable should not be caught");
- if (!CI.isByRef())
- if (const RecordType *record = type->getAs<RecordType>()) {
- BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
- continue;
- }
- CharUnits fieldSize;
- if (CI.isByRef())
- fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
- else
- fieldSize = CGM.getContext().getTypeSizeInChars(type);
- UpdateRunSkipBlockVars(CI.isByRef(), getBlockCaptureLifetime(type, false),
- fieldOffset, fieldSize);
- }
-}
-
-llvm::Constant *
-CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- fillRunSkipBlockVars(CGM, blockInfo);
- return getBitmapBlockLayout(false);
-}
-
-std::string CGObjCCommonMac::getRCBlockLayoutStr(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- fillRunSkipBlockVars(CGM, blockInfo);
- return getBlockLayoutInfoString(RunSkipBlockVars,
- blockInfo.needsCopyDisposeHelpers());
-}
-
-llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
- QualType T) {
- assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
- assert(!T->isArrayType() && "__block array variable should not be caught");
- CharUnits fieldOffset;
- RunSkipBlockVars.clear();
- bool hasUnion = false;
- if (const RecordType *record = T->getAs<RecordType>()) {
- BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */);
- llvm::Constant *Result = getBitmapBlockLayout(true);
- if (isa<llvm::ConstantInt>(Result))
- Result = llvm::ConstantExpr::getIntToPtr(Result, CGM.Int8PtrTy);
- return Result;
- }
- llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
- return nullPtr;
-}
-
-llvm::Value *CGObjCMac::GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD) {
- // FIXME: I don't understand why gcc generates this, or where it is
- // resolved. Investigate. Its also wasteful to look this up over and over.
- LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
-
- return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
- ObjCTypes.getExternalProtocolPtrTy());
-}
-
-void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
- // FIXME: We shouldn't need this, the protocol decl should contain enough
- // information to tell us whether this was a declaration or a definition.
- DefinedProtocols.insert(PD->getIdentifier());
-
- // If we have generated a forward reference to this protocol, emit
- // it now. Otherwise do nothing, the protocol objects are lazily
- // emitted.
- if (Protocols.count(PD->getIdentifier()))
- GetOrEmitProtocol(PD);
-}
-
-llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
- if (DefinedProtocols.count(PD->getIdentifier()))
- return GetOrEmitProtocol(PD);
-
- return GetOrEmitProtocolRef(PD);
-}
-
-llvm::Value *CGObjCCommonMac::EmitClassRefViaRuntime(
- CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID,
- ObjCCommonTypesHelper &ObjCTypes) {
- llvm::Constant *lookUpClassFn = ObjCTypes.getLookUpClassFn();
-
- llvm::Value *className =
- CGF.CGM.GetAddrOfConstantCString(ID->getObjCRuntimeNameAsString())
- .getPointer();
- ASTContext &ctx = CGF.CGM.getContext();
- className =
- CGF.Builder.CreateBitCast(className,
- CGF.ConvertType(
- ctx.getPointerType(ctx.CharTy.withConst())));
- llvm::CallInst *call = CGF.Builder.CreateCall(lookUpClassFn, className);
- call->setDoesNotThrow();
- return call;
-}
-
-/*
-// Objective-C 1.0 extensions
-struct _objc_protocol {
-struct _objc_protocol_extension *isa;
-char *protocol_name;
-struct _objc_protocol_list *protocol_list;
-struct _objc__method_prototype_list *instance_methods;
-struct _objc__method_prototype_list *class_methods
-};
-
-See EmitProtocolExtension().
-*/
-llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
- llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
-
- // Early exit if a defining object has already been generated.
- if (Entry && Entry->hasInitializer())
- return Entry;
-
- // Use the protocol definition, if there is one.
- if (const ObjCProtocolDecl *Def = PD->getDefinition())
- PD = Def;
-
- // FIXME: I don't understand why gcc generates this, or where it is
- // resolved. Investigate. Its also wasteful to look this up over and over.
- LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
-
- // Construct method lists.
- auto methodLists = ProtocolMethodLists::get(PD);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ProtocolTy);
- values.add(EmitProtocolExtension(PD, methodLists));
- values.add(GetClassName(PD->getObjCRuntimeNameAsString()));
- values.add(EmitProtocolList("OBJC_PROTOCOL_REFS_" + PD->getName(),
- PD->protocol_begin(), PD->protocol_end()));
- values.add(methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::RequiredInstanceMethods));
- values.add(methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::RequiredClassMethods));
-
- if (Entry) {
- // Already created, update the initializer.
- assert(Entry->hasPrivateLinkage());
- values.finishAndSetAsInitializer(Entry);
- } else {
- Entry = values.finishAndCreateGlobal("OBJC_PROTOCOL_" + PD->getName(),
- CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
-
- Protocols[PD->getIdentifier()] = Entry;
- }
- CGM.addCompilerUsedGlobal(Entry);
-
- return Entry;
-}
-
-llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
- llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
-
- if (!Entry) {
- // We use the initializer as a marker of whether this is a forward
- // reference or not. At module finalization we add the empty
- // contents for protocols which were referenced but never defined.
- Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy,
- false, llvm::GlobalValue::PrivateLinkage,
- nullptr, "OBJC_PROTOCOL_" + PD->getName());
- Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
- // FIXME: Is this necessary? Why only for protocol?
- Entry->setAlignment(4);
- }
-
- return Entry;
-}
-
-/*
- struct _objc_protocol_extension {
- uint32_t size;
- struct objc_method_description_list *optional_instance_methods;
- struct objc_method_description_list *optional_class_methods;
- struct objc_property_list *instance_properties;
- const char ** extendedMethodTypes;
- struct objc_property_list *class_properties;
- };
-*/
-llvm::Constant *
-CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
- const ProtocolMethodLists &methodLists) {
- auto optInstanceMethods =
- methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::OptionalInstanceMethods);
- auto optClassMethods =
- methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::OptionalClassMethods);
-
- auto extendedMethodTypes =
- EmitProtocolMethodTypes("OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
- methodLists.emitExtendedTypesArray(this),
- ObjCTypes);
-
- auto instanceProperties =
- EmitPropertyList("OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr, PD,
- ObjCTypes, false);
- auto classProperties =
- EmitPropertyList("OBJC_$_CLASS_PROP_PROTO_LIST_" + PD->getName(), nullptr,
- PD, ObjCTypes, true);
-
- // Return null if no extension bits are used.
- if (optInstanceMethods->isNullValue() &&
- optClassMethods->isNullValue() &&
- extendedMethodTypes->isNullValue() &&
- instanceProperties->isNullValue() &&
- classProperties->isNullValue()) {
- return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
- }
-
- uint64_t size =
- CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ProtocolExtensionTy);
- values.addInt(ObjCTypes.IntTy, size);
- values.add(optInstanceMethods);
- values.add(optClassMethods);
- values.add(instanceProperties);
- values.add(extendedMethodTypes);
- values.add(classProperties);
-
- // No special section, but goes in llvm.used
- return CreateMetadataVar("\01l_OBJC_PROTOCOLEXT_" + PD->getName(), values,
- StringRef(), CGM.getPointerAlign(), true);
-}
-
-/*
- struct objc_protocol_list {
- struct objc_protocol_list *next;
- long count;
- Protocol *list[];
- };
-*/
-llvm::Constant *
-CGObjCMac::EmitProtocolList(Twine name,
- ObjCProtocolDecl::protocol_iterator begin,
- ObjCProtocolDecl::protocol_iterator end) {
- // Just return null for empty protocol lists
- if (begin == end)
- return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
-
- // This field is only used by the runtime.
- values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
-
- // Reserve a slot for the count.
- auto countSlot = values.addPlaceholder();
-
- auto refsArray = values.beginArray(ObjCTypes.ProtocolPtrTy);
- for (; begin != end; ++begin) {
- refsArray.add(GetProtocolRef(*begin));
- }
- auto count = refsArray.size();
-
- // This list is null terminated.
- refsArray.addNullPointer(ObjCTypes.ProtocolPtrTy);
-
- refsArray.finishAndAddTo(values);
- values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count);
-
- StringRef section;
- if (CGM.getTriple().isOSBinFormatMachO())
- section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
-
- llvm::GlobalVariable *GV =
- CreateMetadataVar(name, values, section, CGM.getPointerAlign(), false);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
-}
-
-static void
-PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
- SmallVectorImpl<const ObjCPropertyDecl *> &Properties,
- const ObjCProtocolDecl *Proto,
- bool IsClassProperty) {
- for (const auto *P : Proto->protocols())
- PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
-
- for (const auto *PD : Proto->properties()) {
- if (IsClassProperty != PD->isClassProperty())
- continue;
- if (!PropertySet.insert(PD->getIdentifier()).second)
- continue;
- Properties.push_back(PD);
- }
-}
-
-/*
- struct _objc_property {
- const char * const name;
- const char * const attributes;
- };
-
- struct _objc_property_list {
- uint32_t entsize; // sizeof (struct _objc_property)
- uint32_t prop_count;
- struct _objc_property[prop_count];
- };
-*/
-llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
- const Decl *Container,
- const ObjCContainerDecl *OCD,
- const ObjCCommonTypesHelper &ObjCTypes,
- bool IsClassProperty) {
- if (IsClassProperty) {
- // Make this entry NULL for OS X with deployment target < 10.11, for iOS
- // with deployment target < 9.0.
- const llvm::Triple &Triple = CGM.getTarget().getTriple();
- if ((Triple.isMacOSX() && Triple.isMacOSXVersionLT(10, 11)) ||
- (Triple.isiOS() && Triple.isOSVersionLT(9)))
- return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
- }
-
- SmallVector<const ObjCPropertyDecl *, 16> Properties;
- llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
-
- if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
- for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
- for (auto *PD : ClassExt->properties()) {
- if (IsClassProperty != PD->isClassProperty())
- continue;
- PropertySet.insert(PD->getIdentifier());
- Properties.push_back(PD);
- }
-
- for (const auto *PD : OCD->properties()) {
- if (IsClassProperty != PD->isClassProperty())
- continue;
- // Don't emit duplicate metadata for properties that were already in a
- // class extension.
- if (!PropertySet.insert(PD->getIdentifier()).second)
- continue;
- Properties.push_back(PD);
- }
-
- if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
- for (const auto *P : OID->all_referenced_protocols())
- PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
- }
- else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) {
- for (const auto *P : CD->protocols())
- PushProtocolProperties(PropertySet, Properties, P, IsClassProperty);
- }
-
- // Return null for empty list.
- if (Properties.empty())
- return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
-
- unsigned propertySize =
- CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
- values.addInt(ObjCTypes.IntTy, propertySize);
- values.addInt(ObjCTypes.IntTy, Properties.size());
- auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy);
- for (auto PD : Properties) {
- auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy);
- property.add(GetPropertyName(PD->getIdentifier()));
- property.add(GetPropertyTypeString(PD, Container));
- property.finishAndAddTo(propertiesArray);
- }
- propertiesArray.finishAndAddTo(values);
-
- StringRef Section;
- if (CGM.getTriple().isOSBinFormatMachO())
- Section = (ObjCABI == 2) ? "__DATA, __objc_const"
- : "__OBJC,__property,regular,no_dead_strip";
-
- llvm::GlobalVariable *GV =
- CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
-}
-
-llvm::Constant *
-CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name,
- ArrayRef<llvm::Constant*> MethodTypes,
- const ObjCCommonTypesHelper &ObjCTypes) {
- // Return null for empty list.
- if (MethodTypes.empty())
- return llvm::Constant::getNullValue(ObjCTypes.Int8PtrPtrTy);
-
- llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
- MethodTypes.size());
- llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes);
-
- StringRef Section;
- if (CGM.getTriple().isOSBinFormatMachO() && ObjCABI == 2)
- Section = "__DATA, __objc_const";
-
- llvm::GlobalVariable *GV =
- CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy);
-}
-
-/*
- struct _objc_category {
- char *category_name;
- char *class_name;
- struct _objc_method_list *instance_methods;
- struct _objc_method_list *class_methods;
- struct _objc_protocol_list *protocols;
- uint32_t size; // <rdar://4585769>
- struct _objc_property_list *instance_properties;
- struct _objc_property_list *class_properties;
- };
-*/
-void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategoryTy);
-
- // FIXME: This is poor design, the OCD should have a pointer to the category
- // decl. Additionally, note that Category can be null for the @implementation
- // w/o an @interface case. Sema should just create one for us as it does for
- // @implementation so everyone else can live life under a clear blue sky.
- const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
- const ObjCCategoryDecl *Category =
- Interface->FindCategoryDeclaration(OCD->getIdentifier());
-
- SmallString<256> ExtName;
- llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
- << OCD->getName();
-
- ConstantInitBuilder Builder(CGM);
- auto Values = Builder.beginStruct(ObjCTypes.CategoryTy);
-
- enum {
- InstanceMethods,
- ClassMethods,
- NumMethodLists
- };
- SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
- for (const auto *MD : OCD->methods()) {
- Methods[unsigned(MD->isClassMethod())].push_back(MD);
- }
-
- Values.add(GetClassName(OCD->getName()));
- Values.add(GetClassName(Interface->getObjCRuntimeNameAsString()));
- LazySymbols.insert(Interface->getIdentifier());
-
- Values.add(emitMethodList(ExtName, MethodListType::CategoryInstanceMethods,
- Methods[InstanceMethods]));
- Values.add(emitMethodList(ExtName, MethodListType::CategoryClassMethods,
- Methods[ClassMethods]));
- if (Category) {
- Values.add(
- EmitProtocolList("OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(),
- Category->protocol_begin(), Category->protocol_end()));
- } else {
- Values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
- }
- Values.addInt(ObjCTypes.IntTy, Size);
-
- // If there is no category @interface then there can be no properties.
- if (Category) {
- Values.add(EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(),
- OCD, Category, ObjCTypes, false));
- Values.add(EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
- OCD, Category, ObjCTypes, true));
- } else {
- Values.addNullPointer(ObjCTypes.PropertyListPtrTy);
- Values.addNullPointer(ObjCTypes.PropertyListPtrTy);
- }
-
- llvm::GlobalVariable *GV =
- CreateMetadataVar("OBJC_CATEGORY_" + ExtName.str(), Values,
- "__OBJC,__category,regular,no_dead_strip",
- CGM.getPointerAlign(), true);
- DefinedCategories.push_back(GV);
- DefinedCategoryNames.insert(llvm::CachedHashString(ExtName));
- // method definition entries must be clear for next implementation.
- MethodDefinitions.clear();
-}
-
-enum FragileClassFlags {
- /// Apparently: is not a meta-class.
- FragileABI_Class_Factory = 0x00001,
-
- /// Is a meta-class.
- FragileABI_Class_Meta = 0x00002,
-
- /// Has a non-trivial constructor or destructor.
- FragileABI_Class_HasCXXStructors = 0x02000,
-
- /// Has hidden visibility.
- FragileABI_Class_Hidden = 0x20000,
-
- /// Class implementation was compiled under ARC.
- FragileABI_Class_CompiledByARC = 0x04000000,
-
- /// Class implementation was compiled under MRC and has MRC weak ivars.
- /// Exclusive with CompiledByARC.
- FragileABI_Class_HasMRCWeakIvars = 0x08000000,
-};
-
-enum NonFragileClassFlags {
- /// Is a meta-class.
- NonFragileABI_Class_Meta = 0x00001,
-
- /// Is a root class.
- NonFragileABI_Class_Root = 0x00002,
-
- /// Has a non-trivial constructor or destructor.
- NonFragileABI_Class_HasCXXStructors = 0x00004,
-
- /// Has hidden visibility.
- NonFragileABI_Class_Hidden = 0x00010,
-
- /// Has the exception attribute.
- NonFragileABI_Class_Exception = 0x00020,
-
- /// (Obsolete) ARC-specific: this class has a .release_ivars method
- NonFragileABI_Class_HasIvarReleaser = 0x00040,
-
- /// Class implementation was compiled under ARC.
- NonFragileABI_Class_CompiledByARC = 0x00080,
-
- /// Class has non-trivial destructors, but zero-initialization is okay.
- NonFragileABI_Class_HasCXXDestructorOnly = 0x00100,
-
- /// Class implementation was compiled under MRC and has MRC weak ivars.
- /// Exclusive with CompiledByARC.
- NonFragileABI_Class_HasMRCWeakIvars = 0x00200,
-};
-
-static bool hasWeakMember(QualType type) {
- if (type.getObjCLifetime() == Qualifiers::OCL_Weak) {
- return true;
- }
-
- if (auto recType = type->getAs<RecordType>()) {
- for (auto field : recType->getDecl()->fields()) {
- if (hasWeakMember(field->getType()))
- return true;
- }
- }
-
- return false;
-}
-
-/// For compatibility, we only want to set the "HasMRCWeakIvars" flag
-/// (and actually fill in a layout string) if we really do have any
-/// __weak ivars.
-static bool hasMRCWeakIvars(CodeGenModule &CGM,
- const ObjCImplementationDecl *ID) {
- if (!CGM.getLangOpts().ObjCWeak) return false;
- assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
-
- for (const ObjCIvarDecl *ivar =
- ID->getClassInterface()->all_declared_ivar_begin();
- ivar; ivar = ivar->getNextIvar()) {
- if (hasWeakMember(ivar->getType()))
- return true;
- }
-
- return false;
-}
-
-/*
- struct _objc_class {
- Class isa;
- Class super_class;
- const char *name;
- long version;
- long info;
- long instance_size;
- struct _objc_ivar_list *ivars;
- struct _objc_method_list *methods;
- struct _objc_cache *cache;
- struct _objc_protocol_list *protocols;
- // Objective-C 1.0 extensions (<rdr://4585769>)
- const char *ivar_layout;
- struct _objc_class_ext *ext;
- };
-
- See EmitClassExtension();
-*/
-void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
- IdentifierInfo *RuntimeName =
- &CGM.getContext().Idents.get(ID->getObjCRuntimeNameAsString());
- DefinedSymbols.insert(RuntimeName);
-
- std::string ClassName = ID->getNameAsString();
- // FIXME: Gross
- ObjCInterfaceDecl *Interface =
- const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
- llvm::Constant *Protocols =
- EmitProtocolList("OBJC_CLASS_PROTOCOLS_" + ID->getName(),
- Interface->all_referenced_protocol_begin(),
- Interface->all_referenced_protocol_end());
- unsigned Flags = FragileABI_Class_Factory;
- if (ID->hasNonZeroConstructors() || ID->hasDestructors())
- Flags |= FragileABI_Class_HasCXXStructors;
-
- bool hasMRCWeak = false;
-
- if (CGM.getLangOpts().ObjCAutoRefCount)
- Flags |= FragileABI_Class_CompiledByARC;
- else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
- Flags |= FragileABI_Class_HasMRCWeakIvars;
-
- CharUnits Size =
- CGM.getContext().getASTObjCImplementationLayout(ID).getSize();
-
- // FIXME: Set CXX-structors flag.
- if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= FragileABI_Class_Hidden;
-
- enum {
- InstanceMethods,
- ClassMethods,
- NumMethodLists
- };
- SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
- for (const auto *MD : ID->methods()) {
- Methods[unsigned(MD->isClassMethod())].push_back(MD);
- }
-
- for (const auto *PID : ID->property_impls()) {
- if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
- ObjCPropertyDecl *PD = PID->getPropertyDecl();
-
- if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
- if (GetMethodDefinition(MD))
- Methods[InstanceMethods].push_back(MD);
- if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
- if (GetMethodDefinition(MD))
- Methods[InstanceMethods].push_back(MD);
- }
- }
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ClassTy);
- values.add(EmitMetaClass(ID, Protocols, Methods[ClassMethods]));
- if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) {
- // Record a reference to the super class.
- LazySymbols.insert(Super->getIdentifier());
-
- values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
- ObjCTypes.ClassPtrTy);
- } else {
- values.addNullPointer(ObjCTypes.ClassPtrTy);
- }
- values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
- // Version is always 0.
- values.addInt(ObjCTypes.LongTy, 0);
- values.addInt(ObjCTypes.LongTy, Flags);
- values.addInt(ObjCTypes.LongTy, Size.getQuantity());
- values.add(EmitIvarList(ID, false));
- values.add(emitMethodList(ID->getName(), MethodListType::InstanceMethods,
- Methods[InstanceMethods]));
- // cache is always NULL.
- values.addNullPointer(ObjCTypes.CachePtrTy);
- values.add(Protocols);
- values.add(BuildStrongIvarLayout(ID, CharUnits::Zero(), Size));
- values.add(EmitClassExtension(ID, Size, hasMRCWeak,
- /*isMetaclass*/ false));
-
- std::string Name("OBJC_CLASS_");
- Name += ClassName;
- const char *Section = "__OBJC,__class,regular,no_dead_strip";
- // Check for a forward reference.
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
- if (GV) {
- assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
- "Forward metaclass reference has incorrect type.");
- values.finishAndSetAsInitializer(GV);
- GV->setSection(Section);
- GV->setAlignment(CGM.getPointerAlign().getQuantity());
- CGM.addCompilerUsedGlobal(GV);
- } else
- GV = CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true);
- DefinedClasses.push_back(GV);
- ImplementedClasses.push_back(Interface);
- // method definition entries must be clear for next implementation.
- MethodDefinitions.clear();
-}
-
-llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
- llvm::Constant *Protocols,
- ArrayRef<const ObjCMethodDecl*> Methods) {
- unsigned Flags = FragileABI_Class_Meta;
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy);
-
- if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= FragileABI_Class_Hidden;
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ClassTy);
- // The isa for the metaclass is the root of the hierarchy.
- const ObjCInterfaceDecl *Root = ID->getClassInterface();
- while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
- Root = Super;
- values.addBitCast(GetClassName(Root->getObjCRuntimeNameAsString()),
- ObjCTypes.ClassPtrTy);
- // The super class for the metaclass is emitted as the name of the
- // super class. The runtime fixes this up to point to the
- // *metaclass* for the super class.
- if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) {
- values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
- ObjCTypes.ClassPtrTy);
- } else {
- values.addNullPointer(ObjCTypes.ClassPtrTy);
- }
- values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
- // Version is always 0.
- values.addInt(ObjCTypes.LongTy, 0);
- values.addInt(ObjCTypes.LongTy, Flags);
- values.addInt(ObjCTypes.LongTy, Size);
- values.add(EmitIvarList(ID, true));
- values.add(emitMethodList(ID->getName(), MethodListType::ClassMethods,
- Methods));
- // cache is always NULL.
- values.addNullPointer(ObjCTypes.CachePtrTy);
- values.add(Protocols);
- // ivar_layout for metaclass is always NULL.
- values.addNullPointer(ObjCTypes.Int8PtrTy);
- // The class extension is used to store class properties for metaclasses.
- values.add(EmitClassExtension(ID, CharUnits::Zero(), false/*hasMRCWeak*/,
- /*isMetaclass*/true));
-
- std::string Name("OBJC_METACLASS_");
- Name += ID->getName();
-
- // Check for a forward reference.
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
- if (GV) {
- assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
- "Forward metaclass reference has incorrect type.");
- values.finishAndSetAsInitializer(GV);
- } else {
- GV = values.finishAndCreateGlobal(Name, CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- }
- GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
- CGM.addCompilerUsedGlobal(GV);
-
- return GV;
-}
-
-llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
- std::string Name = "OBJC_METACLASS_" + ID->getNameAsString();
-
- // FIXME: Should we look these up somewhere other than the module. Its a bit
- // silly since we only generate these while processing an implementation, so
- // exactly one pointer would work if know when we entered/exitted an
- // implementation block.
-
- // Check for an existing forward reference.
- // Previously, metaclass with internal linkage may have been defined.
- // pass 'true' as 2nd argument so it is returned.
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
- if (!GV)
- GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
- llvm::GlobalValue::PrivateLinkage, nullptr,
- Name);
-
- assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
- "Forward metaclass reference has incorrect type.");
- return GV;
-}
-
-llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
- std::string Name = "OBJC_CLASS_" + ID->getNameAsString();
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
-
- if (!GV)
- GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
- llvm::GlobalValue::PrivateLinkage, nullptr,
- Name);
-
- assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
- "Forward class metadata reference has incorrect type.");
- return GV;
-}
-
-/*
- Emit a "class extension", which in this specific context means extra
- data that doesn't fit in the normal fragile-ABI class structure, and
- has nothing to do with the language concept of a class extension.
-
- struct objc_class_ext {
- uint32_t size;
- const char *weak_ivar_layout;
- struct _objc_property_list *properties;
- };
-*/
-llvm::Constant *
-CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID,
- CharUnits InstanceSize, bool hasMRCWeakIvars,
- bool isMetaclass) {
- // Weak ivar layout.
- llvm::Constant *layout;
- if (isMetaclass) {
- layout = llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
- } else {
- layout = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize,
- hasMRCWeakIvars);
- }
-
- // Properties.
- llvm::Constant *propertyList =
- EmitPropertyList((isMetaclass ? Twine("\01l_OBJC_$_CLASS_PROP_LIST_")
- : Twine("\01l_OBJC_$_PROP_LIST_"))
- + ID->getName(),
- ID, ID->getClassInterface(), ObjCTypes, isMetaclass);
-
- // Return null if no extension bits are used.
- if (layout->isNullValue() && propertyList->isNullValue()) {
- return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
- }
-
- uint64_t size =
- CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ClassExtensionTy);
- values.addInt(ObjCTypes.IntTy, size);
- values.add(layout);
- values.add(propertyList);
-
- return CreateMetadataVar("OBJC_CLASSEXT_" + ID->getName(), values,
- "__OBJC,__class_ext,regular,no_dead_strip",
- CGM.getPointerAlign(), true);
-}
-
-/*
- struct objc_ivar {
- char *ivar_name;
- char *ivar_type;
- int ivar_offset;
- };
-
- struct objc_ivar_list {
- int ivar_count;
- struct objc_ivar list[count];
- };
-*/
-llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
- bool ForClass) {
- // When emitting the root class GCC emits ivar entries for the
- // actual class structure. It is not clear if we need to follow this
- // behavior; for now lets try and get away with not doing it. If so,
- // the cleanest solution would be to make up an ObjCInterfaceDecl
- // for the class.
- if (ForClass)
- return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
-
- const ObjCInterfaceDecl *OID = ID->getClassInterface();
-
- ConstantInitBuilder builder(CGM);
- auto ivarList = builder.beginStruct();
- auto countSlot = ivarList.addPlaceholder();
- auto ivars = ivarList.beginArray(ObjCTypes.IvarTy);
-
- for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
- IVD; IVD = IVD->getNextIvar()) {
- // Ignore unnamed bit-fields.
- if (!IVD->getDeclName())
- continue;
-
- auto ivar = ivars.beginStruct(ObjCTypes.IvarTy);
- ivar.add(GetMethodVarName(IVD->getIdentifier()));
- ivar.add(GetMethodVarType(IVD));
- ivar.addInt(ObjCTypes.IntTy, ComputeIvarBaseOffset(CGM, OID, IVD));
- ivar.finishAndAddTo(ivars);
- }
-
- // Return null for empty list.
- auto count = ivars.size();
- if (count == 0) {
- ivars.abandon();
- ivarList.abandon();
- return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
- }
-
- ivars.finishAndAddTo(ivarList);
- ivarList.fillPlaceholderWithInt(countSlot, ObjCTypes.IntTy, count);
-
- llvm::GlobalVariable *GV;
- if (ForClass)
- GV =
- CreateMetadataVar("OBJC_CLASS_VARIABLES_" + ID->getName(), ivarList,
- "__OBJC,__class_vars,regular,no_dead_strip",
- CGM.getPointerAlign(), true);
- else
- GV = CreateMetadataVar("OBJC_INSTANCE_VARIABLES_" + ID->getName(), ivarList,
- "__OBJC,__instance_vars,regular,no_dead_strip",
- CGM.getPointerAlign(), true);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy);
-}
-
-/// Build a struct objc_method_description constant for the given method.
-///
-/// struct objc_method_description {
-/// SEL method_name;
-/// char *method_types;
-/// };
-void CGObjCMac::emitMethodDescriptionConstant(ConstantArrayBuilder &builder,
- const ObjCMethodDecl *MD) {
- auto description = builder.beginStruct(ObjCTypes.MethodDescriptionTy);
- description.addBitCast(GetMethodVarName(MD->getSelector()),
- ObjCTypes.SelectorPtrTy);
- description.add(GetMethodVarType(MD));
- description.finishAndAddTo(builder);
-}
-
-/// Build a struct objc_method constant for the given method.
-///
-/// struct objc_method {
-/// SEL method_name;
-/// char *method_types;
-/// void *method;
-/// };
-void CGObjCMac::emitMethodConstant(ConstantArrayBuilder &builder,
- const ObjCMethodDecl *MD) {
- llvm::Function *fn = GetMethodDefinition(MD);
- assert(fn && "no definition registered for method");
-
- auto method = builder.beginStruct(ObjCTypes.MethodTy);
- method.addBitCast(GetMethodVarName(MD->getSelector()),
- ObjCTypes.SelectorPtrTy);
- method.add(GetMethodVarType(MD));
- method.addBitCast(fn, ObjCTypes.Int8PtrTy);
- method.finishAndAddTo(builder);
-}
-
-/// Build a struct objc_method_list or struct objc_method_description_list,
-/// as appropriate.
-///
-/// struct objc_method_list {
-/// struct objc_method_list *obsolete;
-/// int count;
-/// struct objc_method methods_list[count];
-/// };
-///
-/// struct objc_method_description_list {
-/// int count;
-/// struct objc_method_description list[count];
-/// };
-llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT,
- ArrayRef<const ObjCMethodDecl *> methods) {
- StringRef prefix;
- StringRef section;
- bool forProtocol = false;
- switch (MLT) {
- case MethodListType::CategoryInstanceMethods:
- prefix = "OBJC_CATEGORY_INSTANCE_METHODS_";
- section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
- forProtocol = false;
- break;
- case MethodListType::CategoryClassMethods:
- prefix = "OBJC_CATEGORY_CLASS_METHODS_";
- section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
- forProtocol = false;
- break;
- case MethodListType::InstanceMethods:
- prefix = "OBJC_INSTANCE_METHODS_";
- section = "__OBJC,__inst_meth,regular,no_dead_strip";
- forProtocol = false;
- break;
- case MethodListType::ClassMethods:
- prefix = "OBJC_CLASS_METHODS_";
- section = "__OBJC,__cls_meth,regular,no_dead_strip";
- forProtocol = false;
- break;
- case MethodListType::ProtocolInstanceMethods:
- prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_";
- section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
- forProtocol = true;
- break;
- case MethodListType::ProtocolClassMethods:
- prefix = "OBJC_PROTOCOL_CLASS_METHODS_";
- section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
- forProtocol = true;
- break;
- case MethodListType::OptionalProtocolInstanceMethods:
- prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_OPT_";
- section = "__OBJC,__cat_inst_meth,regular,no_dead_strip";
- forProtocol = true;
- break;
- case MethodListType::OptionalProtocolClassMethods:
- prefix = "OBJC_PROTOCOL_CLASS_METHODS_OPT_";
- section = "__OBJC,__cat_cls_meth,regular,no_dead_strip";
- forProtocol = true;
- break;
- }
-
- // Return null for empty list.
- if (methods.empty())
- return llvm::Constant::getNullValue(forProtocol
- ? ObjCTypes.MethodDescriptionListPtrTy
- : ObjCTypes.MethodListPtrTy);
-
- // For protocols, this is an objc_method_description_list, which has
- // a slightly different structure.
- if (forProtocol) {
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
- values.addInt(ObjCTypes.IntTy, methods.size());
- auto methodArray = values.beginArray(ObjCTypes.MethodDescriptionTy);
- for (auto MD : methods) {
- emitMethodDescriptionConstant(methodArray, MD);
- }
- methodArray.finishAndAddTo(values);
-
- llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section,
- CGM.getPointerAlign(), true);
- return llvm::ConstantExpr::getBitCast(GV,
- ObjCTypes.MethodDescriptionListPtrTy);
- }
-
- // Otherwise, it's an objc_method_list.
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
- values.addNullPointer(ObjCTypes.Int8PtrTy);
- values.addInt(ObjCTypes.IntTy, methods.size());
- auto methodArray = values.beginArray(ObjCTypes.MethodTy);
- for (auto MD : methods) {
- emitMethodConstant(methodArray, MD);
- }
- methodArray.finishAndAddTo(values);
-
- llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section,
- CGM.getPointerAlign(), true);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy);
-}
-
-llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) {
- SmallString<256> Name;
- GetNameForMethod(OMD, CD, Name);
-
- CodeGenTypes &Types = CGM.getTypes();
- llvm::FunctionType *MethodTy =
- Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
- llvm::Function *Method =
- llvm::Function::Create(MethodTy,
- llvm::GlobalValue::InternalLinkage,
- Name.str(),
- &CGM.getModule());
- MethodDefinitions.insert(std::make_pair(OMD, Method));
-
- return Method;
-}
-
-llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
- ConstantStructBuilder &Init,
- StringRef Section,
- CharUnits Align,
- bool AddToUsed) {
- llvm::GlobalVariable *GV =
- Init.finishAndCreateGlobal(Name, Align, /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- if (!Section.empty())
- GV->setSection(Section);
- if (AddToUsed)
- CGM.addCompilerUsedGlobal(GV);
- return GV;
-}
-
-llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
- llvm::Constant *Init,
- StringRef Section,
- CharUnits Align,
- bool AddToUsed) {
- llvm::Type *Ty = Init->getType();
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Ty, false,
- llvm::GlobalValue::PrivateLinkage, Init, Name);
- if (!Section.empty())
- GV->setSection(Section);
- GV->setAlignment(Align.getQuantity());
- if (AddToUsed)
- CGM.addCompilerUsedGlobal(GV);
- return GV;
-}
-
-llvm::GlobalVariable *
-CGObjCCommonMac::CreateCStringLiteral(StringRef Name, ObjCLabelType Type,
- bool ForceNonFragileABI,
- bool NullTerminate) {
- StringRef Label;
- switch (Type) {
- case ObjCLabelType::ClassName: Label = "OBJC_CLASS_NAME_"; break;
- case ObjCLabelType::MethodVarName: Label = "OBJC_METH_VAR_NAME_"; break;
- case ObjCLabelType::MethodVarType: Label = "OBJC_METH_VAR_TYPE_"; break;
- case ObjCLabelType::PropertyName: Label = "OBJC_PROP_NAME_ATTR_"; break;
- }
-
- bool NonFragile = ForceNonFragileABI || isNonFragileABI();
-
- StringRef Section;
- switch (Type) {
- case ObjCLabelType::ClassName:
- Section = NonFragile ? "__TEXT,__objc_classname,cstring_literals"
- : "__TEXT,__cstring,cstring_literals";
- break;
- case ObjCLabelType::MethodVarName:
- Section = NonFragile ? "__TEXT,__objc_methname,cstring_literals"
- : "__TEXT,__cstring,cstring_literals";
- break;
- case ObjCLabelType::MethodVarType:
- Section = NonFragile ? "__TEXT,__objc_methtype,cstring_literals"
- : "__TEXT,__cstring,cstring_literals";
- break;
- case ObjCLabelType::PropertyName:
- Section = "__TEXT,__cstring,cstring_literals";
- break;
- }
-
- llvm::Constant *Value =
- llvm::ConstantDataArray::getString(VMContext, Name, NullTerminate);
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Value->getType(),
- /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Value, Label);
- if (CGM.getTriple().isOSBinFormatMachO())
- GV->setSection(Section);
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- GV->setAlignment(CharUnits::One().getQuantity());
- CGM.addCompilerUsedGlobal(GV);
-
- return GV;
-}
-
-llvm::Function *CGObjCMac::ModuleInitFunction() {
- // Abuse this interface function as a place to finalize.
- FinishModule();
- return nullptr;
-}
-
-llvm::Constant *CGObjCMac::GetPropertyGetFunction() {
- return ObjCTypes.getGetPropertyFn();
-}
-
-llvm::Constant *CGObjCMac::GetPropertySetFunction() {
- return ObjCTypes.getSetPropertyFn();
-}
-
-llvm::Constant *CGObjCMac::GetOptimizedPropertySetFunction(bool atomic,
- bool copy) {
- return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
-}
-
-llvm::Constant *CGObjCMac::GetGetStructFunction() {
- return ObjCTypes.getCopyStructFn();
-}
-
-llvm::Constant *CGObjCMac::GetSetStructFunction() {
- return ObjCTypes.getCopyStructFn();
-}
-
-llvm::Constant *CGObjCMac::GetCppAtomicObjectGetFunction() {
- return ObjCTypes.getCppAtomicObjectFunction();
-}
-
-llvm::Constant *CGObjCMac::GetCppAtomicObjectSetFunction() {
- return ObjCTypes.getCppAtomicObjectFunction();
-}
-
-llvm::Constant *CGObjCMac::EnumerationMutationFunction() {
- return ObjCTypes.getEnumerationMutationFn();
-}
-
-void CGObjCMac::EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) {
- return EmitTryOrSynchronizedStmt(CGF, S);
-}
-
-void CGObjCMac::EmitSynchronizedStmt(CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S) {
- return EmitTryOrSynchronizedStmt(CGF, S);
-}
-
-namespace {
- struct PerformFragileFinally final : EHScopeStack::Cleanup {
- const Stmt &S;
- Address SyncArgSlot;
- Address CallTryExitVar;
- Address ExceptionData;
- ObjCTypesHelper &ObjCTypes;
- PerformFragileFinally(const Stmt *S,
- Address SyncArgSlot,
- Address CallTryExitVar,
- Address ExceptionData,
- ObjCTypesHelper *ObjCTypes)
- : S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
- ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Check whether we need to call objc_exception_try_exit.
- // In optimized code, this branch will always be folded.
- llvm::BasicBlock *FinallyCallExit =
- CGF.createBasicBlock("finally.call_exit");
- llvm::BasicBlock *FinallyNoCallExit =
- CGF.createBasicBlock("finally.no_call_exit");
- CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CallTryExitVar),
- FinallyCallExit, FinallyNoCallExit);
-
- CGF.EmitBlock(FinallyCallExit);
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(),
- ExceptionData.getPointer());
-
- CGF.EmitBlock(FinallyNoCallExit);
-
- if (isa<ObjCAtTryStmt>(S)) {
- if (const ObjCAtFinallyStmt* FinallyStmt =
- cast<ObjCAtTryStmt>(S).getFinallyStmt()) {
- // Don't try to do the @finally if this is an EH cleanup.
- if (flags.isForEHCleanup()) return;
-
- // Save the current cleanup destination in case there's
- // control flow inside the finally statement.
- llvm::Value *CurCleanupDest =
- CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot());
-
- CGF.EmitStmt(FinallyStmt->getFinallyBody());
-
- if (CGF.HaveInsertPoint()) {
- CGF.Builder.CreateStore(CurCleanupDest,
- CGF.getNormalCleanupDestSlot());
- } else {
- // Currently, the end of the cleanup must always exist.
- CGF.EnsureInsertPoint();
- }
- }
- } else {
- // Emit objc_sync_exit(expr); as finally's sole statement for
- // @synchronized.
- llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot);
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncExitFn(), SyncArg);
- }
- }
- };
-
- class FragileHazards {
- CodeGenFunction &CGF;
- SmallVector<llvm::Value*, 20> Locals;
- llvm::DenseSet<llvm::BasicBlock*> BlocksBeforeTry;
-
- llvm::InlineAsm *ReadHazard;
- llvm::InlineAsm *WriteHazard;
-
- llvm::FunctionType *GetAsmFnType();
-
- void collectLocals();
- void emitReadHazard(CGBuilderTy &Builder);
-
- public:
- FragileHazards(CodeGenFunction &CGF);
-
- void emitWriteHazard();
- void emitHazardsInNewBlocks();
- };
-} // end anonymous namespace
-
-/// Create the fragile-ABI read and write hazards based on the current
-/// state of the function, which is presumed to be immediately prior
-/// to a @try block. These hazards are used to maintain correct
-/// semantics in the face of optimization and the fragile ABI's
-/// cavalier use of setjmp/longjmp.
-FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
- collectLocals();
-
- if (Locals.empty()) return;
-
- // Collect all the blocks in the function.
- for (llvm::Function::iterator
- I = CGF.CurFn->begin(), E = CGF.CurFn->end(); I != E; ++I)
- BlocksBeforeTry.insert(&*I);
-
- llvm::FunctionType *AsmFnTy = GetAsmFnType();
-
- // Create a read hazard for the allocas. This inhibits dead-store
- // optimizations and forces the values to memory. This hazard is
- // inserted before any 'throwing' calls in the protected scope to
- // reflect the possibility that the variables might be read from the
- // catch block if the call throws.
- {
- std::string Constraint;
- for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
- if (I) Constraint += ',';
- Constraint += "*m";
- }
-
- ReadHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
- }
-
- // Create a write hazard for the allocas. This inhibits folding
- // loads across the hazard. This hazard is inserted at the
- // beginning of the catch path to reflect the possibility that the
- // variables might have been written within the protected scope.
- {
- std::string Constraint;
- for (unsigned I = 0, E = Locals.size(); I != E; ++I) {
- if (I) Constraint += ',';
- Constraint += "=*m";
- }
-
- WriteHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false);
- }
-}
-
-/// Emit a write hazard at the current location.
-void FragileHazards::emitWriteHazard() {
- if (Locals.empty()) return;
-
- CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
-}
-
-void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
- assert(!Locals.empty());
- llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals);
- call->setDoesNotThrow();
- call->setCallingConv(CGF.getRuntimeCC());
-}
-
-/// Emit read hazards in all the protected blocks, i.e. all the blocks
-/// which have been inserted since the beginning of the try.
-void FragileHazards::emitHazardsInNewBlocks() {
- if (Locals.empty()) return;
-
- CGBuilderTy Builder(CGF, CGF.getLLVMContext());
-
- // Iterate through all blocks, skipping those prior to the try.
- for (llvm::Function::iterator
- FI = CGF.CurFn->begin(), FE = CGF.CurFn->end(); FI != FE; ++FI) {
- llvm::BasicBlock &BB = *FI;
- if (BlocksBeforeTry.count(&BB)) continue;
-
- // Walk through all the calls in the block.
- for (llvm::BasicBlock::iterator
- BI = BB.begin(), BE = BB.end(); BI != BE; ++BI) {
- llvm::Instruction &I = *BI;
-
- // Ignore instructions that aren't non-intrinsic calls.
- // These are the only calls that can possibly call longjmp.
- if (!isa<llvm::CallInst>(I) && !isa<llvm::InvokeInst>(I)) continue;
- if (isa<llvm::IntrinsicInst>(I))
- continue;
-
- // Ignore call sites marked nounwind. This may be questionable,
- // since 'nounwind' doesn't necessarily mean 'does not call longjmp'.
- llvm::CallSite CS(&I);
- if (CS.doesNotThrow()) continue;
-
- // Insert a read hazard before the call. This will ensure that
- // any writes to the locals are performed before making the
- // call. If the call throws, then this is sufficient to
- // guarantee correctness as long as it doesn't also write to any
- // locals.
- Builder.SetInsertPoint(&BB, BI);
- emitReadHazard(Builder);
- }
- }
-}
-
-static void addIfPresent(llvm::DenseSet<llvm::Value*> &S, Address V) {
- if (V.isValid()) S.insert(V.getPointer());
-}
-
-void FragileHazards::collectLocals() {
- // Compute a set of allocas to ignore.
- llvm::DenseSet<llvm::Value*> AllocasToIgnore;
- addIfPresent(AllocasToIgnore, CGF.ReturnValue);
- addIfPresent(AllocasToIgnore, CGF.NormalCleanupDest);
-
- // Collect all the allocas currently in the function. This is
- // probably way too aggressive.
- llvm::BasicBlock &Entry = CGF.CurFn->getEntryBlock();
- for (llvm::BasicBlock::iterator
- I = Entry.begin(), E = Entry.end(); I != E; ++I)
- if (isa<llvm::AllocaInst>(*I) && !AllocasToIgnore.count(&*I))
- Locals.push_back(&*I);
-}
-
-llvm::FunctionType *FragileHazards::GetAsmFnType() {
- SmallVector<llvm::Type *, 16> tys(Locals.size());
- for (unsigned i = 0, e = Locals.size(); i != e; ++i)
- tys[i] = Locals[i]->getType();
- return llvm::FunctionType::get(CGF.VoidTy, tys, false);
-}
-
-/*
-
- Objective-C setjmp-longjmp (sjlj) Exception Handling
- --
-
- A catch buffer is a setjmp buffer plus:
- - a pointer to the exception that was caught
- - a pointer to the previous exception data buffer
- - two pointers of reserved storage
- Therefore catch buffers form a stack, with a pointer to the top
- of the stack kept in thread-local storage.
-
- objc_exception_try_enter pushes a catch buffer onto the EH stack.
- objc_exception_try_exit pops the given catch buffer, which is
- required to be the top of the EH stack.
- objc_exception_throw pops the top of the EH stack, writes the
- thrown exception into the appropriate field, and longjmps
- to the setjmp buffer. It crashes the process (with a printf
- and an abort()) if there are no catch buffers on the stack.
- objc_exception_extract just reads the exception pointer out of the
- catch buffer.
-
- There's no reason an implementation couldn't use a light-weight
- setjmp here --- something like __builtin_setjmp, but API-compatible
- with the heavyweight setjmp. This will be more important if we ever
- want to implement correct ObjC/C++ exception interactions for the
- fragile ABI.
-
- Note that for this use of setjmp/longjmp to be correct, we may need
- to mark some local variables volatile: if a non-volatile local
- variable is modified between the setjmp and the longjmp, it has
- indeterminate value. For the purposes of LLVM IR, it may be
- sufficient to make loads and stores within the @try (to variables
- declared outside the @try) volatile. This is necessary for
- optimized correctness, but is not currently being done; this is
- being tracked as rdar://problem/8160285
-
- The basic framework for a @try-catch-finally is as follows:
- {
- objc_exception_data d;
- id _rethrow = null;
- bool _call_try_exit = true;
-
- objc_exception_try_enter(&d);
- if (!setjmp(d.jmp_buf)) {
- ... try body ...
- } else {
- // exception path
- id _caught = objc_exception_extract(&d);
-
- // enter new try scope for handlers
- if (!setjmp(d.jmp_buf)) {
- ... match exception and execute catch blocks ...
-
- // fell off end, rethrow.
- _rethrow = _caught;
- ... jump-through-finally to finally_rethrow ...
- } else {
- // exception in catch block
- _rethrow = objc_exception_extract(&d);
- _call_try_exit = false;
- ... jump-through-finally to finally_rethrow ...
- }
- }
- ... jump-through-finally to finally_end ...
-
- finally:
- if (_call_try_exit)
- objc_exception_try_exit(&d);
-
- ... finally block ....
- ... dispatch to finally destination ...
-
- finally_rethrow:
- objc_exception_throw(_rethrow);
-
- finally_end:
- }
-
- This framework differs slightly from the one gcc uses, in that gcc
- uses _rethrow to determine if objc_exception_try_exit should be called
- and if the object should be rethrown. This breaks in the face of
- throwing nil and introduces unnecessary branches.
-
- We specialize this framework for a few particular circumstances:
-
- - If there are no catch blocks, then we avoid emitting the second
- exception handling context.
-
- - If there is a catch-all catch block (i.e. @catch(...) or @catch(id
- e)) we avoid emitting the code to rethrow an uncaught exception.
-
- - FIXME: If there is no @finally block we can do a few more
- simplifications.
-
- Rethrows and Jumps-Through-Finally
- --
-
- '@throw;' is supported by pushing the currently-caught exception
- onto ObjCEHStack while the @catch blocks are emitted.
-
- Branches through the @finally block are handled with an ordinary
- normal cleanup. We do not register an EH cleanup; fragile-ABI ObjC
- exceptions are not compatible with C++ exceptions, and this is
- hardly the only place where this will go wrong.
-
- @synchronized(expr) { stmt; } is emitted as if it were:
- id synch_value = expr;
- objc_sync_enter(synch_value);
- @try { stmt; } @finally { objc_sync_exit(synch_value); }
-*/
-
-void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const Stmt &S) {
- bool isTry = isa<ObjCAtTryStmt>(S);
-
- // A destination for the fall-through edges of the catch handlers to
- // jump to.
- CodeGenFunction::JumpDest FinallyEnd =
- CGF.getJumpDestInCurrentScope("finally.end");
-
- // A destination for the rethrow edge of the catch handlers to jump
- // to.
- CodeGenFunction::JumpDest FinallyRethrow =
- CGF.getJumpDestInCurrentScope("finally.rethrow");
-
- // For @synchronized, call objc_sync_enter(sync.expr). The
- // evaluation of the expression must occur before we enter the
- // @synchronized. We can't avoid a temp here because we need the
- // value to be preserved. If the backend ever does liveness
- // correctly after setjmp, this will be unnecessary.
- Address SyncArgSlot = Address::invalid();
- if (!isTry) {
- llvm::Value *SyncArg =
- CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
- SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncEnterFn(), SyncArg);
-
- SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(),
- CGF.getPointerAlign(), "sync.arg");
- CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
- }
-
- // Allocate memory for the setjmp buffer. This needs to be kept
- // live throughout the try and catch blocks.
- Address ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
- CGF.getPointerAlign(),
- "exceptiondata.ptr");
-
- // Create the fragile hazards. Note that this will not capture any
- // of the allocas required for exception processing, but will
- // capture the current basic block (which extends all the way to the
- // setjmp call) as "before the @try".
- FragileHazards Hazards(CGF);
-
- // Create a flag indicating whether the cleanup needs to call
- // objc_exception_try_exit. This is true except when
- // - no catches match and we're branching through the cleanup
- // just to rethrow the exception, or
- // - a catch matched and we're falling out of the catch handler.
- // The setjmp-safety rule here is that we should always store to this
- // variable in a place that dominates the branch through the cleanup
- // without passing through any setjmps.
- Address CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(),
- CharUnits::One(),
- "_call_try_exit");
-
- // A slot containing the exception to rethrow. Only needed when we
- // have both a @catch and a @finally.
- Address PropagatingExnVar = Address::invalid();
-
- // Push a normal cleanup to leave the try scope.
- CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
- SyncArgSlot,
- CallTryExitVar,
- ExceptionData,
- &ObjCTypes);
-
- // Enter a try block:
- // - Call objc_exception_try_enter to push ExceptionData on top of
- // the EH stack.
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
- ExceptionData.getPointer());
-
- // - Call setjmp on the exception data buffer.
- llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
- llvm::Value *GEPIndexes[] = { Zero, Zero, Zero };
- llvm::Value *SetJmpBuffer = CGF.Builder.CreateGEP(
- ObjCTypes.ExceptionDataTy, ExceptionData.getPointer(), GEPIndexes,
- "setjmp_buffer");
- llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall(
- ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
- SetJmpResult->setCanReturnTwice();
-
- // If setjmp returned 0, enter the protected block; otherwise,
- // branch to the handler.
- llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
- llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
- llvm::Value *DidCatch =
- CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
- CGF.Builder.CreateCondBr(DidCatch, TryHandler, TryBlock);
-
- // Emit the protected block.
- CGF.EmitBlock(TryBlock);
- CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
- CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
- : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
-
- CGBuilderTy::InsertPoint TryFallthroughIP = CGF.Builder.saveAndClearIP();
-
- // Emit the exception handler block.
- CGF.EmitBlock(TryHandler);
-
- // Don't optimize loads of the in-scope locals across this point.
- Hazards.emitWriteHazard();
-
- // For a @synchronized (or a @try with no catches), just branch
- // through the cleanup to the rethrow block.
- if (!isTry || !cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
- // Tell the cleanup not to re-pop the exit.
- CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
- CGF.EmitBranchThroughCleanup(FinallyRethrow);
-
- // Otherwise, we have to match against the caught exceptions.
- } else {
- // Retrieve the exception object. We may emit multiple blocks but
- // nothing can cross this so the value is already in SSA form.
- llvm::CallInst *Caught =
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData.getPointer(), "caught");
-
- // Push the exception to rethrow onto the EH value stack for the
- // benefit of any @throws in the handlers.
- CGF.ObjCEHValueStack.push_back(Caught);
-
- const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
-
- bool HasFinally = (AtTryStmt->getFinallyStmt() != nullptr);
-
- llvm::BasicBlock *CatchBlock = nullptr;
- llvm::BasicBlock *CatchHandler = nullptr;
- if (HasFinally) {
- // Save the currently-propagating exception before
- // objc_exception_try_enter clears the exception slot.
- PropagatingExnVar = CGF.CreateTempAlloca(Caught->getType(),
- CGF.getPointerAlign(),
- "propagating_exception");
- CGF.Builder.CreateStore(Caught, PropagatingExnVar);
-
- // Enter a new exception try block (in case a @catch block
- // throws an exception).
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
- ExceptionData.getPointer());
-
- llvm::CallInst *SetJmpResult =
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(),
- SetJmpBuffer, "setjmp.result");
- SetJmpResult->setCanReturnTwice();
-
- llvm::Value *Threw =
- CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
-
- CatchBlock = CGF.createBasicBlock("catch");
- CatchHandler = CGF.createBasicBlock("catch_for_catch");
- CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock);
-
- CGF.EmitBlock(CatchBlock);
- }
-
- CGF.Builder.CreateStore(CGF.Builder.getInt1(HasFinally), CallTryExitVar);
-
- // Handle catch list. As a special case we check if everything is
- // matched and avoid generating code for falling off the end if
- // so.
- bool AllMatched = false;
- for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) {
- const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I);
-
- const VarDecl *CatchParam = CatchStmt->getCatchParamDecl();
- const ObjCObjectPointerType *OPT = nullptr;
-
- // catch(...) always matches.
- if (!CatchParam) {
- AllMatched = true;
- } else {
- OPT = CatchParam->getType()->getAs<ObjCObjectPointerType>();
-
- // catch(id e) always matches under this ABI, since only
- // ObjC exceptions end up here in the first place.
- // FIXME: For the time being we also match id<X>; this should
- // be rejected by Sema instead.
- if (OPT && (OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()))
- AllMatched = true;
- }
-
- // If this is a catch-all, we don't need to test anything.
- if (AllMatched) {
- CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
-
- if (CatchParam) {
- CGF.EmitAutoVarDecl(*CatchParam);
- assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
-
- // These types work out because ConvertType(id) == i8*.
- EmitInitOfCatchParam(CGF, Caught, CatchParam);
- }
-
- CGF.EmitStmt(CatchStmt->getCatchBody());
-
- // The scope of the catch variable ends right here.
- CatchVarCleanups.ForceCleanup();
-
- CGF.EmitBranchThroughCleanup(FinallyEnd);
- break;
- }
-
- assert(OPT && "Unexpected non-object pointer type in @catch");
- const ObjCObjectType *ObjTy = OPT->getObjectType();
-
- // FIXME: @catch (Class c) ?
- ObjCInterfaceDecl *IDecl = ObjTy->getInterface();
- assert(IDecl && "Catch parameter must have Objective-C type!");
-
- // Check if the @catch block matches the exception object.
- llvm::Value *Class = EmitClassRef(CGF, IDecl);
-
- llvm::Value *matchArgs[] = { Class, Caught };
- llvm::CallInst *Match =
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionMatchFn(),
- matchArgs, "match");
-
- llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("match");
- llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch.next");
-
- CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(Match, "matched"),
- MatchedBlock, NextCatchBlock);
-
- // Emit the @catch block.
- CGF.EmitBlock(MatchedBlock);
-
- // Collect any cleanups for the catch variable. The scope lasts until
- // the end of the catch body.
- CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF);
-
- CGF.EmitAutoVarDecl(*CatchParam);
- assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
-
- // Initialize the catch variable.
- llvm::Value *Tmp =
- CGF.Builder.CreateBitCast(Caught,
- CGF.ConvertType(CatchParam->getType()));
- EmitInitOfCatchParam(CGF, Tmp, CatchParam);
-
- CGF.EmitStmt(CatchStmt->getCatchBody());
-
- // We're done with the catch variable.
- CatchVarCleanups.ForceCleanup();
-
- CGF.EmitBranchThroughCleanup(FinallyEnd);
-
- CGF.EmitBlock(NextCatchBlock);
- }
-
- CGF.ObjCEHValueStack.pop_back();
-
- // If nothing wanted anything to do with the caught exception,
- // kill the extract call.
- if (Caught->use_empty())
- Caught->eraseFromParent();
-
- if (!AllMatched)
- CGF.EmitBranchThroughCleanup(FinallyRethrow);
-
- if (HasFinally) {
- // Emit the exception handler for the @catch blocks.
- CGF.EmitBlock(CatchHandler);
-
- // In theory we might now need a write hazard, but actually it's
- // unnecessary because there's no local-accessing code between
- // the try's write hazard and here.
- //Hazards.emitWriteHazard();
-
- // Extract the new exception and save it to the
- // propagating-exception slot.
- assert(PropagatingExnVar.isValid());
- llvm::CallInst *NewCaught =
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData.getPointer(), "caught");
- CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
-
- // Don't pop the catch handler; the throw already did.
- CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
- CGF.EmitBranchThroughCleanup(FinallyRethrow);
- }
- }
-
- // Insert read hazards as required in the new blocks.
- Hazards.emitHazardsInNewBlocks();
-
- // Pop the cleanup.
- CGF.Builder.restoreIP(TryFallthroughIP);
- if (CGF.HaveInsertPoint())
- CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar);
- CGF.PopCleanupBlock();
- CGF.EmitBlock(FinallyEnd.getBlock(), true);
-
- // Emit the rethrow block.
- CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
- CGF.EmitBlock(FinallyRethrow.getBlock(), true);
- if (CGF.HaveInsertPoint()) {
- // If we have a propagating-exception variable, check it.
- llvm::Value *PropagatingExn;
- if (PropagatingExnVar.isValid()) {
- PropagatingExn = CGF.Builder.CreateLoad(PropagatingExnVar);
-
- // Otherwise, just look in the buffer for the exception to throw.
- } else {
- llvm::CallInst *Caught =
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData.getPointer());
- PropagatingExn = Caught;
- }
-
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionThrowFn(),
- PropagatingExn);
- CGF.Builder.CreateUnreachable();
- }
-
- CGF.Builder.restoreIP(SavedIP);
-}
-
-void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint) {
- llvm::Value *ExceptionAsObject;
-
- if (const Expr *ThrowExpr = S.getThrowExpr()) {
- llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
- ExceptionAsObject =
- CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
- } else {
- assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
- "Unexpected rethrow outside @catch block.");
- ExceptionAsObject = CGF.ObjCEHValueStack.back();
- }
-
- CGF.EmitRuntimeCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
- ->setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
-
- // Clear the insertion point to indicate we are in unreachable code.
- if (ClearInsertionPoint)
- CGF.Builder.ClearInsertionPoint();
-}
-
-/// EmitObjCWeakRead - Code gen for loading value of a __weak
-/// object: objc_read_weak (id *src)
-///
-llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- Address AddrWeakObj) {
- llvm::Type* DestTy = AddrWeakObj.getElementType();
- AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
- ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak =
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj.getPointer(), "weakread");
- read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
- return read_weak;
-}
-
-/// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
-/// objc_assign_weak (id src, id *dst)
-///
-void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst) {
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
- : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer() };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
- args, "weakassign");
-}
-
-/// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
-/// objc_assign_global (id src, id *dst)
-///
-void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst,
- bool threadlocal) {
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
- : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer() };
- if (!threadlocal)
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
- args, "globalassign");
- else
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
- args, "threadlocalassign");
-}
-
-/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
-/// objc_assign_ivar (id src, id *dst, ptrdiff_t ivaroffset)
-///
-void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst,
- llvm::Value *ivarOffset) {
- assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
- : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer(), ivarOffset };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
-}
-
-/// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
-/// objc_assign_strongCast (id src, id *dst)
-///
-void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst) {
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty)
- : CGF.Builder.CreateBitCast(src, CGM.Int64Ty);
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer() };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
- args, "strongassign");
-}
-
-void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- Address DestPtr,
- Address SrcPtr,
- llvm::Value *size) {
- SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
- DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), size };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
-}
-
-/// EmitObjCValueForIvar - Code Gen for ivar reference.
-///
-LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) {
- const ObjCInterfaceDecl *ID =
- ObjectTy->getAs<ObjCObjectType>()->getInterface();
- return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
- EmitIvarOffset(CGF, ID, Ivar));
-}
-
-llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) {
- uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar);
- return llvm::ConstantInt::get(
- CGM.getTypes().ConvertType(CGM.getContext().LongTy),
- Offset);
-}
-
-/* *** Private Interface *** */
-
-std::string CGObjCCommonMac::GetSectionName(StringRef Section,
- StringRef MachOAttributes) {
- switch (CGM.getTriple().getObjectFormat()) {
- default:
- llvm_unreachable("unexpected object file format");
- case llvm::Triple::MachO: {
- if (MachOAttributes.empty())
- return ("__DATA," + Section).str();
- return ("__DATA," + Section + "," + MachOAttributes).str();
- }
- case llvm::Triple::ELF:
- assert(Section.substr(0, 2) == "__" &&
- "expected the name to begin with __");
- return Section.substr(2).str();
- case llvm::Triple::COFF:
- assert(Section.substr(0, 2) == "__" &&
- "expected the name to begin with __");
- return ("." + Section.substr(2) + "$B").str();
- }
-}
-
-/// EmitImageInfo - Emit the image info marker used to encode some module
-/// level information.
-///
-/// See: <rdr://4810609&4810587&4810587>
-/// struct IMAGE_INFO {
-/// unsigned version;
-/// unsigned flags;
-/// };
-enum ImageInfoFlags {
- eImageInfo_FixAndContinue = (1 << 0), // This flag is no longer set by clang.
- eImageInfo_GarbageCollected = (1 << 1),
- eImageInfo_GCOnly = (1 << 2),
- eImageInfo_OptimizedByDyld = (1 << 3), // This flag is set by the dyld shared cache.
-
- // A flag indicating that the module has no instances of a @synthesize of a
- // superclass variable. <rdar://problem/6803242>
- eImageInfo_CorrectedSynthesize = (1 << 4), // This flag is no longer set by clang.
- eImageInfo_ImageIsSimulated = (1 << 5),
- eImageInfo_ClassProperties = (1 << 6)
-};
-
-void CGObjCCommonMac::EmitImageInfo() {
- unsigned version = 0; // Version is unused?
- std::string Section =
- (ObjCABI == 1)
- ? "__OBJC,__image_info,regular"
- : GetSectionName("__objc_imageinfo", "regular,no_dead_strip");
-
- // Generate module-level named metadata to convey this information to the
- // linker and code-gen.
- llvm::Module &Mod = CGM.getModule();
-
- // Add the ObjC ABI version to the module flags.
- Mod.addModuleFlag(llvm::Module::Error, "Objective-C Version", ObjCABI);
- Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
- version);
- Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
- llvm::MDString::get(VMContext, Section));
-
- if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
- // Non-GC overrides those files which specify GC.
- Mod.addModuleFlag(llvm::Module::Override,
- "Objective-C Garbage Collection", (uint32_t)0);
- } else {
- // Add the ObjC garbage collection value.
- Mod.addModuleFlag(llvm::Module::Error,
- "Objective-C Garbage Collection",
- eImageInfo_GarbageCollected);
-
- if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
- // Add the ObjC GC Only value.
- Mod.addModuleFlag(llvm::Module::Error, "Objective-C GC Only",
- eImageInfo_GCOnly);
-
- // Require that GC be specified and set to eImageInfo_GarbageCollected.
- llvm::Metadata *Ops[2] = {
- llvm::MDString::get(VMContext, "Objective-C Garbage Collection"),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), eImageInfo_GarbageCollected))};
- Mod.addModuleFlag(llvm::Module::Require, "Objective-C GC Only",
- llvm::MDNode::get(VMContext, Ops));
- }
- }
-
- // Indicate whether we're compiling this to run on a simulator.
- if (CGM.getTarget().getTriple().isSimulatorEnvironment())
- Mod.addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated",
- eImageInfo_ImageIsSimulated);
-
- // Indicate whether we are generating class properties.
- Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties",
- eImageInfo_ClassProperties);
-}
-
-// struct objc_module {
-// unsigned long version;
-// unsigned long size;
-// const char *name;
-// Symtab symtab;
-// };
-
-// FIXME: Get from somewhere
-static const int ModuleVersion = 7;
-
-void CGObjCMac::EmitModuleInfo() {
- uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ModuleTy);
- values.addInt(ObjCTypes.LongTy, ModuleVersion);
- values.addInt(ObjCTypes.LongTy, Size);
- // This used to be the filename, now it is unused. <rdr://4327263>
- values.add(GetClassName(StringRef("")));
- values.add(EmitModuleSymbols());
- CreateMetadataVar("OBJC_MODULES", values,
- "__OBJC,__module_info,regular,no_dead_strip",
- CGM.getPointerAlign(), true);
-}
-
-llvm::Constant *CGObjCMac::EmitModuleSymbols() {
- unsigned NumClasses = DefinedClasses.size();
- unsigned NumCategories = DefinedCategories.size();
-
- // Return null if no symbols were defined.
- if (!NumClasses && !NumCategories)
- return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
- values.addInt(ObjCTypes.LongTy, 0);
- values.addNullPointer(ObjCTypes.SelectorPtrTy);
- values.addInt(ObjCTypes.ShortTy, NumClasses);
- values.addInt(ObjCTypes.ShortTy, NumCategories);
-
- // The runtime expects exactly the list of defined classes followed
- // by the list of defined categories, in a single array.
- auto array = values.beginArray(ObjCTypes.Int8PtrTy);
- for (unsigned i=0; i<NumClasses; i++) {
- const ObjCInterfaceDecl *ID = ImplementedClasses[i];
- assert(ID);
- if (ObjCImplementationDecl *IMP = ID->getImplementation())
- // We are implementing a weak imported interface. Give it external linkage
- if (ID->isWeakImported() && !IMP->isWeakImported())
- DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
-
- array.addBitCast(DefinedClasses[i], ObjCTypes.Int8PtrTy);
- }
- for (unsigned i=0; i<NumCategories; i++)
- array.addBitCast(DefinedCategories[i], ObjCTypes.Int8PtrTy);
-
- array.finishAndAddTo(values);
-
- llvm::GlobalVariable *GV = CreateMetadataVar(
- "OBJC_SYMBOLS", values, "__OBJC,__symbols,regular,no_dead_strip",
- CGM.getPointerAlign(), true);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
-}
-
-llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
- IdentifierInfo *II) {
- LazySymbols.insert(II);
-
- llvm::GlobalVariable *&Entry = ClassReferences[II];
-
- if (!Entry) {
- llvm::Constant *Casted =
- llvm::ConstantExpr::getBitCast(GetClassName(II->getName()),
- ObjCTypes.ClassPtrTy);
- Entry = CreateMetadataVar(
- "OBJC_CLASS_REFERENCES_", Casted,
- "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
- CGM.getPointerAlign(), true);
- }
-
- return CGF.Builder.CreateAlignedLoad(Entry, CGF.getPointerAlign());
-}
-
-llvm::Value *CGObjCMac::EmitClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) {
- // If the class has the objc_runtime_visible attribute, we need to
- // use the Objective-C runtime to get the class.
- if (ID->hasAttr<ObjCRuntimeVisibleAttr>())
- return EmitClassRefViaRuntime(CGF, ID, ObjCTypes);
-
- IdentifierInfo *RuntimeName =
- &CGM.getContext().Idents.get(ID->getObjCRuntimeNameAsString());
- return EmitClassRefFromId(CGF, RuntimeName);
-}
-
-llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
- IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(CGF, II);
-}
-
-llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) {
- return CGF.Builder.CreateLoad(EmitSelectorAddr(CGF, Sel));
-}
-
-Address CGObjCMac::EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel) {
- CharUnits Align = CGF.getPointerAlign();
-
- llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
- if (!Entry) {
- llvm::Constant *Casted =
- llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
- ObjCTypes.SelectorPtrTy);
- Entry = CreateMetadataVar(
- "OBJC_SELECTOR_REFERENCES_", Casted,
- "__OBJC,__message_refs,literal_pointers,no_dead_strip", Align, true);
- Entry->setExternallyInitialized(true);
- }
-
- return Address(Entry, Align);
-}
-
-llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) {
- llvm::GlobalVariable *&Entry = ClassNames[RuntimeName];
- if (!Entry)
- Entry = CreateCStringLiteral(RuntimeName, ObjCLabelType::ClassName);
- return getConstantGEP(VMContext, Entry, 0, 0);
-}
-
-llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) {
- llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*>::iterator
- I = MethodDefinitions.find(MD);
- if (I != MethodDefinitions.end())
- return I->second;
-
- return nullptr;
-}
-
-/// GetIvarLayoutName - Returns a unique constant for the given
-/// ivar layout bitmap.
-llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident,
- const ObjCCommonTypesHelper &ObjCTypes) {
- return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
-}
-
-void IvarLayoutBuilder::visitRecord(const RecordType *RT,
- CharUnits offset) {
- const RecordDecl *RD = RT->getDecl();
-
- // If this is a union, remember that we had one, because it might mess
- // up the ordering of layout entries.
- if (RD->isUnion())
- IsDisordered = true;
-
- const ASTRecordLayout *recLayout = nullptr;
- visitAggregate(RD->field_begin(), RD->field_end(), offset,
- [&](const FieldDecl *field) -> CharUnits {
- if (!recLayout)
- recLayout = &CGM.getContext().getASTRecordLayout(RD);
- auto offsetInBits = recLayout->getFieldOffset(field->getFieldIndex());
- return CGM.getContext().toCharUnitsFromBits(offsetInBits);
- });
-}
-
-template <class Iterator, class GetOffsetFn>
-void IvarLayoutBuilder::visitAggregate(Iterator begin, Iterator end,
- CharUnits aggregateOffset,
- const GetOffsetFn &getOffset) {
- for (; begin != end; ++begin) {
- auto field = *begin;
-
- // Skip over bitfields.
- if (field->isBitField()) {
- continue;
- }
-
- // Compute the offset of the field within the aggregate.
- CharUnits fieldOffset = aggregateOffset + getOffset(field);
-
- visitField(field, fieldOffset);
- }
-}
-
-/// Collect layout information for the given fields into IvarsInfo.
-void IvarLayoutBuilder::visitField(const FieldDecl *field,
- CharUnits fieldOffset) {
- QualType fieldType = field->getType();
-
- // Drill down into arrays.
- uint64_t numElts = 1;
- if (auto arrayType = CGM.getContext().getAsIncompleteArrayType(fieldType)) {
- numElts = 0;
- fieldType = arrayType->getElementType();
- }
- // Unlike incomplete arrays, constant arrays can be nested.
- while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) {
- numElts *= arrayType->getSize().getZExtValue();
- fieldType = arrayType->getElementType();
- }
-
- assert(!fieldType->isArrayType() && "ivar of non-constant array type?");
-
- // If we ended up with a zero-sized array, we've done what we can do within
- // the limits of this layout encoding.
- if (numElts == 0) return;
-
- // Recurse if the base element type is a record type.
- if (auto recType = fieldType->getAs<RecordType>()) {
- size_t oldEnd = IvarsInfo.size();
-
- visitRecord(recType, fieldOffset);
-
- // If we have an array, replicate the first entry's layout information.
- auto numEltEntries = IvarsInfo.size() - oldEnd;
- if (numElts != 1 && numEltEntries != 0) {
- CharUnits eltSize = CGM.getContext().getTypeSizeInChars(recType);
- for (uint64_t eltIndex = 1; eltIndex != numElts; ++eltIndex) {
- // Copy the last numEltEntries onto the end of the array, adjusting
- // each for the element size.
- for (size_t i = 0; i != numEltEntries; ++i) {
- auto firstEntry = IvarsInfo[oldEnd + i];
- IvarsInfo.push_back(IvarInfo(firstEntry.Offset + eltIndex * eltSize,
- firstEntry.SizeInWords));
- }
- }
- }
-
- return;
- }
-
- // Classify the element type.
- Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), fieldType);
-
- // If it matches what we're looking for, add an entry.
- if ((ForStrongLayout && GCAttr == Qualifiers::Strong)
- || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) {
- assert(CGM.getContext().getTypeSizeInChars(fieldType)
- == CGM.getPointerSize());
- IvarsInfo.push_back(IvarInfo(fieldOffset, numElts));
- }
-}
-
-/// buildBitmap - This routine does the horsework of taking the offsets of
-/// strong/weak references and creating a bitmap. The bitmap is also
-/// returned in the given buffer, suitable for being passed to \c dump().
-llvm::Constant *IvarLayoutBuilder::buildBitmap(CGObjCCommonMac &CGObjC,
- llvm::SmallVectorImpl<unsigned char> &buffer) {
- // The bitmap is a series of skip/scan instructions, aligned to word
- // boundaries. The skip is performed first.
- const unsigned char MaxNibble = 0xF;
- const unsigned char SkipMask = 0xF0, SkipShift = 4;
- const unsigned char ScanMask = 0x0F, ScanShift = 0;
-
- assert(!IvarsInfo.empty() && "generating bitmap for no data");
-
- // Sort the ivar info on byte position in case we encounterred a
- // union nested in the ivar list.
- if (IsDisordered) {
- // This isn't a stable sort, but our algorithm should handle it fine.
- llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end());
- } else {
- assert(std::is_sorted(IvarsInfo.begin(), IvarsInfo.end()));
- }
- assert(IvarsInfo.back().Offset < InstanceEnd);
-
- assert(buffer.empty());
-
- // Skip the next N words.
- auto skip = [&](unsigned numWords) {
- assert(numWords > 0);
-
- // Try to merge into the previous byte. Since scans happen second, we
- // can't do this if it includes a scan.
- if (!buffer.empty() && !(buffer.back() & ScanMask)) {
- unsigned lastSkip = buffer.back() >> SkipShift;
- if (lastSkip < MaxNibble) {
- unsigned claimed = std::min(MaxNibble - lastSkip, numWords);
- numWords -= claimed;
- lastSkip += claimed;
- buffer.back() = (lastSkip << SkipShift);
- }
- }
-
- while (numWords >= MaxNibble) {
- buffer.push_back(MaxNibble << SkipShift);
- numWords -= MaxNibble;
- }
- if (numWords) {
- buffer.push_back(numWords << SkipShift);
- }
- };
-
- // Scan the next N words.
- auto scan = [&](unsigned numWords) {
- assert(numWords > 0);
-
- // Try to merge into the previous byte. Since scans happen second, we can
- // do this even if it includes a skip.
- if (!buffer.empty()) {
- unsigned lastScan = (buffer.back() & ScanMask) >> ScanShift;
- if (lastScan < MaxNibble) {
- unsigned claimed = std::min(MaxNibble - lastScan, numWords);
- numWords -= claimed;
- lastScan += claimed;
- buffer.back() = (buffer.back() & SkipMask) | (lastScan << ScanShift);
- }
- }
-
- while (numWords >= MaxNibble) {
- buffer.push_back(MaxNibble << ScanShift);
- numWords -= MaxNibble;
- }
- if (numWords) {
- buffer.push_back(numWords << ScanShift);
- }
- };
-
- // One past the end of the last scan.
- unsigned endOfLastScanInWords = 0;
- const CharUnits WordSize = CGM.getPointerSize();
-
- // Consider all the scan requests.
- for (auto &request : IvarsInfo) {
- CharUnits beginOfScan = request.Offset - InstanceBegin;
-
- // Ignore scan requests that don't start at an even multiple of the
- // word size. We can't encode them.
- if ((beginOfScan % WordSize) != 0) continue;
-
- // Ignore scan requests that start before the instance start.
- // This assumes that scans never span that boundary. The boundary
- // isn't the true start of the ivars, because in the fragile-ARC case
- // it's rounded up to word alignment, but the test above should leave
- // us ignoring that possibility.
- if (beginOfScan.isNegative()) {
- assert(request.Offset + request.SizeInWords * WordSize <= InstanceBegin);
- continue;
- }
-
- unsigned beginOfScanInWords = beginOfScan / WordSize;
- unsigned endOfScanInWords = beginOfScanInWords + request.SizeInWords;
-
- // If the scan starts some number of words after the last one ended,
- // skip forward.
- if (beginOfScanInWords > endOfLastScanInWords) {
- skip(beginOfScanInWords - endOfLastScanInWords);
-
- // Otherwise, start scanning where the last left off.
- } else {
- beginOfScanInWords = endOfLastScanInWords;
-
- // If that leaves us with nothing to scan, ignore this request.
- if (beginOfScanInWords >= endOfScanInWords) continue;
- }
-
- // Scan to the end of the request.
- assert(beginOfScanInWords < endOfScanInWords);
- scan(endOfScanInWords - beginOfScanInWords);
- endOfLastScanInWords = endOfScanInWords;
- }
-
- if (buffer.empty())
- return llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
-
- // For GC layouts, emit a skip to the end of the allocation so that we
- // have precise information about the entire thing. This isn't useful
- // or necessary for the ARC-style layout strings.
- if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
- unsigned lastOffsetInWords =
- (InstanceEnd - InstanceBegin + WordSize - CharUnits::One()) / WordSize;
- if (lastOffsetInWords > endOfLastScanInWords) {
- skip(lastOffsetInWords - endOfLastScanInWords);
- }
- }
-
- // Null terminate the string.
- buffer.push_back(0);
-
- auto *Entry = CGObjC.CreateCStringLiteral(
- reinterpret_cast<char *>(buffer.data()), ObjCLabelType::ClassName);
- return getConstantGEP(CGM.getLLVMContext(), Entry, 0, 0);
-}
-
-/// BuildIvarLayout - Builds ivar layout bitmap for the class
-/// implementation for the __strong or __weak case.
-/// The layout map displays which words in ivar list must be skipped
-/// and which must be scanned by GC (see below). String is built of bytes.
-/// Each byte is divided up in two nibbles (4-bit each). Left nibble is count
-/// of words to skip and right nibble is count of words to scan. So, each
-/// nibble represents up to 15 workds to skip or scan. Skipping the rest is
-/// represented by a 0x00 byte which also ends the string.
-/// 1. when ForStrongLayout is true, following ivars are scanned:
-/// - id, Class
-/// - object *
-/// - __strong anything
-///
-/// 2. When ForStrongLayout is false, following ivars are scanned:
-/// - __weak anything
-///
-llvm::Constant *
-CGObjCCommonMac::BuildIvarLayout(const ObjCImplementationDecl *OMD,
- CharUnits beginOffset, CharUnits endOffset,
- bool ForStrongLayout, bool HasMRCWeakIvars) {
- // If this is MRC, and we're either building a strong layout or there
- // are no weak ivars, bail out early.
- llvm::Type *PtrTy = CGM.Int8PtrTy;
- if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- !CGM.getLangOpts().ObjCAutoRefCount &&
- (ForStrongLayout || !HasMRCWeakIvars))
- return llvm::Constant::getNullValue(PtrTy);
-
- const ObjCInterfaceDecl *OI = OMD->getClassInterface();
- SmallVector<const ObjCIvarDecl*, 32> ivars;
-
- // GC layout strings include the complete object layout, possibly
- // inaccurately in the non-fragile ABI; the runtime knows how to fix this
- // up.
- //
- // ARC layout strings only include the class's ivars. In non-fragile
- // runtimes, that means starting at InstanceStart, rounded up to word
- // alignment. In fragile runtimes, there's no InstanceStart, so it means
- // starting at the offset of the first ivar, rounded up to word alignment.
- //
- // MRC weak layout strings follow the ARC style.
- CharUnits baseOffset;
- if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
- for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
- IVD; IVD = IVD->getNextIvar())
- ivars.push_back(IVD);
-
- if (isNonFragileABI()) {
- baseOffset = beginOffset; // InstanceStart
- } else if (!ivars.empty()) {
- baseOffset =
- CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivars[0]));
- } else {
- baseOffset = CharUnits::Zero();
- }
-
- baseOffset = baseOffset.alignTo(CGM.getPointerAlign());
- }
- else {
- CGM.getContext().DeepCollectObjCIvars(OI, true, ivars);
-
- baseOffset = CharUnits::Zero();
- }
-
- if (ivars.empty())
- return llvm::Constant::getNullValue(PtrTy);
-
- IvarLayoutBuilder builder(CGM, baseOffset, endOffset, ForStrongLayout);
-
- builder.visitAggregate(ivars.begin(), ivars.end(), CharUnits::Zero(),
- [&](const ObjCIvarDecl *ivar) -> CharUnits {
- return CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivar));
- });
-
- if (!builder.hasBitmapData())
- return llvm::Constant::getNullValue(PtrTy);
-
- llvm::SmallVector<unsigned char, 4> buffer;
- llvm::Constant *C = builder.buildBitmap(*this, buffer);
-
- if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
- printf("\n%s ivar layout for class '%s': ",
- ForStrongLayout ? "strong" : "weak",
- OMD->getClassInterface()->getName().str().c_str());
- builder.dump(buffer);
- }
- return C;
-}
-
-llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
- llvm::GlobalVariable *&Entry = MethodVarNames[Sel];
- // FIXME: Avoid std::string in "Sel.getAsString()"
- if (!Entry)
- Entry = CreateCStringLiteral(Sel.getAsString(), ObjCLabelType::MethodVarName);
- return getConstantGEP(VMContext, Entry, 0, 0);
-}
-
-// FIXME: Merge into a single cstring creation function.
-llvm::Constant *CGObjCCommonMac::GetMethodVarName(IdentifierInfo *ID) {
- return GetMethodVarName(CGM.getContext().Selectors.getNullarySelector(ID));
-}
-
-llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
- std::string TypeStr;
- CGM.getContext().getObjCEncodingForType(Field->getType(), TypeStr, Field);
-
- llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
- if (!Entry)
- Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType);
- return getConstantGEP(VMContext, Entry, 0, 0);
-}
-
-llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
- bool Extended) {
- std::string TypeStr =
- CGM.getContext().getObjCEncodingForMethodDecl(D, Extended);
-
- llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
- if (!Entry)
- Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType);
- return getConstantGEP(VMContext, Entry, 0, 0);
-}
-
-// FIXME: Merge into a single cstring creation function.
-llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
- llvm::GlobalVariable *&Entry = PropertyNames[Ident];
- if (!Entry)
- Entry = CreateCStringLiteral(Ident->getName(), ObjCLabelType::PropertyName);
- return getConstantGEP(VMContext, Entry, 0, 0);
-}
-
-// FIXME: Merge into a single cstring creation function.
-// FIXME: This Decl should be more precise.
-llvm::Constant *
-CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
- const Decl *Container) {
- std::string TypeStr =
- CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container);
- return GetPropertyName(&CGM.getContext().Idents.get(TypeStr));
-}
-
-void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
- const ObjCContainerDecl *CD,
- SmallVectorImpl<char> &Name) {
- llvm::raw_svector_ostream OS(Name);
- assert (CD && "Missing container decl in GetNameForMethod");
- OS << '\01' << (D->isInstanceMethod() ? '-' : '+')
- << '[' << CD->getName();
- if (const ObjCCategoryImplDecl *CID =
- dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
- OS << '(' << *CID << ')';
- OS << ' ' << D->getSelector().getAsString() << ']';
-}
-
-void CGObjCMac::FinishModule() {
- EmitModuleInfo();
-
- // Emit the dummy bodies for any protocols which were referenced but
- // never defined.
- for (auto &entry : Protocols) {
- llvm::GlobalVariable *global = entry.second;
- if (global->hasInitializer())
- continue;
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ProtocolTy);
- values.addNullPointer(ObjCTypes.ProtocolExtensionPtrTy);
- values.add(GetClassName(entry.first->getName()));
- values.addNullPointer(ObjCTypes.ProtocolListPtrTy);
- values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy);
- values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy);
- values.finishAndSetAsInitializer(global);
- CGM.addCompilerUsedGlobal(global);
- }
-
- // Add assembler directives to add lazy undefined symbol references
- // for classes which are referenced but not defined. This is
- // important for correct linker interaction.
- //
- // FIXME: It would be nice if we had an LLVM construct for this.
- if ((!LazySymbols.empty() || !DefinedSymbols.empty()) &&
- CGM.getTriple().isOSBinFormatMachO()) {
- SmallString<256> Asm;
- Asm += CGM.getModule().getModuleInlineAsm();
- if (!Asm.empty() && Asm.back() != '\n')
- Asm += '\n';
-
- llvm::raw_svector_ostream OS(Asm);
- for (const auto *Sym : DefinedSymbols)
- OS << "\t.objc_class_name_" << Sym->getName() << "=0\n"
- << "\t.globl .objc_class_name_" << Sym->getName() << "\n";
- for (const auto *Sym : LazySymbols)
- OS << "\t.lazy_reference .objc_class_name_" << Sym->getName() << "\n";
- for (const auto &Category : DefinedCategoryNames)
- OS << "\t.objc_category_name_" << Category << "=0\n"
- << "\t.globl .objc_category_name_" << Category << "\n";
-
- CGM.getModule().setModuleInlineAsm(OS.str());
- }
-}
-
-CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
- : CGObjCCommonMac(cgm), ObjCTypes(cgm), ObjCEmptyCacheVar(nullptr),
- ObjCEmptyVtableVar(nullptr) {
- ObjCABI = 2;
-}
-
-/* *** */
-
-ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
- : VMContext(cgm.getLLVMContext()), CGM(cgm), ExternalProtocolPtrTy(nullptr)
-{
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
-
- ShortTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.ShortTy));
- IntTy = CGM.IntTy;
- LongTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.LongTy));
- Int8PtrTy = CGM.Int8PtrTy;
- Int8PtrPtrTy = CGM.Int8PtrPtrTy;
-
- // arm64 targets use "int" ivar offset variables. All others,
- // including OS X x86_64 and Windows x86_64, use "long" ivar offsets.
- if (CGM.getTarget().getTriple().getArch() == llvm::Triple::aarch64)
- IvarOffsetVarTy = IntTy;
- else
- IvarOffsetVarTy = LongTy;
-
- ObjectPtrTy =
- cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCIdType()));
- PtrObjectPtrTy =
- llvm::PointerType::getUnqual(ObjectPtrTy);
- SelectorPtrTy =
- cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCSelType()));
-
- // I'm not sure I like this. The implicit coordination is a bit
- // gross. We should solve this in a reasonable fashion because this
- // is a pretty common task (match some runtime data structure with
- // an LLVM data structure).
-
- // FIXME: This is leaked.
- // FIXME: Merge with rewriter code?
-
- // struct _objc_super {
- // id self;
- // Class cls;
- // }
- RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
- Ctx.getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Ctx.Idents.get("_objc_super"));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
- nullptr, Ctx.getObjCIdType(), nullptr, nullptr,
- false, ICIS_NoInit));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
- nullptr, Ctx.getObjCClassType(), nullptr,
- nullptr, false, ICIS_NoInit));
- RD->completeDefinition();
-
- SuperCTy = Ctx.getTagDeclType(RD);
- SuperPtrCTy = Ctx.getPointerType(SuperCTy);
-
- SuperTy = cast<llvm::StructType>(Types.ConvertType(SuperCTy));
- SuperPtrTy = llvm::PointerType::getUnqual(SuperTy);
-
- // struct _prop_t {
- // char *name;
- // char *attributes;
- // }
- PropertyTy = llvm::StructType::create("struct._prop_t", Int8PtrTy, Int8PtrTy);
-
- // struct _prop_list_t {
- // uint32_t entsize; // sizeof(struct _prop_t)
- // uint32_t count_of_properties;
- // struct _prop_t prop_list[count_of_properties];
- // }
- PropertyListTy = llvm::StructType::create(
- "struct._prop_list_t", IntTy, IntTy, llvm::ArrayType::get(PropertyTy, 0));
- // struct _prop_list_t *
- PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
-
- // struct _objc_method {
- // SEL _cmd;
- // char *method_type;
- // char *_imp;
- // }
- MethodTy = llvm::StructType::create("struct._objc_method", SelectorPtrTy,
- Int8PtrTy, Int8PtrTy);
-
- // struct _objc_cache *
- CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
- CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
-}
-
-ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
- : ObjCCommonTypesHelper(cgm) {
- // struct _objc_method_description {
- // SEL name;
- // char *types;
- // }
- MethodDescriptionTy = llvm::StructType::create(
- "struct._objc_method_description", SelectorPtrTy, Int8PtrTy);
-
- // struct _objc_method_description_list {
- // int count;
- // struct _objc_method_description[1];
- // }
- MethodDescriptionListTy =
- llvm::StructType::create("struct._objc_method_description_list", IntTy,
- llvm::ArrayType::get(MethodDescriptionTy, 0));
-
- // struct _objc_method_description_list *
- MethodDescriptionListPtrTy =
- llvm::PointerType::getUnqual(MethodDescriptionListTy);
-
- // Protocol description structures
-
- // struct _objc_protocol_extension {
- // uint32_t size; // sizeof(struct _objc_protocol_extension)
- // struct _objc_method_description_list *optional_instance_methods;
- // struct _objc_method_description_list *optional_class_methods;
- // struct _objc_property_list *instance_properties;
- // const char ** extendedMethodTypes;
- // struct _objc_property_list *class_properties;
- // }
- ProtocolExtensionTy = llvm::StructType::create(
- "struct._objc_protocol_extension", IntTy, MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy, PropertyListPtrTy, Int8PtrPtrTy,
- PropertyListPtrTy);
-
- // struct _objc_protocol_extension *
- ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
-
- // Handle recursive construction of Protocol and ProtocolList types
-
- ProtocolTy =
- llvm::StructType::create(VMContext, "struct._objc_protocol");
-
- ProtocolListTy =
- llvm::StructType::create(VMContext, "struct._objc_protocol_list");
- ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy), LongTy,
- llvm::ArrayType::get(ProtocolTy, 0));
-
- // struct _objc_protocol {
- // struct _objc_protocol_extension *isa;
- // char *protocol_name;
- // struct _objc_protocol **_objc_protocol_list;
- // struct _objc_method_description_list *instance_methods;
- // struct _objc_method_description_list *class_methods;
- // }
- ProtocolTy->setBody(ProtocolExtensionPtrTy, Int8PtrTy,
- llvm::PointerType::getUnqual(ProtocolListTy),
- MethodDescriptionListPtrTy, MethodDescriptionListPtrTy);
-
- // struct _objc_protocol_list *
- ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
-
- ProtocolPtrTy = llvm::PointerType::getUnqual(ProtocolTy);
-
- // Class description structures
-
- // struct _objc_ivar {
- // char *ivar_name;
- // char *ivar_type;
- // int ivar_offset;
- // }
- IvarTy = llvm::StructType::create("struct._objc_ivar", Int8PtrTy, Int8PtrTy,
- IntTy);
-
- // struct _objc_ivar_list *
- IvarListTy =
- llvm::StructType::create(VMContext, "struct._objc_ivar_list");
- IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
-
- // struct _objc_method_list *
- MethodListTy =
- llvm::StructType::create(VMContext, "struct._objc_method_list");
- MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
-
- // struct _objc_class_extension *
- ClassExtensionTy = llvm::StructType::create(
- "struct._objc_class_extension", IntTy, Int8PtrTy, PropertyListPtrTy);
- ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
-
- ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
-
- // struct _objc_class {
- // Class isa;
- // Class super_class;
- // char *name;
- // long version;
- // long info;
- // long instance_size;
- // struct _objc_ivar_list *ivars;
- // struct _objc_method_list *methods;
- // struct _objc_cache *cache;
- // struct _objc_protocol_list *protocols;
- // char *ivar_layout;
- // struct _objc_class_ext *ext;
- // };
- ClassTy->setBody(llvm::PointerType::getUnqual(ClassTy),
- llvm::PointerType::getUnqual(ClassTy), Int8PtrTy, LongTy,
- LongTy, LongTy, IvarListPtrTy, MethodListPtrTy, CachePtrTy,
- ProtocolListPtrTy, Int8PtrTy, ClassExtensionPtrTy);
-
- ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
-
- // struct _objc_category {
- // char *category_name;
- // char *class_name;
- // struct _objc_method_list *instance_method;
- // struct _objc_method_list *class_method;
- // struct _objc_protocol_list *protocols;
- // uint32_t size; // sizeof(struct _objc_category)
- // struct _objc_property_list *instance_properties;// category's @property
- // struct _objc_property_list *class_properties;
- // }
- CategoryTy = llvm::StructType::create(
- "struct._objc_category", Int8PtrTy, Int8PtrTy, MethodListPtrTy,
- MethodListPtrTy, ProtocolListPtrTy, IntTy, PropertyListPtrTy,
- PropertyListPtrTy);
-
- // Global metadata structures
-
- // struct _objc_symtab {
- // long sel_ref_cnt;
- // SEL *refs;
- // short cls_def_cnt;
- // short cat_def_cnt;
- // char *defs[cls_def_cnt + cat_def_cnt];
- // }
- SymtabTy = llvm::StructType::create("struct._objc_symtab", LongTy,
- SelectorPtrTy, ShortTy, ShortTy,
- llvm::ArrayType::get(Int8PtrTy, 0));
- SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
-
- // struct _objc_module {
- // long version;
- // long size; // sizeof(struct _objc_module)
- // char *name;
- // struct _objc_symtab* symtab;
- // }
- ModuleTy = llvm::StructType::create("struct._objc_module", LongTy, LongTy,
- Int8PtrTy, SymtabPtrTy);
-
- // FIXME: This is the size of the setjmp buffer and should be target
- // specific. 18 is what's used on 32-bit X86.
- uint64_t SetJmpBufferSize = 18;
-
- // Exceptions
- llvm::Type *StackPtrTy = llvm::ArrayType::get(CGM.Int8PtrTy, 4);
-
- ExceptionDataTy = llvm::StructType::create(
- "struct._objc_exception_data",
- llvm::ArrayType::get(CGM.Int32Ty, SetJmpBufferSize), StackPtrTy);
-}
-
-ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
- : ObjCCommonTypesHelper(cgm) {
- // struct _method_list_t {
- // uint32_t entsize; // sizeof(struct _objc_method)
- // uint32_t method_count;
- // struct _objc_method method_list[method_count];
- // }
- MethodListnfABITy =
- llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
- llvm::ArrayType::get(MethodTy, 0));
- // struct method_list_t *
- MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
-
- // struct _protocol_t {
- // id isa; // NULL
- // const char * const protocol_name;
- // const struct _protocol_list_t * protocol_list; // super protocols
- // const struct method_list_t * const instance_methods;
- // const struct method_list_t * const class_methods;
- // const struct method_list_t *optionalInstanceMethods;
- // const struct method_list_t *optionalClassMethods;
- // const struct _prop_list_t * properties;
- // const uint32_t size; // sizeof(struct _protocol_t)
- // const uint32_t flags; // = 0
- // const char ** extendedMethodTypes;
- // const char *demangledName;
- // const struct _prop_list_t * class_properties;
- // }
-
- // Holder for struct _protocol_list_t *
- ProtocolListnfABITy =
- llvm::StructType::create(VMContext, "struct._objc_protocol_list");
-
- ProtocolnfABITy = llvm::StructType::create(
- "struct._protocol_t", ObjectPtrTy, Int8PtrTy,
- llvm::PointerType::getUnqual(ProtocolListnfABITy), MethodListnfABIPtrTy,
- MethodListnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy,
- PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy, Int8PtrTy,
- PropertyListPtrTy);
-
- // struct _protocol_t*
- ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
-
- // struct _protocol_list_t {
- // long protocol_count; // Note, this is 32/64 bit
- // struct _protocol_t *[protocol_count];
- // }
- ProtocolListnfABITy->setBody(LongTy,
- llvm::ArrayType::get(ProtocolnfABIPtrTy, 0));
-
- // struct _objc_protocol_list*
- ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
-
- // struct _ivar_t {
- // unsigned [long] int *offset; // pointer to ivar offset location
- // char *name;
- // char *type;
- // uint32_t alignment;
- // uint32_t size;
- // }
- IvarnfABITy = llvm::StructType::create(
- "struct._ivar_t", llvm::PointerType::getUnqual(IvarOffsetVarTy),
- Int8PtrTy, Int8PtrTy, IntTy, IntTy);
-
- // struct _ivar_list_t {
- // uint32 entsize; // sizeof(struct _ivar_t)
- // uint32 count;
- // struct _iver_t list[count];
- // }
- IvarListnfABITy =
- llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
- llvm::ArrayType::get(IvarnfABITy, 0));
-
- IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
-
- // struct _class_ro_t {
- // uint32_t const flags;
- // uint32_t const instanceStart;
- // uint32_t const instanceSize;
- // uint32_t const reserved; // only when building for 64bit targets
- // const uint8_t * const ivarLayout;
- // const char *const name;
- // const struct _method_list_t * const baseMethods;
- // const struct _objc_protocol_list *const baseProtocols;
- // const struct _ivar_list_t *const ivars;
- // const uint8_t * const weakIvarLayout;
- // const struct _prop_list_t * const properties;
- // }
-
- // FIXME. Add 'reserved' field in 64bit abi mode!
- ClassRonfABITy = llvm::StructType::create(
- "struct._class_ro_t", IntTy, IntTy, IntTy, Int8PtrTy, Int8PtrTy,
- MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, IvarListnfABIPtrTy,
- Int8PtrTy, PropertyListPtrTy);
-
- // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
- llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false)
- ->getPointerTo();
-
- // struct _class_t {
- // struct _class_t *isa;
- // struct _class_t * const superclass;
- // void *cache;
- // IMP *vtable;
- // struct class_ro_t *ro;
- // }
-
- ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t");
- ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
- llvm::PointerType::getUnqual(ClassnfABITy), CachePtrTy,
- llvm::PointerType::getUnqual(ImpnfABITy),
- llvm::PointerType::getUnqual(ClassRonfABITy));
-
- // LLVM for struct _class_t *
- ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
-
- // struct _category_t {
- // const char * const name;
- // struct _class_t *const cls;
- // const struct _method_list_t * const instance_methods;
- // const struct _method_list_t * const class_methods;
- // const struct _protocol_list_t * const protocols;
- // const struct _prop_list_t * const properties;
- // const struct _prop_list_t * const class_properties;
- // const uint32_t size;
- // }
- CategorynfABITy = llvm::StructType::create(
- "struct._category_t", Int8PtrTy, ClassnfABIPtrTy, MethodListnfABIPtrTy,
- MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, PropertyListPtrTy,
- PropertyListPtrTy, IntTy);
-
- // New types for nonfragile abi messaging.
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
-
- // MessageRefTy - LLVM for:
- // struct _message_ref_t {
- // IMP messenger;
- // SEL name;
- // };
-
- // First the clang type for struct _message_ref_t
- RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
- Ctx.getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Ctx.Idents.get("_message_ref_t"));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
- nullptr, Ctx.VoidPtrTy, nullptr, nullptr, false,
- ICIS_NoInit));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
- nullptr, Ctx.getObjCSelType(), nullptr, nullptr,
- false, ICIS_NoInit));
- RD->completeDefinition();
-
- MessageRefCTy = Ctx.getTagDeclType(RD);
- MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy);
- MessageRefTy = cast<llvm::StructType>(Types.ConvertType(MessageRefCTy));
-
- // MessageRefPtrTy - LLVM for struct _message_ref_t*
- MessageRefPtrTy = llvm::PointerType::getUnqual(MessageRefTy);
-
- // SuperMessageRefTy - LLVM for:
- // struct _super_message_ref_t {
- // SUPER_IMP messenger;
- // SEL name;
- // };
- SuperMessageRefTy = llvm::StructType::create("struct._super_message_ref_t",
- ImpnfABITy, SelectorPtrTy);
-
- // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
- SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
-
-
- // struct objc_typeinfo {
- // const void** vtable; // objc_ehtype_vtable + 2
- // const char* name; // c++ typeinfo string
- // Class cls;
- // };
- EHTypeTy = llvm::StructType::create("struct._objc_typeinfo",
- llvm::PointerType::getUnqual(Int8PtrTy),
- Int8PtrTy, ClassnfABIPtrTy);
- EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
-}
-
-llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
- FinishNonFragileABIModule();
-
- return nullptr;
-}
-
-void CGObjCNonFragileABIMac::AddModuleClassList(
- ArrayRef<llvm::GlobalValue *> Container, StringRef SymbolName,
- StringRef SectionName) {
- unsigned NumClasses = Container.size();
-
- if (!NumClasses)
- return;
-
- SmallVector<llvm::Constant*, 8> Symbols(NumClasses);
- for (unsigned i=0; i<NumClasses; i++)
- Symbols[i] = llvm::ConstantExpr::getBitCast(Container[i],
- ObjCTypes.Int8PtrTy);
- llvm::Constant *Init =
- llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
- Symbols.size()),
- Symbols);
-
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::PrivateLinkage,
- Init,
- SymbolName);
- GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
- GV->setSection(SectionName);
- CGM.addCompilerUsedGlobal(GV);
-}
-
-void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
- // nonfragile abi has no module definition.
-
- // Build list of all implemented class addresses in array
- // L_OBJC_LABEL_CLASS_$.
-
- for (unsigned i=0, NumClasses=ImplementedClasses.size(); i<NumClasses; i++) {
- const ObjCInterfaceDecl *ID = ImplementedClasses[i];
- assert(ID);
- if (ObjCImplementationDecl *IMP = ID->getImplementation())
- // We are implementing a weak imported interface. Give it external linkage
- if (ID->isWeakImported() && !IMP->isWeakImported()) {
- DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
- DefinedMetaClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
- }
- }
-
- AddModuleClassList(DefinedClasses, "OBJC_LABEL_CLASS_$",
- GetSectionName("__objc_classlist",
- "regular,no_dead_strip"));
-
- AddModuleClassList(DefinedNonLazyClasses, "OBJC_LABEL_NONLAZY_CLASS_$",
- GetSectionName("__objc_nlclslist",
- "regular,no_dead_strip"));
-
- // Build list of all implemented category addresses in array
- // L_OBJC_LABEL_CATEGORY_$.
- AddModuleClassList(DefinedCategories, "OBJC_LABEL_CATEGORY_$",
- GetSectionName("__objc_catlist",
- "regular,no_dead_strip"));
- AddModuleClassList(DefinedNonLazyCategories, "OBJC_LABEL_NONLAZY_CATEGORY_$",
- GetSectionName("__objc_nlcatlist",
- "regular,no_dead_strip"));
-
- EmitImageInfo();
-}
-
-/// isVTableDispatchedSelector - Returns true if SEL is not in the list of
-/// VTableDispatchMethods; false otherwise. What this means is that
-/// except for the 19 selectors in the list, we generate 32bit-style
-/// message dispatch call for all the rest.
-bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
- // At various points we've experimented with using vtable-based
- // dispatch for all methods.
- switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
- case CodeGenOptions::Legacy:
- return false;
- case CodeGenOptions::NonLegacy:
- return true;
- case CodeGenOptions::Mixed:
- break;
- }
-
- // If so, see whether this selector is in the white-list of things which must
- // use the new dispatch convention. We lazily build a dense set for this.
- if (VTableDispatchMethods.empty()) {
- VTableDispatchMethods.insert(GetNullarySelector("alloc"));
- VTableDispatchMethods.insert(GetNullarySelector("class"));
- VTableDispatchMethods.insert(GetNullarySelector("self"));
- VTableDispatchMethods.insert(GetNullarySelector("isFlipped"));
- VTableDispatchMethods.insert(GetNullarySelector("length"));
- VTableDispatchMethods.insert(GetNullarySelector("count"));
-
- // These are vtable-based if GC is disabled.
- // Optimistically use vtable dispatch for hybrid compiles.
- if (CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
- VTableDispatchMethods.insert(GetNullarySelector("retain"));
- VTableDispatchMethods.insert(GetNullarySelector("release"));
- VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
- }
-
- VTableDispatchMethods.insert(GetUnarySelector("allocWithZone"));
- VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
- VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
- VTableDispatchMethods.insert(GetUnarySelector("objectForKey"));
- VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
- VTableDispatchMethods.insert(GetUnarySelector("isEqualToString"));
- VTableDispatchMethods.insert(GetUnarySelector("isEqual"));
-
- // These are vtable-based if GC is enabled.
- // Optimistically use vtable dispatch for hybrid compiles.
- if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
- VTableDispatchMethods.insert(GetNullarySelector("hash"));
- VTableDispatchMethods.insert(GetUnarySelector("addObject"));
-
- // "countByEnumeratingWithState:objects:count"
- IdentifierInfo *KeyIdents[] = {
- &CGM.getContext().Idents.get("countByEnumeratingWithState"),
- &CGM.getContext().Idents.get("objects"),
- &CGM.getContext().Idents.get("count")
- };
- VTableDispatchMethods.insert(
- CGM.getContext().Selectors.getSelector(3, KeyIdents));
- }
- }
-
- return VTableDispatchMethods.count(Sel);
-}
-
-/// BuildClassRoTInitializer - generate meta-data for:
-/// struct _class_ro_t {
-/// uint32_t const flags;
-/// uint32_t const instanceStart;
-/// uint32_t const instanceSize;
-/// uint32_t const reserved; // only when building for 64bit targets
-/// const uint8_t * const ivarLayout;
-/// const char *const name;
-/// const struct _method_list_t * const baseMethods;
-/// const struct _protocol_list_t *const baseProtocols;
-/// const struct _ivar_list_t *const ivars;
-/// const uint8_t * const weakIvarLayout;
-/// const struct _prop_list_t * const properties;
-/// }
-///
-llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
- unsigned flags,
- unsigned InstanceStart,
- unsigned InstanceSize,
- const ObjCImplementationDecl *ID) {
- std::string ClassName = ID->getObjCRuntimeNameAsString();
-
- CharUnits beginInstance = CharUnits::fromQuantity(InstanceStart);
- CharUnits endInstance = CharUnits::fromQuantity(InstanceSize);
-
- bool hasMRCWeak = false;
- if (CGM.getLangOpts().ObjCAutoRefCount)
- flags |= NonFragileABI_Class_CompiledByARC;
- else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
- flags |= NonFragileABI_Class_HasMRCWeakIvars;
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ClassRonfABITy);
-
- values.addInt(ObjCTypes.IntTy, flags);
- values.addInt(ObjCTypes.IntTy, InstanceStart);
- values.addInt(ObjCTypes.IntTy, InstanceSize);
- values.add((flags & NonFragileABI_Class_Meta)
- ? GetIvarLayoutName(nullptr, ObjCTypes)
- : BuildStrongIvarLayout(ID, beginInstance, endInstance));
- values.add(GetClassName(ID->getObjCRuntimeNameAsString()));
-
- // const struct _method_list_t * const baseMethods;
- SmallVector<const ObjCMethodDecl*, 16> methods;
- if (flags & NonFragileABI_Class_Meta) {
- for (const auto *MD : ID->class_methods())
- methods.push_back(MD);
- } else {
- for (const auto *MD : ID->instance_methods())
- methods.push_back(MD);
-
- for (const auto *PID : ID->property_impls()) {
- if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){
- ObjCPropertyDecl *PD = PID->getPropertyDecl();
-
- if (auto MD = PD->getGetterMethodDecl())
- if (GetMethodDefinition(MD))
- methods.push_back(MD);
- if (auto MD = PD->getSetterMethodDecl())
- if (GetMethodDefinition(MD))
- methods.push_back(MD);
- }
- }
- }
-
- values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
- (flags & NonFragileABI_Class_Meta)
- ? MethodListType::ClassMethods
- : MethodListType::InstanceMethods,
- methods));
-
- const ObjCInterfaceDecl *OID = ID->getClassInterface();
- assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
- values.add(EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_"
- + OID->getObjCRuntimeNameAsString(),
- OID->all_referenced_protocol_begin(),
- OID->all_referenced_protocol_end()));
-
- if (flags & NonFragileABI_Class_Meta) {
- values.addNullPointer(ObjCTypes.IvarListnfABIPtrTy);
- values.add(GetIvarLayoutName(nullptr, ObjCTypes));
- values.add(EmitPropertyList(
- "\01l_OBJC_$_CLASS_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
- ID, ID->getClassInterface(), ObjCTypes, true));
- } else {
- values.add(EmitIvarList(ID));
- values.add(BuildWeakIvarLayout(ID, beginInstance, endInstance, hasMRCWeak));
- values.add(EmitPropertyList(
- "\01l_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
- ID, ID->getClassInterface(), ObjCTypes, false));
- }
-
- llvm::SmallString<64> roLabel;
- llvm::raw_svector_ostream(roLabel)
- << ((flags & NonFragileABI_Class_Meta) ? "\01l_OBJC_METACLASS_RO_$_"
- : "\01l_OBJC_CLASS_RO_$_")
- << ClassName;
-
- llvm::GlobalVariable *CLASS_RO_GV =
- values.finishAndCreateGlobal(roLabel, CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- if (CGM.getTriple().isOSBinFormatMachO())
- CLASS_RO_GV->setSection("__DATA, __objc_const");
- return CLASS_RO_GV;
-}
-
-/// Build the metaclass object for a class.
-///
-/// struct _class_t {
-/// struct _class_t *isa;
-/// struct _class_t * const superclass;
-/// void *cache;
-/// IMP *vtable;
-/// struct class_ro_t *ro;
-/// }
-///
-llvm::GlobalVariable *
-CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI,
- bool isMetaclass,
- llvm::Constant *IsAGV,
- llvm::Constant *SuperClassGV,
- llvm::Constant *ClassRoGV,
- bool HiddenVisibility) {
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ClassnfABITy);
- values.add(IsAGV);
- if (SuperClassGV) {
- values.add(SuperClassGV);
- } else {
- values.addNullPointer(ObjCTypes.ClassnfABIPtrTy);
- }
- values.add(ObjCEmptyCacheVar);
- values.add(ObjCEmptyVtableVar);
- values.add(ClassRoGV);
-
- llvm::GlobalVariable *GV =
- cast<llvm::GlobalVariable>(GetClassGlobal(CI, isMetaclass, ForDefinition));
- values.finishAndSetAsInitializer(GV);
-
- if (CGM.getTriple().isOSBinFormatMachO())
- GV->setSection("__DATA, __objc_data");
- GV->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy));
- if (!CGM.getTriple().isOSBinFormatCOFF())
- if (HiddenVisibility)
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- return GV;
-}
-
-bool
-CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
- return OD->getClassMethod(GetNullarySelector("load")) != nullptr;
-}
-
-void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
- uint32_t &InstanceStart,
- uint32_t &InstanceSize) {
- const ASTRecordLayout &RL =
- CGM.getContext().getASTObjCImplementationLayout(OID);
-
- // InstanceSize is really instance end.
- InstanceSize = RL.getDataSize().getQuantity();
-
- // If there are no fields, the start is the same as the end.
- if (!RL.getFieldCount())
- InstanceStart = InstanceSize;
- else
- InstanceStart = RL.getFieldOffset(0) / CGM.getContext().getCharWidth();
-}
-
-static llvm::GlobalValue::DLLStorageClassTypes getStorage(CodeGenModule &CGM,
- StringRef Name) {
- IdentifierInfo &II = CGM.getContext().Idents.get(Name);
- TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl();
- DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
-
- const VarDecl *VD = nullptr;
- for (const auto &Result : DC->lookup(&II))
- if ((VD = dyn_cast<VarDecl>(Result)))
- break;
-
- if (!VD)
- return llvm::GlobalValue::DLLImportStorageClass;
- if (VD->hasAttr<DLLExportAttr>())
- return llvm::GlobalValue::DLLExportStorageClass;
- if (VD->hasAttr<DLLImportAttr>())
- return llvm::GlobalValue::DLLImportStorageClass;
- return llvm::GlobalValue::DefaultStorageClass;
-}
-
-void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
- if (!ObjCEmptyCacheVar) {
- ObjCEmptyCacheVar =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CacheTy, false,
- llvm::GlobalValue::ExternalLinkage, nullptr,
- "_objc_empty_cache");
- if (CGM.getTriple().isOSBinFormatCOFF())
- ObjCEmptyCacheVar->setDLLStorageClass(getStorage(CGM, "_objc_empty_cache"));
-
- // Only OS X with deployment version <10.9 use the empty vtable symbol
- const llvm::Triple &Triple = CGM.getTarget().getTriple();
- if (Triple.isMacOSX() && Triple.isMacOSXVersionLT(10, 9))
- ObjCEmptyVtableVar =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ImpnfABITy, false,
- llvm::GlobalValue::ExternalLinkage, nullptr,
- "_objc_empty_vtable");
- else
- ObjCEmptyVtableVar =
- llvm::ConstantPointerNull::get(ObjCTypes.ImpnfABITy->getPointerTo());
- }
-
- // FIXME: Is this correct (that meta class size is never computed)?
- uint32_t InstanceStart =
- CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy);
- uint32_t InstanceSize = InstanceStart;
- uint32_t flags = NonFragileABI_Class_Meta;
-
- llvm::Constant *SuperClassGV, *IsAGV;
-
- const auto *CI = ID->getClassInterface();
- assert(CI && "CGObjCNonFragileABIMac::GenerateClass - class is 0");
-
- // Build the flags for the metaclass.
- bool classIsHidden = (CGM.getTriple().isOSBinFormatCOFF())
- ? !CI->hasAttr<DLLExportAttr>()
- : CI->getVisibility() == HiddenVisibility;
- if (classIsHidden)
- flags |= NonFragileABI_Class_Hidden;
-
- // FIXME: why is this flag set on the metaclass?
- // ObjC metaclasses have no fields and don't really get constructed.
- if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
- flags |= NonFragileABI_Class_HasCXXStructors;
- if (!ID->hasNonZeroConstructors())
- flags |= NonFragileABI_Class_HasCXXDestructorOnly;
- }
-
- if (!CI->getSuperClass()) {
- // class is root
- flags |= NonFragileABI_Class_Root;
-
- SuperClassGV = GetClassGlobal(CI, /*metaclass*/ false, NotForDefinition);
- IsAGV = GetClassGlobal(CI, /*metaclass*/ true, NotForDefinition);
- } else {
- // Has a root. Current class is not a root.
- const ObjCInterfaceDecl *Root = ID->getClassInterface();
- while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
- Root = Super;
-
- const auto *Super = CI->getSuperClass();
- IsAGV = GetClassGlobal(Root, /*metaclass*/ true, NotForDefinition);
- SuperClassGV = GetClassGlobal(Super, /*metaclass*/ true, NotForDefinition);
- }
-
- llvm::GlobalVariable *CLASS_RO_GV =
- BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID);
-
- llvm::GlobalVariable *MetaTClass =
- BuildClassObject(CI, /*metaclass*/ true,
- IsAGV, SuperClassGV, CLASS_RO_GV, classIsHidden);
- CGM.setGVProperties(MetaTClass, CI);
- DefinedMetaClasses.push_back(MetaTClass);
-
- // Metadata for the class
- flags = 0;
- if (classIsHidden)
- flags |= NonFragileABI_Class_Hidden;
-
- if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
- flags |= NonFragileABI_Class_HasCXXStructors;
-
- // Set a flag to enable a runtime optimization when a class has
- // fields that require destruction but which don't require
- // anything except zero-initialization during construction. This
- // is most notably true of __strong and __weak types, but you can
- // also imagine there being C++ types with non-trivial default
- // constructors that merely set all fields to null.
- if (!ID->hasNonZeroConstructors())
- flags |= NonFragileABI_Class_HasCXXDestructorOnly;
- }
-
- if (hasObjCExceptionAttribute(CGM.getContext(), CI))
- flags |= NonFragileABI_Class_Exception;
-
- if (!CI->getSuperClass()) {
- flags |= NonFragileABI_Class_Root;
- SuperClassGV = nullptr;
- } else {
- // Has a root. Current class is not a root.
- const auto *Super = CI->getSuperClass();
- SuperClassGV = GetClassGlobal(Super, /*metaclass*/ false, NotForDefinition);
- }
-
- GetClassSizeInfo(ID, InstanceStart, InstanceSize);
- CLASS_RO_GV =
- BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID);
-
- llvm::GlobalVariable *ClassMD =
- BuildClassObject(CI, /*metaclass*/ false,
- MetaTClass, SuperClassGV, CLASS_RO_GV, classIsHidden);
- CGM.setGVProperties(ClassMD, CI);
- DefinedClasses.push_back(ClassMD);
- ImplementedClasses.push_back(CI);
-
- // Determine if this class is also "non-lazy".
- if (ImplementationIsNonLazy(ID))
- DefinedNonLazyClasses.push_back(ClassMD);
-
- // Force the definition of the EHType if necessary.
- if (flags & NonFragileABI_Class_Exception)
- (void) GetInterfaceEHType(CI, ForDefinition);
- // Make sure method definition entries are all clear for next implementation.
- MethodDefinitions.clear();
-}
-
-/// GenerateProtocolRef - This routine is called to generate code for
-/// a protocol reference expression; as in:
-/// @code
-/// @protocol(Proto1);
-/// @endcode
-/// It generates a weak reference to l_OBJC_PROTOCOL_REFERENCE_$_Proto1
-/// which will hold address of the protocol meta-data.
-///
-llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD) {
-
- // This routine is called for @protocol only. So, we must build definition
- // of protocol's meta-data (not a reference to it!)
- //
- llvm::Constant *Init =
- llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD),
- ObjCTypes.getExternalProtocolPtrTy());
-
- std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_");
- ProtocolName += PD->getObjCRuntimeNameAsString();
-
- CharUnits Align = CGF.getPointerAlign();
-
- llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
- if (PTGV)
- return CGF.Builder.CreateAlignedLoad(PTGV, Align);
- PTGV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::WeakAnyLinkage, Init,
- ProtocolName);
- PTGV->setSection(GetSectionName("__objc_protorefs",
- "coalesced,no_dead_strip"));
- PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- PTGV->setAlignment(Align.getQuantity());
- if (!CGM.getTriple().isOSBinFormatMachO())
- PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName));
- CGM.addUsedGlobal(PTGV);
- return CGF.Builder.CreateAlignedLoad(PTGV, Align);
-}
-
-/// GenerateCategory - Build metadata for a category implementation.
-/// struct _category_t {
-/// const char * const name;
-/// struct _class_t *const cls;
-/// const struct _method_list_t * const instance_methods;
-/// const struct _method_list_t * const class_methods;
-/// const struct _protocol_list_t * const protocols;
-/// const struct _prop_list_t * const properties;
-/// const struct _prop_list_t * const class_properties;
-/// const uint32_t size;
-/// }
-///
-void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
- const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
- const char *Prefix = "\01l_OBJC_$_CATEGORY_";
-
- llvm::SmallString<64> ExtCatName(Prefix);
- ExtCatName += Interface->getObjCRuntimeNameAsString();
- ExtCatName += "_$_";
- ExtCatName += OCD->getNameAsString();
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.CategorynfABITy);
- values.add(GetClassName(OCD->getIdentifier()->getName()));
- // meta-class entry symbol
- values.add(GetClassGlobal(Interface, /*metaclass*/ false, NotForDefinition));
- std::string listName =
- (Interface->getObjCRuntimeNameAsString() + "_$_" + OCD->getName()).str();
-
- SmallVector<const ObjCMethodDecl *, 16> instanceMethods;
- SmallVector<const ObjCMethodDecl *, 8> classMethods;
- for (const auto *MD : OCD->methods()) {
- if (MD->isInstanceMethod()) {
- instanceMethods.push_back(MD);
- } else {
- classMethods.push_back(MD);
- }
- }
-
- values.add(emitMethodList(listName, MethodListType::CategoryInstanceMethods,
- instanceMethods));
- values.add(emitMethodList(listName, MethodListType::CategoryClassMethods,
- classMethods));
-
- const ObjCCategoryDecl *Category =
- Interface->FindCategoryDeclaration(OCD->getIdentifier());
- if (Category) {
- SmallString<256> ExtName;
- llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_"
- << OCD->getName();
- values.add(EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_"
- + Interface->getObjCRuntimeNameAsString() + "_$_"
- + Category->getName(),
- Category->protocol_begin(),
- Category->protocol_end()));
- values.add(EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(),
- OCD, Category, ObjCTypes, false));
- values.add(EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
- OCD, Category, ObjCTypes, true));
- } else {
- values.addNullPointer(ObjCTypes.ProtocolListnfABIPtrTy);
- values.addNullPointer(ObjCTypes.PropertyListPtrTy);
- values.addNullPointer(ObjCTypes.PropertyListPtrTy);
- }
-
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy);
- values.addInt(ObjCTypes.IntTy, Size);
-
- llvm::GlobalVariable *GCATV =
- values.finishAndCreateGlobal(ExtCatName.str(), CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- if (CGM.getTriple().isOSBinFormatMachO())
- GCATV->setSection("__DATA, __objc_const");
- CGM.addCompilerUsedGlobal(GCATV);
- DefinedCategories.push_back(GCATV);
-
- // Determine if this category is also "non-lazy".
- if (ImplementationIsNonLazy(OCD))
- DefinedNonLazyCategories.push_back(GCATV);
- // method definition entries must be clear for next implementation.
- MethodDefinitions.clear();
-}
-
-/// emitMethodConstant - Return a struct objc_method constant. If
-/// forProtocol is true, the implementation will be null; otherwise,
-/// the method must have a definition registered with the runtime.
-///
-/// struct _objc_method {
-/// SEL _cmd;
-/// char *method_type;
-/// char *_imp;
-/// }
-void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
- const ObjCMethodDecl *MD,
- bool forProtocol) {
- auto method = builder.beginStruct(ObjCTypes.MethodTy);
- method.addBitCast(GetMethodVarName(MD->getSelector()),
- ObjCTypes.SelectorPtrTy);
- method.add(GetMethodVarType(MD));
-
- if (forProtocol) {
- // Protocol methods have no implementation. So, this entry is always NULL.
- method.addNullPointer(ObjCTypes.Int8PtrTy);
- } else {
- llvm::Function *fn = GetMethodDefinition(MD);
- assert(fn && "no definition for method?");
- method.addBitCast(fn, ObjCTypes.Int8PtrTy);
- }
-
- method.finishAndAddTo(builder);
-}
-
-/// Build meta-data for method declarations.
-///
-/// struct _method_list_t {
-/// uint32_t entsize; // sizeof(struct _objc_method)
-/// uint32_t method_count;
-/// struct _objc_method method_list[method_count];
-/// }
-///
-llvm::Constant *
-CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind,
- ArrayRef<const ObjCMethodDecl *> methods) {
- // Return null for empty list.
- if (methods.empty())
- return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy);
-
- StringRef prefix;
- bool forProtocol;
- switch (kind) {
- case MethodListType::CategoryInstanceMethods:
- prefix = "\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_";
- forProtocol = false;
- break;
- case MethodListType::CategoryClassMethods:
- prefix = "\01l_OBJC_$_CATEGORY_CLASS_METHODS_";
- forProtocol = false;
- break;
- case MethodListType::InstanceMethods:
- prefix = "\01l_OBJC_$_INSTANCE_METHODS_";
- forProtocol = false;
- break;
- case MethodListType::ClassMethods:
- prefix = "\01l_OBJC_$_CLASS_METHODS_";
- forProtocol = false;
- break;
-
- case MethodListType::ProtocolInstanceMethods:
- prefix = "\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_";
- forProtocol = true;
- break;
- case MethodListType::ProtocolClassMethods:
- prefix = "\01l_OBJC_$_PROTOCOL_CLASS_METHODS_";
- forProtocol = true;
- break;
- case MethodListType::OptionalProtocolInstanceMethods:
- prefix = "\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_";
- forProtocol = true;
- break;
- case MethodListType::OptionalProtocolClassMethods:
- prefix = "\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_";
- forProtocol = true;
- break;
- }
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
-
- // sizeof(struct _objc_method)
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy);
- values.addInt(ObjCTypes.IntTy, Size);
- // method_count
- values.addInt(ObjCTypes.IntTy, methods.size());
- auto methodArray = values.beginArray(ObjCTypes.MethodTy);
- for (auto MD : methods) {
- emitMethodConstant(methodArray, MD, forProtocol);
- }
- methodArray.finishAndAddTo(values);
-
- auto *GV = values.finishAndCreateGlobal(prefix + name, CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- if (CGM.getTriple().isOSBinFormatMachO())
- GV->setSection("__DATA, __objc_const");
- CGM.addCompilerUsedGlobal(GV);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
-}
-
-/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
-/// the given ivar.
-llvm::GlobalVariable *
-CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar) {
- const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
- llvm::SmallString<64> Name("OBJC_IVAR_$_");
- Name += Container->getObjCRuntimeNameAsString();
- Name += ".";
- Name += Ivar->getName();
- llvm::GlobalVariable *IvarOffsetGV = CGM.getModule().getGlobalVariable(Name);
- if (!IvarOffsetGV) {
- IvarOffsetGV =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.IvarOffsetVarTy,
- false, llvm::GlobalValue::ExternalLinkage,
- nullptr, Name.str());
- if (CGM.getTriple().isOSBinFormatCOFF()) {
- bool IsPrivateOrPackage =
- Ivar->getAccessControl() == ObjCIvarDecl::Private ||
- Ivar->getAccessControl() == ObjCIvarDecl::Package;
-
- const ObjCInterfaceDecl *ContainingID = Ivar->getContainingInterface();
-
- if (ContainingID->hasAttr<DLLImportAttr>())
- IvarOffsetGV
- ->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- else if (ContainingID->hasAttr<DLLExportAttr>() && !IsPrivateOrPackage)
- IvarOffsetGV
- ->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- }
- }
- return IvarOffsetGV;
-}
-
-llvm::Constant *
-CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar,
- unsigned long int Offset) {
- llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
- IvarOffsetGV->setInitializer(
- llvm::ConstantInt::get(ObjCTypes.IvarOffsetVarTy, Offset));
- IvarOffsetGV->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy));
-
- if (!CGM.getTriple().isOSBinFormatCOFF()) {
- // FIXME: This matches gcc, but shouldn't the visibility be set on the use
- // as well (i.e., in ObjCIvarOffsetVariable).
- if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
- Ivar->getAccessControl() == ObjCIvarDecl::Package ||
- ID->getVisibility() == HiddenVisibility)
- IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- else
- IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
- }
-
- if (CGM.getTriple().isOSBinFormatMachO())
- IvarOffsetGV->setSection("__DATA, __objc_ivar");
- return IvarOffsetGV;
-}
-
-/// EmitIvarList - Emit the ivar list for the given
-/// implementation. The return value has type
-/// IvarListnfABIPtrTy.
-/// struct _ivar_t {
-/// unsigned [long] int *offset; // pointer to ivar offset location
-/// char *name;
-/// char *type;
-/// uint32_t alignment;
-/// uint32_t size;
-/// }
-/// struct _ivar_list_t {
-/// uint32 entsize; // sizeof(struct _ivar_t)
-/// uint32 count;
-/// struct _iver_t list[count];
-/// }
-///
-
-llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
- const ObjCImplementationDecl *ID) {
-
- ConstantInitBuilder builder(CGM);
- auto ivarList = builder.beginStruct();
- ivarList.addInt(ObjCTypes.IntTy,
- CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy));
- auto ivarCountSlot = ivarList.addPlaceholder();
- auto ivars = ivarList.beginArray(ObjCTypes.IvarnfABITy);
-
- const ObjCInterfaceDecl *OID = ID->getClassInterface();
- assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
-
- // FIXME. Consolidate this with similar code in GenerateClass.
-
- for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
- IVD; IVD = IVD->getNextIvar()) {
- // Ignore unnamed bit-fields.
- if (!IVD->getDeclName())
- continue;
-
- auto ivar = ivars.beginStruct(ObjCTypes.IvarnfABITy);
- ivar.add(EmitIvarOffsetVar(ID->getClassInterface(), IVD,
- ComputeIvarBaseOffset(CGM, ID, IVD)));
- ivar.add(GetMethodVarName(IVD->getIdentifier()));
- ivar.add(GetMethodVarType(IVD));
- llvm::Type *FieldTy =
- CGM.getTypes().ConvertTypeForMem(IVD->getType());
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy);
- unsigned Align = CGM.getContext().getPreferredTypeAlign(
- IVD->getType().getTypePtr()) >> 3;
- Align = llvm::Log2_32(Align);
- ivar.addInt(ObjCTypes.IntTy, Align);
- // NOTE. Size of a bitfield does not match gcc's, because of the
- // way bitfields are treated special in each. But I am told that
- // 'size' for bitfield ivars is ignored by the runtime so it does
- // not matter. If it matters, there is enough info to get the
- // bitfield right!
- ivar.addInt(ObjCTypes.IntTy, Size);
- ivar.finishAndAddTo(ivars);
- }
- // Return null for empty list.
- if (ivars.empty()) {
- ivars.abandon();
- ivarList.abandon();
- return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
- }
-
- auto ivarCount = ivars.size();
- ivars.finishAndAddTo(ivarList);
- ivarList.fillPlaceholderWithInt(ivarCountSlot, ObjCTypes.IntTy, ivarCount);
-
- const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_";
- llvm::GlobalVariable *GV =
- ivarList.finishAndCreateGlobal(Prefix + OID->getObjCRuntimeNameAsString(),
- CGM.getPointerAlign(), /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- if (CGM.getTriple().isOSBinFormatMachO())
- GV->setSection("__DATA, __objc_const");
- CGM.addCompilerUsedGlobal(GV);
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy);
-}
-
-llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
- const ObjCProtocolDecl *PD) {
- llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
-
- if (!Entry) {
- // We use the initializer as a marker of whether this is a forward
- // reference or not. At module finalization we add the empty
- // contents for protocols which were referenced but never defined.
- llvm::SmallString<64> Protocol;
- llvm::raw_svector_ostream(Protocol) << "\01l_OBJC_PROTOCOL_$_"
- << PD->getObjCRuntimeNameAsString();
-
- Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy,
- false, llvm::GlobalValue::ExternalLinkage,
- nullptr, Protocol);
- if (!CGM.getTriple().isOSBinFormatMachO())
- Entry->setComdat(CGM.getModule().getOrInsertComdat(Protocol));
- }
-
- return Entry;
-}
-
-/// GetOrEmitProtocol - Generate the protocol meta-data:
-/// @code
-/// struct _protocol_t {
-/// id isa; // NULL
-/// const char * const protocol_name;
-/// const struct _protocol_list_t * protocol_list; // super protocols
-/// const struct method_list_t * const instance_methods;
-/// const struct method_list_t * const class_methods;
-/// const struct method_list_t *optionalInstanceMethods;
-/// const struct method_list_t *optionalClassMethods;
-/// const struct _prop_list_t * properties;
-/// const uint32_t size; // sizeof(struct _protocol_t)
-/// const uint32_t flags; // = 0
-/// const char ** extendedMethodTypes;
-/// const char *demangledName;
-/// const struct _prop_list_t * class_properties;
-/// }
-/// @endcode
-///
-
-llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
- const ObjCProtocolDecl *PD) {
- llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
-
- // Early exit if a defining object has already been generated.
- if (Entry && Entry->hasInitializer())
- return Entry;
-
- // Use the protocol definition, if there is one.
- assert(PD->hasDefinition() &&
- "emitting protocol metadata without definition");
- PD = PD->getDefinition();
-
- auto methodLists = ProtocolMethodLists::get(PD);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.ProtocolnfABITy);
-
- // isa is NULL
- values.addNullPointer(ObjCTypes.ObjectPtrTy);
- values.add(GetClassName(PD->getObjCRuntimeNameAsString()));
- values.add(EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_"
- + PD->getObjCRuntimeNameAsString(),
- PD->protocol_begin(),
- PD->protocol_end()));
- values.add(methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::RequiredInstanceMethods));
- values.add(methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::RequiredClassMethods));
- values.add(methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::OptionalInstanceMethods));
- values.add(methodLists.emitMethodList(this, PD,
- ProtocolMethodLists::OptionalClassMethods));
- values.add(EmitPropertyList(
- "\01l_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
- nullptr, PD, ObjCTypes, false));
- uint32_t Size =
- CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
- values.addInt(ObjCTypes.IntTy, Size);
- values.addInt(ObjCTypes.IntTy, 0);
- values.add(EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
- + PD->getObjCRuntimeNameAsString(),
- methodLists.emitExtendedTypesArray(this),
- ObjCTypes));
-
- // const char *demangledName;
- values.addNullPointer(ObjCTypes.Int8PtrTy);
-
- values.add(EmitPropertyList(
- "\01l_OBJC_$_CLASS_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
- nullptr, PD, ObjCTypes, true));
-
- if (Entry) {
- // Already created, fix the linkage and update the initializer.
- Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
- values.finishAndSetAsInitializer(Entry);
- } else {
- llvm::SmallString<64> symbolName;
- llvm::raw_svector_ostream(symbolName)
- << "\01l_OBJC_PROTOCOL_$_" << PD->getObjCRuntimeNameAsString();
-
- Entry = values.finishAndCreateGlobal(symbolName, CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::WeakAnyLinkage);
- if (!CGM.getTriple().isOSBinFormatMachO())
- Entry->setComdat(CGM.getModule().getOrInsertComdat(symbolName));
-
- Protocols[PD->getIdentifier()] = Entry;
- }
- Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.addUsedGlobal(Entry);
-
- // Use this protocol meta-data to build protocol list table in section
- // __DATA, __objc_protolist
- llvm::SmallString<64> ProtocolRef;
- llvm::raw_svector_ostream(ProtocolRef) << "\01l_OBJC_LABEL_PROTOCOL_$_"
- << PD->getObjCRuntimeNameAsString();
-
- llvm::GlobalVariable *PTGV =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy,
- false, llvm::GlobalValue::WeakAnyLinkage, Entry,
- ProtocolRef);
- if (!CGM.getTriple().isOSBinFormatMachO())
- PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef));
- PTGV->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
- PTGV->setSection(GetSectionName("__objc_protolist",
- "coalesced,no_dead_strip"));
- PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.addUsedGlobal(PTGV);
- return Entry;
-}
-
-/// EmitProtocolList - Generate protocol list meta-data:
-/// @code
-/// struct _protocol_list_t {
-/// long protocol_count; // Note, this is 32/64 bit
-/// struct _protocol_t[protocol_count];
-/// }
-/// @endcode
-///
-llvm::Constant *
-CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
- ObjCProtocolDecl::protocol_iterator begin,
- ObjCProtocolDecl::protocol_iterator end) {
- SmallVector<llvm::Constant *, 16> ProtocolRefs;
-
- // Just return null for empty protocol lists
- if (begin == end)
- return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
-
- // FIXME: We shouldn't need to do this lookup here, should we?
- SmallString<256> TmpName;
- Name.toVector(TmpName);
- llvm::GlobalVariable *GV =
- CGM.getModule().getGlobalVariable(TmpName.str(), true);
- if (GV)
- return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy);
-
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
- auto countSlot = values.addPlaceholder();
-
- // A null-terminated array of protocols.
- auto array = values.beginArray(ObjCTypes.ProtocolnfABIPtrTy);
- for (; begin != end; ++begin)
- array.add(GetProtocolRef(*begin)); // Implemented???
- auto count = array.size();
- array.addNullPointer(ObjCTypes.ProtocolnfABIPtrTy);
-
- array.finishAndAddTo(values);
- values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count);
-
- GV = values.finishAndCreateGlobal(Name, CGM.getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage);
- if (CGM.getTriple().isOSBinFormatMachO())
- GV->setSection("__DATA, __objc_const");
- CGM.addCompilerUsedGlobal(GV);
- return llvm::ConstantExpr::getBitCast(GV,
- ObjCTypes.ProtocolListnfABIPtrTy);
-}
-
-/// EmitObjCValueForIvar - Code Gen for nonfragile ivar reference.
-/// This code gen. amounts to generating code for:
-/// @code
-/// (type *)((char *)base + _OBJC_IVAR_$_.ivar;
-/// @encode
-///
-LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
- CodeGen::CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) {
- ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
- llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
- return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
- Offset);
-}
-
-llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
- CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) {
- llvm::Value *IvarOffsetValue = ObjCIvarOffsetVariable(Interface, Ivar);
- IvarOffsetValue = CGF.Builder.CreateAlignedLoad(IvarOffsetValue,
- CGF.getSizeAlign(), "ivar");
- if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
- cast<llvm::LoadInst>(IvarOffsetValue)
- ->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext, None));
-
- // This could be 32bit int or 64bit integer depending on the architecture.
- // Cast it to 64bit integer value, if it is a 32bit integer ivar offset value
- // as this is what caller always expects.
- if (ObjCTypes.IvarOffsetVarTy == ObjCTypes.IntTy)
- IvarOffsetValue = CGF.Builder.CreateIntCast(
- IvarOffsetValue, ObjCTypes.LongTy, true, "ivar.conv");
- return IvarOffsetValue;
-}
-
-static void appendSelectorForMessageRefTable(std::string &buffer,
- Selector selector) {
- if (selector.isUnarySelector()) {
- buffer += selector.getNameForSlot(0);
- return;
- }
-
- for (unsigned i = 0, e = selector.getNumArgs(); i != e; ++i) {
- buffer += selector.getNameForSlot(i);
- buffer += '_';
- }
-}
-
-/// Emit a "vtable" message send. We emit a weak hidden-visibility
-/// struct, initially containing the selector pointer and a pointer to
-/// a "fixup" variant of the appropriate objc_msgSend. To call, we
-/// load and call the function pointer, passing the address of the
-/// struct as the second parameter. The runtime determines whether
-/// the selector is currently emitted using vtable dispatch; if so, it
-/// substitutes a stub function which simply tail-calls through the
-/// appropriate vtable slot, and if not, it substitues a stub function
-/// which tail-calls objc_msgSend. Both stubs adjust the selector
-/// argument to correctly point to the selector.
-RValue
-CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
- ReturnValueSlot returnSlot,
- QualType resultType,
- Selector selector,
- llvm::Value *arg0,
- QualType arg0Type,
- bool isSuper,
- const CallArgList &formalArgs,
- const ObjCMethodDecl *method) {
- // Compute the actual arguments.
- CallArgList args;
-
- // First argument: the receiver / super-call structure.
- if (!isSuper)
- arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy);
- args.add(RValue::get(arg0), arg0Type);
-
- // Second argument: a pointer to the message ref structure. Leave
- // the actual argument value blank for now.
- args.add(RValue::get(nullptr), ObjCTypes.MessageRefCPtrTy);
-
- args.insert(args.end(), formalArgs.begin(), formalArgs.end());
-
- MessageSendInfo MSI = getMessageSendInfo(method, resultType, args);
-
- NullReturnState nullReturn;
-
- // Find the function to call and the mangled name for the message
- // ref structure. Using a different mangled name wouldn't actually
- // be a problem; it would just be a waste.
- //
- // The runtime currently never uses vtable dispatch for anything
- // except normal, non-super message-sends.
- // FIXME: don't use this for that.
- llvm::Constant *fn = nullptr;
- std::string messageRefName("\01l_");
- if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
- if (isSuper) {
- fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
- messageRefName += "objc_msgSendSuper2_stret_fixup";
- } else {
- nullReturn.init(CGF, arg0);
- fn = ObjCTypes.getMessageSendStretFixupFn();
- messageRefName += "objc_msgSend_stret_fixup";
- }
- } else if (!isSuper && CGM.ReturnTypeUsesFPRet(resultType)) {
- fn = ObjCTypes.getMessageSendFpretFixupFn();
- messageRefName += "objc_msgSend_fpret_fixup";
- } else {
- if (isSuper) {
- fn = ObjCTypes.getMessageSendSuper2FixupFn();
- messageRefName += "objc_msgSendSuper2_fixup";
- } else {
- fn = ObjCTypes.getMessageSendFixupFn();
- messageRefName += "objc_msgSend_fixup";
- }
- }
- assert(fn && "CGObjCNonFragileABIMac::EmitMessageSend");
- messageRefName += '_';
-
- // Append the selector name, except use underscores anywhere we
- // would have used colons.
- appendSelectorForMessageRefTable(messageRefName, selector);
-
- llvm::GlobalVariable *messageRef
- = CGM.getModule().getGlobalVariable(messageRefName);
- if (!messageRef) {
- // Build the message ref structure.
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct();
- values.add(fn);
- values.add(GetMethodVarName(selector));
- messageRef = values.finishAndCreateGlobal(messageRefName,
- CharUnits::fromQuantity(16),
- /*constant*/ false,
- llvm::GlobalValue::WeakAnyLinkage);
- messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
- messageRef->setSection(GetSectionName("__objc_msgrefs", "coalesced"));
- }
-
- bool requiresnullCheck = false;
- if (CGM.getLangOpts().ObjCAutoRefCount && method)
- for (const auto *ParamDecl : method->parameters()) {
- if (ParamDecl->hasAttr<NSConsumedAttr>()) {
- if (!nullReturn.NullBB)
- nullReturn.init(CGF, arg0);
- requiresnullCheck = true;
- break;
- }
- }
-
- Address mref =
- Address(CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy),
- CGF.getPointerAlign());
-
- // Update the message ref argument.
- args[1].setRValue(RValue::get(mref.getPointer()));
-
- // Load the function to call from the message ref table.
- Address calleeAddr =
- CGF.Builder.CreateStructGEP(mref, 0, CharUnits::Zero());
- llvm::Value *calleePtr = CGF.Builder.CreateLoad(calleeAddr, "msgSend_fn");
-
- calleePtr = CGF.Builder.CreateBitCast(calleePtr, MSI.MessengerType);
- CGCallee callee(CGCalleeInfo(), calleePtr);
-
- RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
- return nullReturn.complete(CGF, returnSlot, result, resultType, formalArgs,
- requiresnullCheck ? method : nullptr);
-}
-
-/// Generate code for a message send expression in the nonfragile abi.
-CodeGen::RValue
-CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method) {
- return isVTableDispatchedSelector(Sel)
- ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
- Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method)
- : EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, Class, ObjCTypes);
-}
-
-llvm::Constant *
-CGObjCNonFragileABIMac::GetClassGlobal(const ObjCInterfaceDecl *ID,
- bool metaclass,
- ForDefinition_t isForDefinition) {
- auto prefix =
- (metaclass ? getMetaclassSymbolPrefix() : getClassSymbolPrefix());
- return GetClassGlobal((prefix + ID->getObjCRuntimeNameAsString()).str(),
- isForDefinition,
- ID->isWeakImported(),
- !isForDefinition
- && CGM.getTriple().isOSBinFormatCOFF()
- && ID->hasAttr<DLLImportAttr>());
-}
-
-llvm::Constant *
-CGObjCNonFragileABIMac::GetClassGlobal(StringRef Name,
- ForDefinition_t IsForDefinition,
- bool Weak, bool DLLImport) {
- llvm::GlobalValue::LinkageTypes L =
- Weak ? llvm::GlobalValue::ExternalWeakLinkage
- : llvm::GlobalValue::ExternalLinkage;
-
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (!GV || GV->getType() != ObjCTypes.ClassnfABITy->getPointerTo()) {
- auto *NewGV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, L,
- nullptr, Name);
-
- if (DLLImport)
- NewGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
-
- if (GV) {
- GV->replaceAllUsesWith(
- llvm::ConstantExpr::getBitCast(NewGV, GV->getType()));
- GV->eraseFromParent();
- }
- GV = NewGV;
- CGM.getModule().getGlobalList().push_back(GV);
- }
-
- assert(GV->getLinkage() == L);
- return GV;
-}
-
-llvm::Value *
-CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
- IdentifierInfo *II,
- const ObjCInterfaceDecl *ID) {
- CharUnits Align = CGF.getPointerAlign();
- llvm::GlobalVariable *&Entry = ClassReferences[II];
-
- if (!Entry) {
- llvm::Constant *ClassGV;
- if (ID) {
- ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition);
- } else {
- ClassGV = GetClassGlobal((getClassSymbolPrefix() + II->getName()).str(),
- NotForDefinition);
- }
-
- Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::PrivateLinkage,
- ClassGV, "OBJC_CLASSLIST_REFERENCES_$_");
- Entry->setAlignment(Align.getQuantity());
- Entry->setSection(GetSectionName("__objc_classrefs",
- "regular,no_dead_strip"));
- CGM.addCompilerUsedGlobal(Entry);
- }
- return CGF.Builder.CreateAlignedLoad(Entry, Align);
-}
-
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) {
- // If the class has the objc_runtime_visible attribute, we need to
- // use the Objective-C runtime to get the class.
- if (ID->hasAttr<ObjCRuntimeVisibleAttr>())
- return EmitClassRefViaRuntime(CGF, ID, ObjCTypes);
-
- return EmitClassRefFromId(CGF, ID->getIdentifier(), ID);
-}
-
-llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
- CodeGenFunction &CGF) {
- IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(CGF, II, nullptr);
-}
-
-llvm::Value *
-CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) {
- CharUnits Align = CGF.getPointerAlign();
- llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
-
- if (!Entry) {
- auto ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition);
- Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::PrivateLinkage,
- ClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(Align.getQuantity());
- Entry->setSection(GetSectionName("__objc_superrefs",
- "regular,no_dead_strip"));
- CGM.addCompilerUsedGlobal(Entry);
- }
- return CGF.Builder.CreateAlignedLoad(Entry, Align);
-}
-
-/// EmitMetaClassRef - Return a Value * of the address of _class_t
-/// meta-data
-///
-llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID,
- bool Weak) {
- CharUnits Align = CGF.getPointerAlign();
- llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
- if (!Entry) {
- auto MetaClassGV = GetClassGlobal(ID, /*metaclass*/ true, NotForDefinition);
-
- Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::PrivateLinkage,
- MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(Align.getQuantity());
-
- Entry->setSection(GetSectionName("__objc_superrefs",
- "regular,no_dead_strip"));
- CGM.addCompilerUsedGlobal(Entry);
- }
-
- return CGF.Builder.CreateAlignedLoad(Entry, Align);
-}
-
-/// GetClass - Return a reference to the class for the given interface
-/// decl.
-llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) {
- if (ID->isWeakImported()) {
- auto ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition);
- (void)ClassGV;
- assert(!isa<llvm::GlobalVariable>(ClassGV) ||
- cast<llvm::GlobalVariable>(ClassGV)->hasExternalWeakLinkage());
- }
-
- return EmitClassRef(CGF, ID);
-}
-
-/// Generates a message send where the super is the receiver. This is
-/// a message send to self with special delivery semantics indicating
-/// which class's method should be called.
-CodeGen::RValue
-CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- const ObjCInterfaceDecl *Class,
- bool isCategoryImpl,
- llvm::Value *Receiver,
- bool IsClassMessage,
- const CodeGen::CallArgList &CallArgs,
- const ObjCMethodDecl *Method) {
- // ...
- // Create and init a super structure; this is a (receiver, class)
- // pair we will pass to objc_msgSendSuper.
- Address ObjCSuper =
- CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
- "objc_super");
-
- llvm::Value *ReceiverAsObject =
- CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateStore(
- ReceiverAsObject,
- CGF.Builder.CreateStructGEP(ObjCSuper, 0, CharUnits::Zero()));
-
- // If this is a class message the metaclass is passed as the target.
- llvm::Value *Target;
- if (IsClassMessage)
- Target = EmitMetaClassRef(CGF, Class, Class->isWeakImported());
- else
- Target = EmitSuperClassRef(CGF, Class);
-
- // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
- // ObjCTypes types.
- llvm::Type *ClassTy =
- CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
- Target = CGF.Builder.CreateBitCast(Target, ClassTy);
- CGF.Builder.CreateStore(
- Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1, CGF.getPointerSize()));
-
- return (isVTableDispatchedSelector(Sel))
- ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
- ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method)
- : EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF, Sel),
- ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, Class, ObjCTypes);
-}
-
-llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
- Selector Sel) {
- Address Addr = EmitSelectorAddr(CGF, Sel);
-
- llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr);
- LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext, None));
- return LI;
-}
-
-Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF,
- Selector Sel) {
- llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
-
- CharUnits Align = CGF.getPointerAlign();
- if (!Entry) {
- llvm::Constant *Casted =
- llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
- ObjCTypes.SelectorPtrTy);
- Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy,
- false, llvm::GlobalValue::PrivateLinkage,
- Casted, "OBJC_SELECTOR_REFERENCES_");
- Entry->setExternallyInitialized(true);
- Entry->setSection(GetSectionName("__objc_selrefs",
- "literal_pointers,no_dead_strip"));
- Entry->setAlignment(Align.getQuantity());
- CGM.addCompilerUsedGlobal(Entry);
- }
-
- return Address(Entry, Align);
-}
-
-/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
-/// objc_assign_ivar (id src, id *dst, ptrdiff_t)
-///
-void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src,
- Address dst,
- llvm::Value *ivarOffset) {
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
- : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer(), ivarOffset };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
-}
-
-/// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
-/// objc_assign_strongCast (id src, id *dst)
-///
-void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
- CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst) {
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
- : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer() };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
- args, "weakassign");
-}
-
-void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
- CodeGen::CodeGenFunction &CGF,
- Address DestPtr,
- Address SrcPtr,
- llvm::Value *Size) {
- SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
- DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), Size };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
-}
-
-/// EmitObjCWeakRead - Code gen for loading value of a __weak
-/// object: objc_read_weak (id *src)
-///
-llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
- CodeGen::CodeGenFunction &CGF,
- Address AddrWeakObj) {
- llvm::Type *DestTy = AddrWeakObj.getElementType();
- AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak =
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj.getPointer(), "weakread");
- read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
- return read_weak;
-}
-
-/// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
-/// objc_assign_weak (id src, id *dst)
-///
-void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst) {
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
- : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer() };
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
- args, "weakassign");
-}
-
-/// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
-/// objc_assign_global (id src, id *dst)
-///
-void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dst,
- bool threadlocal) {
- llvm::Type * SrcTy = src->getType();
- if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
- assert(Size <= 8 && "does not support size > 8");
- src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
- : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
- src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
- }
- src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
- dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst.getPointer() };
- if (!threadlocal)
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
- args, "globalassign");
- else
- CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
- args, "threadlocalassign");
-}
-
-void
-CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S) {
- EmitAtSynchronizedStmt(CGF, S,
- cast<llvm::Function>(ObjCTypes.getSyncEnterFn()),
- cast<llvm::Function>(ObjCTypes.getSyncExitFn()));
-}
-
-llvm::Constant *
-CGObjCNonFragileABIMac::GetEHType(QualType T) {
- // There's a particular fixed type info for 'id'.
- if (T->isObjCIdType() || T->isObjCQualifiedIdType()) {
- auto *IDEHType = CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
- if (!IDEHType) {
- IDEHType =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
- llvm::GlobalValue::ExternalLinkage, nullptr,
- "OBJC_EHTYPE_id");
- if (CGM.getTriple().isOSBinFormatCOFF())
- IDEHType->setDLLStorageClass(getStorage(CGM, "OBJC_EHTYPE_id"));
- }
- return IDEHType;
- }
-
- // All other types should be Objective-C interface pointer types.
- const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
- assert(PT && "Invalid @catch type.");
-
- const ObjCInterfaceType *IT = PT->getInterfaceType();
- assert(IT && "Invalid @catch type.");
-
- return GetInterfaceEHType(IT->getDecl(), NotForDefinition);
-}
-
-void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtTryStmt &S) {
- EmitTryCatchStmt(CGF, S,
- cast<llvm::Function>(ObjCTypes.getObjCBeginCatchFn()),
- cast<llvm::Function>(ObjCTypes.getObjCEndCatchFn()),
- cast<llvm::Function>(ObjCTypes.getExceptionRethrowFn()));
-}
-
-/// EmitThrowStmt - Generate code for a throw statement.
-void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint) {
- if (const Expr *ThrowExpr = S.getThrowExpr()) {
- llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
- Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
- CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
- .setDoesNotReturn();
- } else {
- CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
- .setDoesNotReturn();
- }
-
- CGF.Builder.CreateUnreachable();
- if (ClearInsertionPoint)
- CGF.Builder.ClearInsertionPoint();
-}
-
-llvm::Constant *
-CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
- ForDefinition_t IsForDefinition) {
- llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()];
- StringRef ClassName = ID->getObjCRuntimeNameAsString();
-
- // If we don't need a definition, return the entry if found or check
- // if we use an external reference.
- if (!IsForDefinition) {
- if (Entry)
- return Entry;
-
- // If this type (or a super class) has the __objc_exception__
- // attribute, emit an external reference.
- if (hasObjCExceptionAttribute(CGM.getContext(), ID)) {
- std::string EHTypeName = ("OBJC_EHTYPE_$_" + ClassName).str();
- Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
- false, llvm::GlobalValue::ExternalLinkage,
- nullptr, EHTypeName);
- CGM.setGVProperties(Entry, ID);
- return Entry;
- }
- }
-
- // Otherwise we need to either make a new entry or fill in the initializer.
- assert((!Entry || !Entry->hasInitializer()) && "Duplicate EHType definition");
-
- std::string VTableName = "objc_ehtype_vtable";
- auto *VTableGV = CGM.getModule().getGlobalVariable(VTableName);
- if (!VTableGV) {
- VTableGV =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.Int8PtrTy, false,
- llvm::GlobalValue::ExternalLinkage, nullptr,
- VTableName);
- if (CGM.getTriple().isOSBinFormatCOFF())
- VTableGV->setDLLStorageClass(getStorage(CGM, VTableName));
- }
-
- llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
- ConstantInitBuilder builder(CGM);
- auto values = builder.beginStruct(ObjCTypes.EHTypeTy);
- values.add(
- llvm::ConstantExpr::getInBoundsGetElementPtr(VTableGV->getValueType(),
- VTableGV, VTableIdx));
- values.add(GetClassName(ClassName));
- values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition));
-
- llvm::GlobalValue::LinkageTypes L = IsForDefinition
- ? llvm::GlobalValue::ExternalLinkage
- : llvm::GlobalValue::WeakAnyLinkage;
- if (Entry) {
- values.finishAndSetAsInitializer(Entry);
- Entry->setAlignment(CGM.getPointerAlign().getQuantity());
- } else {
- Entry = values.finishAndCreateGlobal("OBJC_EHTYPE_$_" + ClassName,
- CGM.getPointerAlign(),
- /*constant*/ false,
- L);
- if (hasObjCExceptionAttribute(CGM.getContext(), ID))
- CGM.setGVProperties(Entry, ID);
- }
- assert(Entry->getLinkage() == L);
-
- if (!CGM.getTriple().isOSBinFormatCOFF())
- if (ID->getVisibility() == HiddenVisibility)
- Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
-
- if (IsForDefinition)
- if (CGM.getTriple().isOSBinFormatMachO())
- Entry->setSection("__DATA,__objc_const");
-
- return Entry;
-}
-
-/* *** */
-
-CodeGen::CGObjCRuntime *
-CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
- switch (CGM.getLangOpts().ObjCRuntime.getKind()) {
- case ObjCRuntime::FragileMacOSX:
- return new CGObjCMac(CGM);
-
- case ObjCRuntime::MacOSX:
- case ObjCRuntime::iOS:
- case ObjCRuntime::WatchOS:
- return new CGObjCNonFragileABIMac(CGM);
-
- case ObjCRuntime::GNUstep:
- case ObjCRuntime::GCC:
- case ObjCRuntime::ObjFW:
- llvm_unreachable("these runtimes are not Mac runtimes");
- }
- llvm_unreachable("bad runtime");
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp
deleted file mode 100644
index 4b6f24a03f2..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-//==- CGObjCRuntime.cpp - Interface to Shared Objective-C Runtime Features ==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This abstract class defines the interface for Objective-C runtime-specific
-// code generation. It provides some concrete helper methods for functionality
-// shared between all (or most) of the Objective-C runtimes supported by clang.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGObjCRuntime.h"
-#include "CGCleanup.h"
-#include "CGCXXABI.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/Support/SaveAndRestore.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *OID,
- const ObjCIvarDecl *Ivar) {
- return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) /
- CGM.getContext().getCharWidth();
-}
-
-uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
- const ObjCImplementationDecl *OID,
- const ObjCIvarDecl *Ivar) {
- return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID,
- Ivar) /
- CGM.getContext().getCharWidth();
-}
-
-unsigned CGObjCRuntime::ComputeBitfieldBitOffset(
- CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar) {
- return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(),
- Ivar);
-}
-
-LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *OID,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers,
- llvm::Value *Offset) {
- // Compute (type*) ( (char *) BaseValue + Offset)
- QualType InterfaceTy{OID->getTypeForDecl(), 0};
- QualType ObjectPtrTy =
- CGF.CGM.getContext().getObjCObjectPointerType(InterfaceTy);
- QualType IvarTy =
- Ivar->getUsageType(ObjectPtrTy).withCVRQualifiers(CVRQualifiers);
- llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
- llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy);
- V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
-
- if (!Ivar->isBitField()) {
- V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
- LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy);
- return LV;
- }
-
- // We need to compute an access strategy for this bit-field. We are given the
- // offset to the first byte in the bit-field, the sub-byte offset is taken
- // from the original layout. We reuse the normal bit-field access strategy by
- // treating this as an access to a struct where the bit-field is in byte 0,
- // and adjust the containing type size as appropriate.
- //
- // FIXME: Note that currently we make a very conservative estimate of the
- // alignment of the bit-field, because (a) it is not clear what guarantees the
- // runtime makes us, and (b) we don't have a way to specify that the struct is
- // at an alignment plus offset.
- //
- // Note, there is a subtle invariant here: we can only call this routine on
- // non-synthesized ivars but we may be called for synthesized ivars. However,
- // a synthesized ivar can never be a bit-field, so this is safe.
- uint64_t FieldBitOffset =
- CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar);
- uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
- uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign();
- uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
- CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits(
- llvm::alignTo(BitOffset + BitFieldSize, AlignmentBits));
- CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits);
-
- // Allocate a new CGBitFieldInfo object to describe this access.
- //
- // FIXME: This is incredibly wasteful, these should be uniqued or part of some
- // layout object. However, this is blocked on other cleanups to the
- // Objective-C code, so for now we just live with allocating a bunch of these
- // objects.
- CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
- CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
- CGF.CGM.getContext().toBits(StorageSize),
- CharUnits::fromQuantity(0)));
-
- Address Addr(V, Alignment);
- Addr = CGF.Builder.CreateElementBitCast(Addr,
- llvm::Type::getIntNTy(CGF.getLLVMContext(),
- Info->StorageSize));
- return LValue::MakeBitfield(Addr, *Info, IvarTy,
- LValueBaseInfo(AlignmentSource::Decl),
- TBAAAccessInfo());
-}
-
-namespace {
- struct CatchHandler {
- const VarDecl *Variable;
- const Stmt *Body;
- llvm::BasicBlock *Block;
- llvm::Constant *TypeInfo;
- /// Flags used to differentiate cleanups and catchalls in Windows SEH
- unsigned Flags;
- };
-
- struct CallObjCEndCatch final : EHScopeStack::Cleanup {
- CallObjCEndCatch(bool MightThrow, llvm::Value *Fn)
- : MightThrow(MightThrow), Fn(Fn) {}
- bool MightThrow;
- llvm::Value *Fn;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- if (MightThrow)
- CGF.EmitRuntimeCallOrInvoke(Fn);
- else
- CGF.EmitNounwindRuntimeCall(Fn);
- }
- };
-}
-
-
-void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
- const ObjCAtTryStmt &S,
- llvm::Constant *beginCatchFn,
- llvm::Constant *endCatchFn,
- llvm::Constant *exceptionRethrowFn) {
- // Jump destination for falling out of catch bodies.
- CodeGenFunction::JumpDest Cont;
- if (S.getNumCatchStmts())
- Cont = CGF.getJumpDestInCurrentScope("eh.cont");
-
- bool useFunclets = EHPersonality::get(CGF).usesFuncletPads();
-
- CodeGenFunction::FinallyInfo FinallyInfo;
- if (!useFunclets)
- if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
- FinallyInfo.enter(CGF, Finally->getFinallyBody(),
- beginCatchFn, endCatchFn, exceptionRethrowFn);
-
- SmallVector<CatchHandler, 8> Handlers;
-
-
- // Enter the catch, if there is one.
- if (S.getNumCatchStmts()) {
- for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) {
- const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I);
- const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
-
- Handlers.push_back(CatchHandler());
- CatchHandler &Handler = Handlers.back();
- Handler.Variable = CatchDecl;
- Handler.Body = CatchStmt->getCatchBody();
- Handler.Block = CGF.createBasicBlock("catch");
- Handler.Flags = 0;
-
- // @catch(...) always matches.
- if (!CatchDecl) {
- auto catchAll = getCatchAllTypeInfo();
- Handler.TypeInfo = catchAll.RTTI;
- Handler.Flags = catchAll.Flags;
- // Don't consider any other catches.
- break;
- }
-
- Handler.TypeInfo = GetEHType(CatchDecl->getType());
- }
-
- EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
- for (unsigned I = 0, E = Handlers.size(); I != E; ++I)
- Catch->setHandler(I, { Handlers[I].TypeInfo, Handlers[I].Flags }, Handlers[I].Block);
- }
-
- if (useFunclets)
- if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) {
- CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
- if (!CGF.CurSEHParent)
- CGF.CurSEHParent = cast<NamedDecl>(CGF.CurFuncDecl);
- // Outline the finally block.
- const Stmt *FinallyBlock = Finally->getFinallyBody();
- HelperCGF.startOutlinedSEHHelper(CGF, /*isFilter*/false, FinallyBlock);
-
- // Emit the original filter expression, convert to i32, and return.
- HelperCGF.EmitStmt(FinallyBlock);
-
- HelperCGF.FinishFunction(FinallyBlock->getEndLoc());
-
- llvm::Function *FinallyFunc = HelperCGF.CurFn;
-
-
- // Push a cleanup for __finally blocks.
- CGF.pushSEHCleanup(NormalAndEHCleanup, FinallyFunc);
- }
-
-
- // Emit the try body.
- CGF.EmitStmt(S.getTryBody());
-
- // Leave the try.
- if (S.getNumCatchStmts())
- CGF.popCatchScope();
-
- // Remember where we were.
- CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
-
- // Emit the handlers.
- for (unsigned I = 0, E = Handlers.size(); I != E; ++I) {
- CatchHandler &Handler = Handlers[I];
-
- CGF.EmitBlock(Handler.Block);
- llvm::CatchPadInst *CPI = nullptr;
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(CGF.CurrentFuncletPad);
- if (useFunclets)
- if ((CPI = dyn_cast_or_null<llvm::CatchPadInst>(Handler.Block->getFirstNonPHI()))) {
- CGF.CurrentFuncletPad = CPI;
- CPI->setOperand(2, CGF.getExceptionSlot().getPointer());
- }
- llvm::Value *RawExn = CGF.getExceptionFromSlot();
-
- // Enter the catch.
- llvm::Value *Exn = RawExn;
- if (beginCatchFn)
- Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted");
-
- CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange());
-
- if (endCatchFn) {
- // Add a cleanup to leave the catch.
- bool EndCatchMightThrow = (Handler.Variable == nullptr);
-
- CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
- EndCatchMightThrow,
- endCatchFn);
- }
-
- // Bind the catch parameter if it exists.
- if (const VarDecl *CatchParam = Handler.Variable) {
- llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
- llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType);
-
- CGF.EmitAutoVarDecl(*CatchParam);
- EmitInitOfCatchParam(CGF, CastExn, CatchParam);
- }
- if (CPI)
- CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
-
- CGF.ObjCEHValueStack.push_back(Exn);
- CGF.EmitStmt(Handler.Body);
- CGF.ObjCEHValueStack.pop_back();
-
- // Leave any cleanups associated with the catch.
- cleanups.ForceCleanup();
-
- CGF.EmitBranchThroughCleanup(Cont);
- }
-
- // Go back to the try-statement fallthrough.
- CGF.Builder.restoreIP(SavedIP);
-
- // Pop out of the finally.
- if (!useFunclets && S.getFinallyStmt())
- FinallyInfo.exit(CGF);
-
- if (Cont.isValid())
- CGF.EmitBlock(Cont.getBlock());
-}
-
-void CGObjCRuntime::EmitInitOfCatchParam(CodeGenFunction &CGF,
- llvm::Value *exn,
- const VarDecl *paramDecl) {
-
- Address paramAddr = CGF.GetAddrOfLocalVar(paramDecl);
-
- switch (paramDecl->getType().getQualifiers().getObjCLifetime()) {
- case Qualifiers::OCL_Strong:
- exn = CGF.EmitARCRetainNonBlock(exn);
- LLVM_FALLTHROUGH;
-
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- CGF.Builder.CreateStore(exn, paramAddr);
- return;
-
- case Qualifiers::OCL_Weak:
- CGF.EmitARCInitWeak(paramAddr, exn);
- return;
- }
- llvm_unreachable("invalid ownership qualifier");
-}
-
-namespace {
- struct CallSyncExit final : EHScopeStack::Cleanup {
- llvm::Value *SyncExitFn;
- llvm::Value *SyncArg;
- CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
- : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitNounwindRuntimeCall(SyncExitFn, SyncArg);
- }
- };
-}
-
-void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S,
- llvm::Function *syncEnterFn,
- llvm::Function *syncExitFn) {
- CodeGenFunction::RunCleanupsScope cleanups(CGF);
-
- // Evaluate the lock operand. This is guaranteed to dominate the
- // ARC release and lock-release cleanups.
- const Expr *lockExpr = S.getSynchExpr();
- llvm::Value *lock;
- if (CGF.getLangOpts().ObjCAutoRefCount) {
- lock = CGF.EmitARCRetainScalarExpr(lockExpr);
- lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock);
- } else {
- lock = CGF.EmitScalarExpr(lockExpr);
- }
- lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy);
-
- // Acquire the lock.
- CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow();
-
- // Register an all-paths cleanup to release the lock.
- CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock);
-
- // Emit the body of the statement.
- CGF.EmitStmt(S.getSynchBody());
-}
-
-/// Compute the pointer-to-function type to which a message send
-/// should be casted in order to correctly call the given method
-/// with the given arguments.
-///
-/// \param method - may be null
-/// \param resultType - the result type to use if there's no method
-/// \param callArgs - the actual arguments, including implicit ones
-CGObjCRuntime::MessageSendInfo
-CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
- QualType resultType,
- CallArgList &callArgs) {
- // If there's a method, use information from that.
- if (method) {
- const CGFunctionInfo &signature =
- CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty);
-
- llvm::PointerType *signatureType =
- CGM.getTypes().GetFunctionType(signature)->getPointerTo();
-
- const CGFunctionInfo &signatureForCall =
- CGM.getTypes().arrangeCall(signature, callArgs);
-
- return MessageSendInfo(signatureForCall, signatureType);
- }
-
- // There's no method; just use a default CC.
- const CGFunctionInfo &argsInfo =
- CGM.getTypes().arrangeUnprototypedObjCMessageSend(resultType, callArgs);
-
- // Derive the signature to call from that.
- llvm::PointerType *signatureType =
- CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo();
- return MessageSendInfo(argsInfo, signatureType);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h b/gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h
deleted file mode 100644
index fa16c198adb..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h
+++ /dev/null
@@ -1,316 +0,0 @@
-//===----- CGObjCRuntime.h - Interface to ObjC Runtimes ---------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for Objective-C code generation. Concrete
-// subclasses of this implement code generation for specific Objective-C
-// runtime libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H
-#define LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H
-#include "CGBuilder.h"
-#include "CGCall.h"
-#include "CGCleanup.h"
-#include "CGValue.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/IdentifierTable.h" // Selector
-
-namespace llvm {
- class Constant;
- class Function;
- class Module;
- class StructLayout;
- class StructType;
- class Type;
- class Value;
-}
-
-namespace clang {
-namespace CodeGen {
- class CodeGenFunction;
-}
-
- class FieldDecl;
- class ObjCAtTryStmt;
- class ObjCAtThrowStmt;
- class ObjCAtSynchronizedStmt;
- class ObjCContainerDecl;
- class ObjCCategoryImplDecl;
- class ObjCImplementationDecl;
- class ObjCInterfaceDecl;
- class ObjCMessageExpr;
- class ObjCMethodDecl;
- class ObjCProtocolDecl;
- class Selector;
- class ObjCIvarDecl;
- class ObjCStringLiteral;
- class BlockDeclRefExpr;
-
-namespace CodeGen {
- class CodeGenModule;
- class CGBlockInfo;
-
-// FIXME: Several methods should be pure virtual but aren't to avoid the
-// partially-implemented subclass breaking.
-
-/// Implements runtime-specific code generation functions.
-class CGObjCRuntime {
-protected:
- CodeGen::CodeGenModule &CGM;
- CGObjCRuntime(CodeGen::CodeGenModule &CGM) : CGM(CGM) {}
-
- // Utility functions for unified ivar access. These need to
- // eventually be folded into other places (the structure layout
- // code).
-
- /// Compute an offset to the given ivar, suitable for passing to
- /// EmitValueForIvarAtOffset. Note that the correct handling of
- /// bit-fields is carefully coordinated by these two, use caution!
- ///
- /// The latter overload is suitable for computing the offset of a
- /// sythesized ivar.
- uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *OID,
- const ObjCIvarDecl *Ivar);
- uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
- const ObjCImplementationDecl *OID,
- const ObjCIvarDecl *Ivar);
-
- LValue EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *OID,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers,
- llvm::Value *Offset);
- /// Emits a try / catch statement. This function is intended to be called by
- /// subclasses, and provides a generic mechanism for generating these, which
- /// should be usable by all runtimes. The caller must provide the functions
- /// to call when entering and exiting a \@catch() block, and the function
- /// used to rethrow exceptions. If the begin and end catch functions are
- /// NULL, then the function assumes that the EH personality function provides
- /// the thrown object directly.
- void EmitTryCatchStmt(CodeGenFunction &CGF,
- const ObjCAtTryStmt &S,
- llvm::Constant *beginCatchFn,
- llvm::Constant *endCatchFn,
- llvm::Constant *exceptionRethrowFn);
-
- void EmitInitOfCatchParam(CodeGenFunction &CGF, llvm::Value *exn,
- const VarDecl *paramDecl);
-
- /// Emits an \@synchronize() statement, using the \p syncEnterFn and
- /// \p syncExitFn arguments as the functions called to lock and unlock
- /// the object. This function can be called by subclasses that use
- /// zero-cost exception handling.
- void EmitAtSynchronizedStmt(CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S,
- llvm::Function *syncEnterFn,
- llvm::Function *syncExitFn);
-
-public:
- virtual ~CGObjCRuntime();
-
- /// Generate the function required to register all Objective-C components in
- /// this compilation unit with the runtime library.
- virtual llvm::Function *ModuleInitFunction() = 0;
-
- /// Get a selector for the specified name and type values.
- /// The result should have the LLVM type for ASTContext::getObjCSelType().
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) = 0;
-
- /// Get the address of a selector for the specified name and type values.
- /// This is a rarely-used language extension, but sadly it exists.
- ///
- /// The result should have the LLVM type for a pointer to
- /// ASTContext::getObjCSelType().
- virtual Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) = 0;
-
- /// Get a typed selector.
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
- const ObjCMethodDecl *Method) = 0;
-
- /// Get the type constant to catch for the given ObjC pointer type.
- /// This is used externally to implement catching ObjC types in C++.
- /// Runtimes which don't support this should add the appropriate
- /// error to Sema.
- virtual llvm::Constant *GetEHType(QualType T) = 0;
-
- virtual CatchTypeInfo getCatchAllTypeInfo() { return { nullptr, 0 }; }
-
- /// Generate a constant string object.
- virtual ConstantAddress GenerateConstantString(const StringLiteral *) = 0;
-
- /// Generate a category. A category contains a list of methods (and
- /// accompanying metadata) and a list of protocols.
- virtual void GenerateCategory(const ObjCCategoryImplDecl *OCD) = 0;
-
- /// Generate a class structure for this class.
- virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0;
-
- /// Register an class alias.
- virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) = 0;
-
- /// Generate an Objective-C message send operation.
- ///
- /// \param Method - The method being called, this may be null if synthesizing
- /// a property setter or getter.
- virtual CodeGen::RValue
- GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot ReturnSlot,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class = nullptr,
- const ObjCMethodDecl *Method = nullptr) = 0;
-
- /// Generate an Objective-C message send operation to the super
- /// class initiated in a method for Class and with the given Self
- /// object.
- ///
- /// \param Method - The method being called, this may be null if synthesizing
- /// a property setter or getter.
- virtual CodeGen::RValue
- GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot ReturnSlot,
- QualType ResultType,
- Selector Sel,
- const ObjCInterfaceDecl *Class,
- bool isCategoryImpl,
- llvm::Value *Self,
- bool IsClassMessage,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method = nullptr) = 0;
-
- /// Emit the code to return the named protocol as an object, as in a
- /// \@protocol expression.
- virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *OPD) = 0;
-
- /// Generate the named protocol. Protocols contain method metadata but no
- /// implementations.
- virtual void GenerateProtocol(const ObjCProtocolDecl *OPD) = 0;
-
- /// Generate a function preamble for a method with the specified
- /// types.
-
- // FIXME: Current this just generates the Function definition, but really this
- // should also be generating the loads of the parameters, as the runtime
- // should have full control over how parameters are passed.
- virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) = 0;
-
- /// Return the runtime function for getting properties.
- virtual llvm::Constant *GetPropertyGetFunction() = 0;
-
- /// Return the runtime function for setting properties.
- virtual llvm::Constant *GetPropertySetFunction() = 0;
-
- /// Return the runtime function for optimized setting properties.
- virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy) = 0;
-
- // API for atomic copying of qualified aggregates in getter.
- virtual llvm::Constant *GetGetStructFunction() = 0;
- // API for atomic copying of qualified aggregates in setter.
- virtual llvm::Constant *GetSetStructFunction() = 0;
- /// API for atomic copying of qualified aggregates with non-trivial copy
- /// assignment (c++) in setter.
- virtual llvm::Constant *GetCppAtomicObjectSetFunction() = 0;
- /// API for atomic copying of qualified aggregates with non-trivial copy
- /// assignment (c++) in getter.
- virtual llvm::Constant *GetCppAtomicObjectGetFunction() = 0;
-
- /// GetClass - Return a reference to the class for the given
- /// interface decl.
- virtual llvm::Value *GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *OID) = 0;
-
-
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
- llvm_unreachable("autoreleasepool unsupported in this ABI");
- }
-
- /// EnumerationMutationFunction - Return the function that's called by the
- /// compiler when a mutation is detected during foreach iteration.
- virtual llvm::Constant *EnumerationMutationFunction() = 0;
-
- virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S) = 0;
- virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtTryStmt &S) = 0;
- virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint=true) = 0;
- virtual llvm::Value *EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- Address AddrWeakObj) = 0;
- virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest) = 0;
- virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest,
- bool threadlocal=false) = 0;
- virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest,
- llvm::Value *ivarOffset) = 0;
- virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, Address dest) = 0;
-
- virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) = 0;
- virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar) = 0;
- virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- Address DestPtr,
- Address SrcPtr,
- llvm::Value *Size) = 0;
- virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
- const CodeGen::CGBlockInfo &blockInfo) = 0;
- virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
- const CodeGen::CGBlockInfo &blockInfo) = 0;
- virtual std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- return {};
- }
-
- /// Returns an i8* which points to the byref layout information.
- virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
- QualType T) = 0;
-
- struct MessageSendInfo {
- const CGFunctionInfo &CallInfo;
- llvm::PointerType *MessengerType;
-
- MessageSendInfo(const CGFunctionInfo &callInfo,
- llvm::PointerType *messengerType)
- : CallInfo(callInfo), MessengerType(messengerType) {}
- };
-
- MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method,
- QualType resultType,
- CallArgList &callArgs);
-
- // FIXME: This probably shouldn't be here, but the code to compute
- // it is here.
- unsigned ComputeBitfieldBitOffset(CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *ID,
- const ObjCIvarDecl *Ivar);
-};
-
-/// Creates an instance of an Objective-C runtime class.
-//TODO: This should include some way of selecting which runtime to target.
-CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM);
-CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM);
-}
-}
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp
deleted file mode 100644
index 7f6f595dd5d..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for OpenCL code generation. Concrete
-// subclasses of this implement code generation for specific OpenCL
-// runtime libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGOpenCLRuntime.h"
-#include "CodeGenFunction.h"
-#include "TargetInfo.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/GlobalValue.h"
-#include <assert.h>
-
-using namespace clang;
-using namespace CodeGen;
-
-CGOpenCLRuntime::~CGOpenCLRuntime() {}
-
-void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
- const VarDecl &D) {
- return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
-}
-
-llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
- assert(T->isOpenCLSpecificType() &&
- "Not an OpenCL specific type!");
-
- llvm::LLVMContext& Ctx = CGM.getLLVMContext();
- uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
- CGM.getContext().getOpenCLTypeAddrSpace(T));
- switch (cast<BuiltinType>(T)->getKind()) {
- default:
- llvm_unreachable("Unexpected opencl builtin type!");
- return nullptr;
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id: \
- return llvm::PointerType::get( \
- llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \
- AddrSpc);
-#include "clang/Basic/OpenCLImageTypes.def"
- case BuiltinType::OCLSampler:
- return getSamplerType(T);
- case BuiltinType::OCLEvent:
- return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc);
- case BuiltinType::OCLClkEvent:
- return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc);
- case BuiltinType::OCLQueue:
- return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc);
- case BuiltinType::OCLReserveID:
- return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc);
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- case BuiltinType::Id: \
- return llvm::PointerType::get( \
- llvm::StructType::create(Ctx, "opencl." #ExtType), AddrSpc);
-#include "clang/Basic/OpenCLExtensionTypes.def"
- }
-}
-
-llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
- if (T->isReadOnly())
- return getPipeType(T, "opencl.pipe_ro_t", PipeROTy);
- else
- return getPipeType(T, "opencl.pipe_wo_t", PipeWOTy);
-}
-
-llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T, StringRef Name,
- llvm::Type *&PipeTy) {
- if (!PipeTy)
- PipeTy = llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), Name),
- CGM.getContext().getTargetAddressSpace(
- CGM.getContext().getOpenCLTypeAddrSpace(T)));
- return PipeTy;
-}
-
-llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
- if (!SamplerTy)
- SamplerTy = llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.sampler_t"),
- CGM.getContext().getTargetAddressSpace(
- CGM.getContext().getOpenCLTypeAddrSpace(T)));
- return SamplerTy;
-}
-
-llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
- const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>();
- // The type of the last (implicit) argument to be passed.
- llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
- unsigned TypeSize = CGM.getContext()
- .getTypeSizeInChars(PipeTy->getElementType())
- .getQuantity();
- return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
-}
-
-llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
- const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>();
- // The type of the last (implicit) argument to be passed.
- llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
- unsigned TypeSize = CGM.getContext()
- .getTypeAlignInChars(PipeTy->getElementType())
- .getQuantity();
- return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
-}
-
-llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
- assert(CGM.getLangOpts().OpenCL);
- return llvm::IntegerType::getInt8PtrTy(
- CGM.getLLVMContext(),
- CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
-}
-
-/// Record emitted llvm invoke function and llvm block literal for the
-/// corresponding block expression.
-void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
- llvm::Function *InvokeF,
- llvm::Value *Block) {
- assert(EnqueuedBlockMap.find(E) == EnqueuedBlockMap.end() &&
- "Block expression emitted twice");
- assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function");
- assert(Block->getType()->isPointerTy() && "Invalid block literal type");
- EnqueuedBlockMap[E].InvokeFunc = InvokeF;
- EnqueuedBlockMap[E].BlockArg = Block;
- EnqueuedBlockMap[E].Kernel = nullptr;
-}
-
-CGOpenCLRuntime::EnqueuedBlockInfo
-CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
- CGF.EmitScalarExpr(E);
-
- // The block literal may be assigned to a const variable. Chasing down
- // to get the block literal.
- if (auto DR = dyn_cast<DeclRefExpr>(E)) {
- E = cast<VarDecl>(DR->getDecl())->getInit();
- }
- E = E->IgnoreImplicit();
- if (auto Cast = dyn_cast<CastExpr>(E)) {
- E = Cast->getSubExpr();
- }
- auto *Block = cast<BlockExpr>(E);
-
- assert(EnqueuedBlockMap.find(Block) != EnqueuedBlockMap.end() &&
- "Block expression not emitted");
-
- // Do not emit the block wrapper again if it has been emitted.
- if (EnqueuedBlockMap[Block].Kernel) {
- return EnqueuedBlockMap[Block];
- }
-
- auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
- CGF, EnqueuedBlockMap[Block].InvokeFunc,
- EnqueuedBlockMap[Block].BlockArg->stripPointerCasts());
-
- // The common part of the post-processing of the kernel goes here.
- F->addFnAttr(llvm::Attribute::NoUnwind);
- F->setCallingConv(
- CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
- EnqueuedBlockMap[Block].Kernel = F;
- return EnqueuedBlockMap[Block];
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h b/gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h
deleted file mode 100644
index 750721f1b80..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h
+++ /dev/null
@@ -1,100 +0,0 @@
-//===----- CGOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for OpenCL code generation. Concrete
-// subclasses of this implement code generation for specific OpenCL
-// runtime libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENCLRUNTIME_H
-#define LLVM_CLANG_LIB_CODEGEN_CGOPENCLRUNTIME_H
-
-#include "clang/AST/Expr.h"
-#include "clang/AST/Type.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/Type.h"
-#include "llvm/IR/Value.h"
-
-namespace clang {
-
-class BlockExpr;
-class Expr;
-class VarDecl;
-
-namespace CodeGen {
-
-class CodeGenFunction;
-class CodeGenModule;
-
-class CGOpenCLRuntime {
-protected:
- CodeGenModule &CGM;
- llvm::Type *PipeROTy;
- llvm::Type *PipeWOTy;
- llvm::PointerType *SamplerTy;
-
- /// Structure for enqueued block information.
- struct EnqueuedBlockInfo {
- llvm::Function *InvokeFunc; /// Block invoke function.
- llvm::Function *Kernel; /// Enqueued block kernel.
- llvm::Value *BlockArg; /// The first argument to enqueued block kernel.
- };
- /// Maps block expression to block information.
- llvm::DenseMap<const Expr *, EnqueuedBlockInfo> EnqueuedBlockMap;
-
- virtual llvm::Type *getPipeType(const PipeType *T, StringRef Name,
- llvm::Type *&PipeTy);
-
-public:
- CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM),
- PipeROTy(nullptr), PipeWOTy(nullptr), SamplerTy(nullptr) {}
- virtual ~CGOpenCLRuntime();
-
- /// Emit the IR required for a work-group-local variable declaration, and add
- /// an entry to CGF's LocalDeclMap for D. The base class does this using
- /// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D.
- virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
- const VarDecl &D);
-
- virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
-
- virtual llvm::Type *getPipeType(const PipeType *T);
-
- llvm::PointerType *getSamplerType(const Type *T);
-
- // Returns a value which indicates the size in bytes of the pipe
- // element.
- virtual llvm::Value *getPipeElemSize(const Expr *PipeArg);
-
- // Returns a value which indicates the alignment in bytes of the pipe
- // element.
- virtual llvm::Value *getPipeElemAlign(const Expr *PipeArg);
-
- /// \return __generic void* type.
- llvm::PointerType *getGenericVoidPointerType();
-
- /// \return enqueued block information for enqueued block.
- EnqueuedBlockInfo emitOpenCLEnqueuedBlock(CodeGenFunction &CGF,
- const Expr *E);
-
- /// Record invoke function and block literal emitted during normal
- /// codegen for a block expression. The information is used by
- /// emitOpenCLEnqueuedBlock to emit wrapper kernel.
- ///
- /// \param InvokeF invoke function emitted for the block expression.
- /// \param Block block literal emitted for the block expression.
- void recordBlockInfo(const BlockExpr *E, llvm::Function *InvokeF,
- llvm::Value *Block);
-};
-
-}
-}
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp
deleted file mode 100644
index 20eb0b29f42..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ /dev/null
@@ -1,9860 +0,0 @@
-//===----- CGOpenMPRuntime.cpp - Interface to OpenMP Runtimes -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides a class for OpenMP runtime code generation.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-#include "CGOpenMPRuntime.h"
-#include "CGRecordLayout.h"
-#include "CodeGenFunction.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/StmtOpenMP.h"
-#include "clang/Basic/BitmaskEnum.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/Value.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-/// Base class for handling code generation inside OpenMP regions.
-class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
-public:
- /// Kinds of OpenMP regions used in codegen.
- enum CGOpenMPRegionKind {
- /// Region with outlined function for standalone 'parallel'
- /// directive.
- ParallelOutlinedRegion,
- /// Region with outlined function for standalone 'task' directive.
- TaskOutlinedRegion,
- /// Region for constructs that do not require function outlining,
- /// like 'for', 'sections', 'atomic' etc. directives.
- InlinedRegion,
- /// Region with outlined function for standalone 'target' directive.
- TargetRegion,
- };
-
- CGOpenMPRegionInfo(const CapturedStmt &CS,
- const CGOpenMPRegionKind RegionKind,
- const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
- bool HasCancel)
- : CGCapturedStmtInfo(CS, CR_OpenMP), RegionKind(RegionKind),
- CodeGen(CodeGen), Kind(Kind), HasCancel(HasCancel) {}
-
- CGOpenMPRegionInfo(const CGOpenMPRegionKind RegionKind,
- const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
- bool HasCancel)
- : CGCapturedStmtInfo(CR_OpenMP), RegionKind(RegionKind), CodeGen(CodeGen),
- Kind(Kind), HasCancel(HasCancel) {}
-
- /// Get a variable or parameter for storing global thread id
- /// inside OpenMP construct.
- virtual const VarDecl *getThreadIDVariable() const = 0;
-
- /// Emit the captured statement body.
- void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
-
- /// Get an LValue for the current ThreadID variable.
- /// \return LValue for thread id variable. This LValue always has type int32*.
- virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
-
- virtual void emitUntiedSwitch(CodeGenFunction & /*CGF*/) {}
-
- CGOpenMPRegionKind getRegionKind() const { return RegionKind; }
-
- OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
-
- bool hasCancel() const { return HasCancel; }
-
- static bool classof(const CGCapturedStmtInfo *Info) {
- return Info->getKind() == CR_OpenMP;
- }
-
- ~CGOpenMPRegionInfo() override = default;
-
-protected:
- CGOpenMPRegionKind RegionKind;
- RegionCodeGenTy CodeGen;
- OpenMPDirectiveKind Kind;
- bool HasCancel;
-};
-
-/// API for captured statement code generation in OpenMP constructs.
-class CGOpenMPOutlinedRegionInfo final : public CGOpenMPRegionInfo {
-public:
- CGOpenMPOutlinedRegionInfo(const CapturedStmt &CS, const VarDecl *ThreadIDVar,
- const RegionCodeGenTy &CodeGen,
- OpenMPDirectiveKind Kind, bool HasCancel,
- StringRef HelperName)
- : CGOpenMPRegionInfo(CS, ParallelOutlinedRegion, CodeGen, Kind,
- HasCancel),
- ThreadIDVar(ThreadIDVar), HelperName(HelperName) {
- assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
- }
-
- /// Get a variable or parameter for storing global thread id
- /// inside OpenMP construct.
- const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
-
- /// Get the name of the capture helper.
- StringRef getHelperName() const override { return HelperName; }
-
- static bool classof(const CGCapturedStmtInfo *Info) {
- return CGOpenMPRegionInfo::classof(Info) &&
- cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
- ParallelOutlinedRegion;
- }
-
-private:
- /// A variable or parameter storing global thread id for OpenMP
- /// constructs.
- const VarDecl *ThreadIDVar;
- StringRef HelperName;
-};
-
-/// API for captured statement code generation in OpenMP constructs.
-class CGOpenMPTaskOutlinedRegionInfo final : public CGOpenMPRegionInfo {
-public:
- class UntiedTaskActionTy final : public PrePostActionTy {
- bool Untied;
- const VarDecl *PartIDVar;
- const RegionCodeGenTy UntiedCodeGen;
- llvm::SwitchInst *UntiedSwitch = nullptr;
-
- public:
- UntiedTaskActionTy(bool Tied, const VarDecl *PartIDVar,
- const RegionCodeGenTy &UntiedCodeGen)
- : Untied(!Tied), PartIDVar(PartIDVar), UntiedCodeGen(UntiedCodeGen) {}
- void Enter(CodeGenFunction &CGF) override {
- if (Untied) {
- // Emit task switching point.
- LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(PartIDVar),
- PartIDVar->getType()->castAs<PointerType>());
- llvm::Value *Res =
- CGF.EmitLoadOfScalar(PartIdLVal, PartIDVar->getLocation());
- llvm::BasicBlock *DoneBB = CGF.createBasicBlock(".untied.done.");
- UntiedSwitch = CGF.Builder.CreateSwitch(Res, DoneBB);
- CGF.EmitBlock(DoneBB);
- CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
- CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
- UntiedSwitch->addCase(CGF.Builder.getInt32(0),
- CGF.Builder.GetInsertBlock());
- emitUntiedSwitch(CGF);
- }
- }
- void emitUntiedSwitch(CodeGenFunction &CGF) const {
- if (Untied) {
- LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(PartIDVar),
- PartIDVar->getType()->castAs<PointerType>());
- CGF.EmitStoreOfScalar(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
- PartIdLVal);
- UntiedCodeGen(CGF);
- CodeGenFunction::JumpDest CurPoint =
- CGF.getJumpDestInCurrentScope(".untied.next.");
- CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
- CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
- UntiedSwitch->addCase(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
- CGF.Builder.GetInsertBlock());
- CGF.EmitBranchThroughCleanup(CurPoint);
- CGF.EmitBlock(CurPoint.getBlock());
- }
- }
- unsigned getNumberOfParts() const { return UntiedSwitch->getNumCases(); }
- };
- CGOpenMPTaskOutlinedRegionInfo(const CapturedStmt &CS,
- const VarDecl *ThreadIDVar,
- const RegionCodeGenTy &CodeGen,
- OpenMPDirectiveKind Kind, bool HasCancel,
- const UntiedTaskActionTy &Action)
- : CGOpenMPRegionInfo(CS, TaskOutlinedRegion, CodeGen, Kind, HasCancel),
- ThreadIDVar(ThreadIDVar), Action(Action) {
- assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
- }
-
- /// Get a variable or parameter for storing global thread id
- /// inside OpenMP construct.
- const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
-
- /// Get an LValue for the current ThreadID variable.
- LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override;
-
- /// Get the name of the capture helper.
- StringRef getHelperName() const override { return ".omp_outlined."; }
-
- void emitUntiedSwitch(CodeGenFunction &CGF) override {
- Action.emitUntiedSwitch(CGF);
- }
-
- static bool classof(const CGCapturedStmtInfo *Info) {
- return CGOpenMPRegionInfo::classof(Info) &&
- cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
- TaskOutlinedRegion;
- }
-
-private:
- /// A variable or parameter storing global thread id for OpenMP
- /// constructs.
- const VarDecl *ThreadIDVar;
- /// Action for emitting code for untied tasks.
- const UntiedTaskActionTy &Action;
-};
-
-/// API for inlined captured statement code generation in OpenMP
-/// constructs.
-class CGOpenMPInlinedRegionInfo : public CGOpenMPRegionInfo {
-public:
- CGOpenMPInlinedRegionInfo(CodeGenFunction::CGCapturedStmtInfo *OldCSI,
- const RegionCodeGenTy &CodeGen,
- OpenMPDirectiveKind Kind, bool HasCancel)
- : CGOpenMPRegionInfo(InlinedRegion, CodeGen, Kind, HasCancel),
- OldCSI(OldCSI),
- OuterRegionInfo(dyn_cast_or_null<CGOpenMPRegionInfo>(OldCSI)) {}
-
- // Retrieve the value of the context parameter.
- llvm::Value *getContextValue() const override {
- if (OuterRegionInfo)
- return OuterRegionInfo->getContextValue();
- llvm_unreachable("No context value for inlined OpenMP region");
- }
-
- void setContextValue(llvm::Value *V) override {
- if (OuterRegionInfo) {
- OuterRegionInfo->setContextValue(V);
- return;
- }
- llvm_unreachable("No context value for inlined OpenMP region");
- }
-
- /// Lookup the captured field decl for a variable.
- const FieldDecl *lookup(const VarDecl *VD) const override {
- if (OuterRegionInfo)
- return OuterRegionInfo->lookup(VD);
- // If there is no outer outlined region,no need to lookup in a list of
- // captured variables, we can use the original one.
- return nullptr;
- }
-
- FieldDecl *getThisFieldDecl() const override {
- if (OuterRegionInfo)
- return OuterRegionInfo->getThisFieldDecl();
- return nullptr;
- }
-
- /// Get a variable or parameter for storing global thread id
- /// inside OpenMP construct.
- const VarDecl *getThreadIDVariable() const override {
- if (OuterRegionInfo)
- return OuterRegionInfo->getThreadIDVariable();
- return nullptr;
- }
-
- /// Get an LValue for the current ThreadID variable.
- LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override {
- if (OuterRegionInfo)
- return OuterRegionInfo->getThreadIDVariableLValue(CGF);
- llvm_unreachable("No LValue for inlined OpenMP construct");
- }
-
- /// Get the name of the capture helper.
- StringRef getHelperName() const override {
- if (auto *OuterRegionInfo = getOldCSI())
- return OuterRegionInfo->getHelperName();
- llvm_unreachable("No helper name for inlined OpenMP construct");
- }
-
- void emitUntiedSwitch(CodeGenFunction &CGF) override {
- if (OuterRegionInfo)
- OuterRegionInfo->emitUntiedSwitch(CGF);
- }
-
- CodeGenFunction::CGCapturedStmtInfo *getOldCSI() const { return OldCSI; }
-
- static bool classof(const CGCapturedStmtInfo *Info) {
- return CGOpenMPRegionInfo::classof(Info) &&
- cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == InlinedRegion;
- }
-
- ~CGOpenMPInlinedRegionInfo() override = default;
-
-private:
- /// CodeGen info about outer OpenMP region.
- CodeGenFunction::CGCapturedStmtInfo *OldCSI;
- CGOpenMPRegionInfo *OuterRegionInfo;
-};
-
-/// API for captured statement code generation in OpenMP target
-/// constructs. For this captures, implicit parameters are used instead of the
-/// captured fields. The name of the target region has to be unique in a given
-/// application so it is provided by the client, because only the client has
-/// the information to generate that.
-class CGOpenMPTargetRegionInfo final : public CGOpenMPRegionInfo {
-public:
- CGOpenMPTargetRegionInfo(const CapturedStmt &CS,
- const RegionCodeGenTy &CodeGen, StringRef HelperName)
- : CGOpenMPRegionInfo(CS, TargetRegion, CodeGen, OMPD_target,
- /*HasCancel=*/false),
- HelperName(HelperName) {}
-
- /// This is unused for target regions because each starts executing
- /// with a single thread.
- const VarDecl *getThreadIDVariable() const override { return nullptr; }
-
- /// Get the name of the capture helper.
- StringRef getHelperName() const override { return HelperName; }
-
- static bool classof(const CGCapturedStmtInfo *Info) {
- return CGOpenMPRegionInfo::classof(Info) &&
- cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == TargetRegion;
- }
-
-private:
- StringRef HelperName;
-};
-
-static void EmptyCodeGen(CodeGenFunction &, PrePostActionTy &) {
- llvm_unreachable("No codegen for expressions");
-}
-/// API for generation of expressions captured in a innermost OpenMP
-/// region.
-class CGOpenMPInnerExprInfo final : public CGOpenMPInlinedRegionInfo {
-public:
- CGOpenMPInnerExprInfo(CodeGenFunction &CGF, const CapturedStmt &CS)
- : CGOpenMPInlinedRegionInfo(CGF.CapturedStmtInfo, EmptyCodeGen,
- OMPD_unknown,
- /*HasCancel=*/false),
- PrivScope(CGF) {
- // Make sure the globals captured in the provided statement are local by
- // using the privatization logic. We assume the same variable is not
- // captured more than once.
- for (const auto &C : CS.captures()) {
- if (!C.capturesVariable() && !C.capturesVariableByCopy())
- continue;
-
- const VarDecl *VD = C.getCapturedVar();
- if (VD->isLocalVarDeclOrParm())
- continue;
-
- DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(VD),
- /*RefersToEnclosingVariableOrCapture=*/false,
- VD->getType().getNonReferenceType(), VK_LValue,
- C.getLocation());
- PrivScope.addPrivate(
- VD, [&CGF, &DRE]() { return CGF.EmitLValue(&DRE).getAddress(); });
- }
- (void)PrivScope.Privatize();
- }
-
- /// Lookup the captured field decl for a variable.
- const FieldDecl *lookup(const VarDecl *VD) const override {
- if (const FieldDecl *FD = CGOpenMPInlinedRegionInfo::lookup(VD))
- return FD;
- return nullptr;
- }
-
- /// Emit the captured statement body.
- void EmitBody(CodeGenFunction &CGF, const Stmt *S) override {
- llvm_unreachable("No body for expressions");
- }
-
- /// Get a variable or parameter for storing global thread id
- /// inside OpenMP construct.
- const VarDecl *getThreadIDVariable() const override {
- llvm_unreachable("No thread id for expressions");
- }
-
- /// Get the name of the capture helper.
- StringRef getHelperName() const override {
- llvm_unreachable("No helper name for expressions");
- }
-
- static bool classof(const CGCapturedStmtInfo *Info) { return false; }
-
-private:
- /// Private scope to capture global variables.
- CodeGenFunction::OMPPrivateScope PrivScope;
-};
-
-/// RAII for emitting code of OpenMP constructs.
-class InlinedOpenMPRegionRAII {
- CodeGenFunction &CGF;
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
- FieldDecl *LambdaThisCaptureField = nullptr;
- const CodeGen::CGBlockInfo *BlockInfo = nullptr;
-
-public:
- /// Constructs region for combined constructs.
- /// \param CodeGen Code generation sequence for combined directives. Includes
- /// a list of functions used for code generation of implicitly inlined
- /// regions.
- InlinedOpenMPRegionRAII(CodeGenFunction &CGF, const RegionCodeGenTy &CodeGen,
- OpenMPDirectiveKind Kind, bool HasCancel)
- : CGF(CGF) {
- // Start emission for the construct.
- CGF.CapturedStmtInfo = new CGOpenMPInlinedRegionInfo(
- CGF.CapturedStmtInfo, CodeGen, Kind, HasCancel);
- std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
- LambdaThisCaptureField = CGF.LambdaThisCaptureField;
- CGF.LambdaThisCaptureField = nullptr;
- BlockInfo = CGF.BlockInfo;
- CGF.BlockInfo = nullptr;
- }
-
- ~InlinedOpenMPRegionRAII() {
- // Restore original CapturedStmtInfo only if we're done with code emission.
- auto *OldCSI =
- cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
- delete CGF.CapturedStmtInfo;
- CGF.CapturedStmtInfo = OldCSI;
- std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
- CGF.LambdaThisCaptureField = LambdaThisCaptureField;
- CGF.BlockInfo = BlockInfo;
- }
-};
-
-/// Values for bit flags used in the ident_t to describe the fields.
-/// All enumeric elements are named and described in accordance with the code
-/// from http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h
-enum OpenMPLocationFlags : unsigned {
- /// Use trampoline for internal microtask.
- OMP_IDENT_IMD = 0x01,
- /// Use c-style ident structure.
- OMP_IDENT_KMPC = 0x02,
- /// Atomic reduction option for kmpc_reduce.
- OMP_ATOMIC_REDUCE = 0x10,
- /// Explicit 'barrier' directive.
- OMP_IDENT_BARRIER_EXPL = 0x20,
- /// Implicit barrier in code.
- OMP_IDENT_BARRIER_IMPL = 0x40,
- /// Implicit barrier in 'for' directive.
- OMP_IDENT_BARRIER_IMPL_FOR = 0x40,
- /// Implicit barrier in 'sections' directive.
- OMP_IDENT_BARRIER_IMPL_SECTIONS = 0xC0,
- /// Implicit barrier in 'single' directive.
- OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140,
- /// Call of __kmp_for_static_init for static loop.
- OMP_IDENT_WORK_LOOP = 0x200,
- /// Call of __kmp_for_static_init for sections.
- OMP_IDENT_WORK_SECTIONS = 0x400,
- /// Call of __kmp_for_static_init for distribute.
- OMP_IDENT_WORK_DISTRIBUTE = 0x800,
- LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_IDENT_WORK_DISTRIBUTE)
-};
-
-/// Describes ident structure that describes a source location.
-/// All descriptions are taken from
-/// http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h
-/// Original structure:
-/// typedef struct ident {
-/// kmp_int32 reserved_1; /**< might be used in Fortran;
-/// see above */
-/// kmp_int32 flags; /**< also f.flags; KMP_IDENT_xxx flags;
-/// KMP_IDENT_KMPC identifies this union
-/// member */
-/// kmp_int32 reserved_2; /**< not really used in Fortran any more;
-/// see above */
-///#if USE_ITT_BUILD
-/// /* but currently used for storing
-/// region-specific ITT */
-/// /* contextual information. */
-///#endif /* USE_ITT_BUILD */
-/// kmp_int32 reserved_3; /**< source[4] in Fortran, do not use for
-/// C++ */
-/// char const *psource; /**< String describing the source location.
-/// The string is composed of semi-colon separated
-// fields which describe the source file,
-/// the function and a pair of line numbers that
-/// delimit the construct.
-/// */
-/// } ident_t;
-enum IdentFieldIndex {
- /// might be used in Fortran
- IdentField_Reserved_1,
- /// OMP_IDENT_xxx flags; OMP_IDENT_KMPC identifies this union member.
- IdentField_Flags,
- /// Not really used in Fortran any more
- IdentField_Reserved_2,
- /// Source[4] in Fortran, do not use for C++
- IdentField_Reserved_3,
- /// String describing the source location. The string is composed of
- /// semi-colon separated fields which describe the source file, the function
- /// and a pair of line numbers that delimit the construct.
- IdentField_PSource
-};
-
-/// Schedule types for 'omp for' loops (these enumerators are taken from
-/// the enum sched_type in kmp.h).
-enum OpenMPSchedType {
- /// Lower bound for default (unordered) versions.
- OMP_sch_lower = 32,
- OMP_sch_static_chunked = 33,
- OMP_sch_static = 34,
- OMP_sch_dynamic_chunked = 35,
- OMP_sch_guided_chunked = 36,
- OMP_sch_runtime = 37,
- OMP_sch_auto = 38,
- /// static with chunk adjustment (e.g., simd)
- OMP_sch_static_balanced_chunked = 45,
- /// Lower bound for 'ordered' versions.
- OMP_ord_lower = 64,
- OMP_ord_static_chunked = 65,
- OMP_ord_static = 66,
- OMP_ord_dynamic_chunked = 67,
- OMP_ord_guided_chunked = 68,
- OMP_ord_runtime = 69,
- OMP_ord_auto = 70,
- OMP_sch_default = OMP_sch_static,
- /// dist_schedule types
- OMP_dist_sch_static_chunked = 91,
- OMP_dist_sch_static = 92,
- /// Support for OpenMP 4.5 monotonic and nonmonotonic schedule modifiers.
- /// Set if the monotonic schedule modifier was present.
- OMP_sch_modifier_monotonic = (1 << 29),
- /// Set if the nonmonotonic schedule modifier was present.
- OMP_sch_modifier_nonmonotonic = (1 << 30),
-};
-
-enum OpenMPRTLFunction {
- /// Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc,
- /// kmpc_micro microtask, ...);
- OMPRTL__kmpc_fork_call,
- /// Call to void *__kmpc_threadprivate_cached(ident_t *loc,
- /// kmp_int32 global_tid, void *data, size_t size, void ***cache);
- OMPRTL__kmpc_threadprivate_cached,
- /// Call to void __kmpc_threadprivate_register( ident_t *,
- /// void *data, kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor);
- OMPRTL__kmpc_threadprivate_register,
- // Call to __kmpc_int32 kmpc_global_thread_num(ident_t *loc);
- OMPRTL__kmpc_global_thread_num,
- // Call to void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *crit);
- OMPRTL__kmpc_critical,
- // Call to void __kmpc_critical_with_hint(ident_t *loc, kmp_int32
- // global_tid, kmp_critical_name *crit, uintptr_t hint);
- OMPRTL__kmpc_critical_with_hint,
- // Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *crit);
- OMPRTL__kmpc_end_critical,
- // Call to kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32
- // global_tid);
- OMPRTL__kmpc_cancel_barrier,
- // Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
- OMPRTL__kmpc_barrier,
- // Call to void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid);
- OMPRTL__kmpc_for_static_fini,
- // Call to void __kmpc_serialized_parallel(ident_t *loc, kmp_int32
- // global_tid);
- OMPRTL__kmpc_serialized_parallel,
- // Call to void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32
- // global_tid);
- OMPRTL__kmpc_end_serialized_parallel,
- // Call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 num_threads);
- OMPRTL__kmpc_push_num_threads,
- // Call to void __kmpc_flush(ident_t *loc);
- OMPRTL__kmpc_flush,
- // Call to kmp_int32 __kmpc_master(ident_t *, kmp_int32 global_tid);
- OMPRTL__kmpc_master,
- // Call to void __kmpc_end_master(ident_t *, kmp_int32 global_tid);
- OMPRTL__kmpc_end_master,
- // Call to kmp_int32 __kmpc_omp_taskyield(ident_t *, kmp_int32 global_tid,
- // int end_part);
- OMPRTL__kmpc_omp_taskyield,
- // Call to kmp_int32 __kmpc_single(ident_t *, kmp_int32 global_tid);
- OMPRTL__kmpc_single,
- // Call to void __kmpc_end_single(ident_t *, kmp_int32 global_tid);
- OMPRTL__kmpc_end_single,
- // Call to kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
- // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- // kmp_routine_entry_t *task_entry);
- OMPRTL__kmpc_omp_task_alloc,
- // Call to kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t *
- // new_task);
- OMPRTL__kmpc_omp_task,
- // Call to void __kmpc_copyprivate(ident_t *loc, kmp_int32 global_tid,
- // size_t cpy_size, void *cpy_data, void(*cpy_func)(void *, void *),
- // kmp_int32 didit);
- OMPRTL__kmpc_copyprivate,
- // Call to kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void
- // (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck);
- OMPRTL__kmpc_reduce,
- // Call to kmp_int32 __kmpc_reduce_nowait(ident_t *loc, kmp_int32
- // global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data,
- // void (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name
- // *lck);
- OMPRTL__kmpc_reduce_nowait,
- // Call to void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *lck);
- OMPRTL__kmpc_end_reduce,
- // Call to void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *lck);
- OMPRTL__kmpc_end_reduce_nowait,
- // Call to void __kmpc_omp_task_begin_if0(ident_t *, kmp_int32 gtid,
- // kmp_task_t * new_task);
- OMPRTL__kmpc_omp_task_begin_if0,
- // Call to void __kmpc_omp_task_complete_if0(ident_t *, kmp_int32 gtid,
- // kmp_task_t * new_task);
- OMPRTL__kmpc_omp_task_complete_if0,
- // Call to void __kmpc_ordered(ident_t *loc, kmp_int32 global_tid);
- OMPRTL__kmpc_ordered,
- // Call to void __kmpc_end_ordered(ident_t *loc, kmp_int32 global_tid);
- OMPRTL__kmpc_end_ordered,
- // Call to kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32
- // global_tid);
- OMPRTL__kmpc_omp_taskwait,
- // Call to void __kmpc_taskgroup(ident_t *loc, kmp_int32 global_tid);
- OMPRTL__kmpc_taskgroup,
- // Call to void __kmpc_end_taskgroup(ident_t *loc, kmp_int32 global_tid);
- OMPRTL__kmpc_end_taskgroup,
- // Call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 global_tid,
- // int proc_bind);
- OMPRTL__kmpc_push_proc_bind,
- // Call to kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32
- // gtid, kmp_task_t * new_task, kmp_int32 ndeps, kmp_depend_info_t
- // *dep_list, kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list);
- OMPRTL__kmpc_omp_task_with_deps,
- // Call to void __kmpc_omp_wait_deps(ident_t *loc_ref, kmp_int32
- // gtid, kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
- // ndeps_noalias, kmp_depend_info_t *noalias_dep_list);
- OMPRTL__kmpc_omp_wait_deps,
- // Call to kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
- // global_tid, kmp_int32 cncl_kind);
- OMPRTL__kmpc_cancellationpoint,
- // Call to kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 cncl_kind);
- OMPRTL__kmpc_cancel,
- // Call to void __kmpc_push_num_teams(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 num_teams, kmp_int32 thread_limit);
- OMPRTL__kmpc_push_num_teams,
- // Call to void __kmpc_fork_teams(ident_t *loc, kmp_int32 argc, kmpc_micro
- // microtask, ...);
- OMPRTL__kmpc_fork_teams,
- // Call to void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int
- // if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int
- // sched, kmp_uint64 grainsize, void *task_dup);
- OMPRTL__kmpc_taskloop,
- // Call to void __kmpc_doacross_init(ident_t *loc, kmp_int32 gtid, kmp_int32
- // num_dims, struct kmp_dim *dims);
- OMPRTL__kmpc_doacross_init,
- // Call to void __kmpc_doacross_fini(ident_t *loc, kmp_int32 gtid);
- OMPRTL__kmpc_doacross_fini,
- // Call to void __kmpc_doacross_post(ident_t *loc, kmp_int32 gtid, kmp_int64
- // *vec);
- OMPRTL__kmpc_doacross_post,
- // Call to void __kmpc_doacross_wait(ident_t *loc, kmp_int32 gtid, kmp_int64
- // *vec);
- OMPRTL__kmpc_doacross_wait,
- // Call to void *__kmpc_task_reduction_init(int gtid, int num_data, void
- // *data);
- OMPRTL__kmpc_task_reduction_init,
- // Call to void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
- // *d);
- OMPRTL__kmpc_task_reduction_get_th_data,
-
- //
- // Offloading related calls
- //
- // Call to void __kmpc_push_target_tripcount(int64_t device_id, kmp_uint64
- // size);
- OMPRTL__kmpc_push_target_tripcount,
- // Call to int32_t __tgt_target(int64_t device_id, void *host_ptr, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- OMPRTL__tgt_target,
- // Call to int32_t __tgt_target_nowait(int64_t device_id, void *host_ptr,
- // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- OMPRTL__tgt_target_nowait,
- // Call to int32_t __tgt_target_teams(int64_t device_id, void *host_ptr,
- // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types, int32_t num_teams, int32_t thread_limit);
- OMPRTL__tgt_target_teams,
- // Call to int32_t __tgt_target_teams_nowait(int64_t device_id, void
- // *host_ptr, int32_t arg_num, void** args_base, void **args, size_t
- // *arg_sizes, int64_t *arg_types, int32_t num_teams, int32_t thread_limit);
- OMPRTL__tgt_target_teams_nowait,
- // Call to void __tgt_register_lib(__tgt_bin_desc *desc);
- OMPRTL__tgt_register_lib,
- // Call to void __tgt_unregister_lib(__tgt_bin_desc *desc);
- OMPRTL__tgt_unregister_lib,
- // Call to void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
- // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types);
- OMPRTL__tgt_target_data_begin,
- // Call to void __tgt_target_data_begin_nowait(int64_t device_id, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- OMPRTL__tgt_target_data_begin_nowait,
- // Call to void __tgt_target_data_end(int64_t device_id, int32_t arg_num,
- // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types);
- OMPRTL__tgt_target_data_end,
- // Call to void __tgt_target_data_end_nowait(int64_t device_id, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- OMPRTL__tgt_target_data_end_nowait,
- // Call to void __tgt_target_data_update(int64_t device_id, int32_t arg_num,
- // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types);
- OMPRTL__tgt_target_data_update,
- // Call to void __tgt_target_data_update_nowait(int64_t device_id, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- OMPRTL__tgt_target_data_update_nowait,
-};
-
-/// A basic class for pre|post-action for advanced codegen sequence for OpenMP
-/// region.
-class CleanupTy final : public EHScopeStack::Cleanup {
- PrePostActionTy *Action;
-
-public:
- explicit CleanupTy(PrePostActionTy *Action) : Action(Action) {}
- void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
- if (!CGF.HaveInsertPoint())
- return;
- Action->Exit(CGF);
- }
-};
-
-} // anonymous namespace
-
-void RegionCodeGenTy::operator()(CodeGenFunction &CGF) const {
- CodeGenFunction::RunCleanupsScope Scope(CGF);
- if (PrePostAction) {
- CGF.EHStack.pushCleanup<CleanupTy>(NormalAndEHCleanup, PrePostAction);
- Callback(CodeGen, CGF, *PrePostAction);
- } else {
- PrePostActionTy Action;
- Callback(CodeGen, CGF, Action);
- }
-}
-
-/// Check if the combiner is a call to UDR combiner and if it is so return the
-/// UDR decl used for reduction.
-static const OMPDeclareReductionDecl *
-getReductionInit(const Expr *ReductionOp) {
- if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
- if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
- if (const auto *DRE =
- dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
- if (const auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
- return DRD;
- return nullptr;
-}
-
-static void emitInitWithReductionInitializer(CodeGenFunction &CGF,
- const OMPDeclareReductionDecl *DRD,
- const Expr *InitOp,
- Address Private, Address Original,
- QualType Ty) {
- if (DRD->getInitializer()) {
- std::pair<llvm::Function *, llvm::Function *> Reduction =
- CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
- const auto *CE = cast<CallExpr>(InitOp);
- const auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
- const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
- const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
- const auto *LHSDRE =
- cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
- const auto *RHSDRE =
- cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()),
- [=]() { return Private; });
- PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()),
- [=]() { return Original; });
- (void)PrivateScope.Privatize();
- RValue Func = RValue::get(Reduction.second);
- CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
- CGF.EmitIgnoredExpr(InitOp);
- } else {
- llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
- std::string Name = CGF.CGM.getOpenMPRuntime().getName({"init"});
- auto *GV = new llvm::GlobalVariable(
- CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Init, Name);
- LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty);
- RValue InitRVal;
- switch (CGF.getEvaluationKind(Ty)) {
- case TEK_Scalar:
- InitRVal = CGF.EmitLoadOfLValue(LV, DRD->getLocation());
- break;
- case TEK_Complex:
- InitRVal =
- RValue::getComplex(CGF.EmitLoadOfComplex(LV, DRD->getLocation()));
- break;
- case TEK_Aggregate:
- InitRVal = RValue::getAggregate(LV.getAddress());
- break;
- }
- OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_RValue);
- CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
- CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
- /*IsInitializer=*/false);
- }
-}
-
-/// Emit initialization of arrays of complex types.
-/// \param DestAddr Address of the array.
-/// \param Type Type of array.
-/// \param Init Initial expression of array.
-/// \param SrcAddr Address of the original array.
-static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
- QualType Type, bool EmitDeclareReductionInit,
- const Expr *Init,
- const OMPDeclareReductionDecl *DRD,
- Address SrcAddr = Address::invalid()) {
- // Perform element-by-element initialization.
- QualType ElementTy;
-
- // Drill down to the base element type on both arrays.
- const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
- llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
- DestAddr =
- CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType());
- if (DRD)
- SrcAddr =
- CGF.Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
-
- llvm::Value *SrcBegin = nullptr;
- if (DRD)
- SrcBegin = SrcAddr.getPointer();
- llvm::Value *DestBegin = DestAddr.getPointer();
- // Cast from pointer to array type to pointer to single element.
- llvm::Value *DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements);
- // The basic structure here is a while-do loop.
- llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
- llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
- llvm::Value *IsEmpty =
- CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
- CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
-
- // Enter the loop body, making that address the current address.
- llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(BodyBB);
-
- CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
-
- llvm::PHINode *SrcElementPHI = nullptr;
- Address SrcElementCurrent = Address::invalid();
- if (DRD) {
- SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
- "omp.arraycpy.srcElementPast");
- SrcElementPHI->addIncoming(SrcBegin, EntryBB);
- SrcElementCurrent =
- Address(SrcElementPHI,
- SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
- }
- llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
- DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
- DestElementPHI->addIncoming(DestBegin, EntryBB);
- Address DestElementCurrent =
- Address(DestElementPHI,
- DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
-
- // Emit copy.
- {
- CodeGenFunction::RunCleanupsScope InitScope(CGF);
- if (EmitDeclareReductionInit) {
- emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
- SrcElementCurrent, ElementTy);
- } else
- CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
- /*IsInitializer=*/false);
- }
-
- if (DRD) {
- // Shift the address forward by one element.
- llvm::Value *SrcElementNext = CGF.Builder.CreateConstGEP1_32(
- SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
- }
-
- // Shift the address forward by one element.
- llvm::Value *DestElementNext = CGF.Builder.CreateConstGEP1_32(
- DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- // Check whether we've reached the end.
- llvm::Value *Done =
- CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
- CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
- DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
-
- // Done.
- CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
-LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) {
- return CGF.EmitOMPSharedLValue(E);
-}
-
-LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF,
- const Expr *E) {
- if (const auto *OASE = dyn_cast<OMPArraySectionExpr>(E))
- return CGF.EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false);
- return LValue();
-}
-
-void ReductionCodeGen::emitAggregateInitialization(
- CodeGenFunction &CGF, unsigned N, Address PrivateAddr, LValue SharedLVal,
- const OMPDeclareReductionDecl *DRD) {
- // Emit VarDecl with copy init for arrays.
- // Get the address of the original variable captured in current
- // captured region.
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
- bool EmitDeclareReductionInit =
- DRD && (DRD->getInitializer() || !PrivateVD->hasInit());
- EmitOMPAggregateInit(CGF, PrivateAddr, PrivateVD->getType(),
- EmitDeclareReductionInit,
- EmitDeclareReductionInit ? ClausesData[N].ReductionOp
- : PrivateVD->getInit(),
- DRD, SharedLVal.getAddress());
-}
-
-ReductionCodeGen::ReductionCodeGen(ArrayRef<const Expr *> Shareds,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> ReductionOps) {
- ClausesData.reserve(Shareds.size());
- SharedAddresses.reserve(Shareds.size());
- Sizes.reserve(Shareds.size());
- BaseDecls.reserve(Shareds.size());
- auto IPriv = Privates.begin();
- auto IRed = ReductionOps.begin();
- for (const Expr *Ref : Shareds) {
- ClausesData.emplace_back(Ref, *IPriv, *IRed);
- std::advance(IPriv, 1);
- std::advance(IRed, 1);
- }
-}
-
-void ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, unsigned N) {
- assert(SharedAddresses.size() == N &&
- "Number of generated lvalues must be exactly N.");
- LValue First = emitSharedLValue(CGF, ClausesData[N].Ref);
- LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Ref);
- SharedAddresses.emplace_back(First, Second);
-}
-
-void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) {
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
- QualType PrivateType = PrivateVD->getType();
- bool AsArraySection = isa<OMPArraySectionExpr>(ClausesData[N].Ref);
- if (!PrivateType->isVariablyModifiedType()) {
- Sizes.emplace_back(
- CGF.getTypeSize(
- SharedAddresses[N].first.getType().getNonReferenceType()),
- nullptr);
- return;
- }
- llvm::Value *Size;
- llvm::Value *SizeInChars;
- auto *ElemType =
- cast<llvm::PointerType>(SharedAddresses[N].first.getPointer()->getType())
- ->getElementType();
- auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType);
- if (AsArraySection) {
- Size = CGF.Builder.CreatePtrDiff(SharedAddresses[N].second.getPointer(),
- SharedAddresses[N].first.getPointer());
- Size = CGF.Builder.CreateNUWAdd(
- Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
- SizeInChars = CGF.Builder.CreateNUWMul(Size, ElemSizeOf);
- } else {
- SizeInChars = CGF.getTypeSize(
- SharedAddresses[N].first.getType().getNonReferenceType());
- Size = CGF.Builder.CreateExactUDiv(SizeInChars, ElemSizeOf);
- }
- Sizes.emplace_back(SizeInChars, Size);
- CodeGenFunction::OpaqueValueMapping OpaqueMap(
- CGF,
- cast<OpaqueValueExpr>(
- CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
- RValue::get(Size));
- CGF.EmitVariablyModifiedType(PrivateType);
-}
-
-void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N,
- llvm::Value *Size) {
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
- QualType PrivateType = PrivateVD->getType();
- if (!PrivateType->isVariablyModifiedType()) {
- assert(!Size && !Sizes[N].second &&
- "Size should be nullptr for non-variably modified reduction "
- "items.");
- return;
- }
- CodeGenFunction::OpaqueValueMapping OpaqueMap(
- CGF,
- cast<OpaqueValueExpr>(
- CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
- RValue::get(Size));
- CGF.EmitVariablyModifiedType(PrivateType);
-}
-
-void ReductionCodeGen::emitInitialization(
- CodeGenFunction &CGF, unsigned N, Address PrivateAddr, LValue SharedLVal,
- llvm::function_ref<bool(CodeGenFunction &)> DefaultInit) {
- assert(SharedAddresses.size() > N && "No variable was generated");
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
- const OMPDeclareReductionDecl *DRD =
- getReductionInit(ClausesData[N].ReductionOp);
- QualType PrivateType = PrivateVD->getType();
- PrivateAddr = CGF.Builder.CreateElementBitCast(
- PrivateAddr, CGF.ConvertTypeForMem(PrivateType));
- QualType SharedType = SharedAddresses[N].first.getType();
- SharedLVal = CGF.MakeAddrLValue(
- CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(),
- CGF.ConvertTypeForMem(SharedType)),
- SharedType, SharedAddresses[N].first.getBaseInfo(),
- CGF.CGM.getTBAAInfoForSubobject(SharedAddresses[N].first, SharedType));
- if (CGF.getContext().getAsArrayType(PrivateVD->getType())) {
- emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD);
- } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
- emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
- PrivateAddr, SharedLVal.getAddress(),
- SharedLVal.getType());
- } else if (!DefaultInit(CGF) && PrivateVD->hasInit() &&
- !CGF.isTrivialInitializer(PrivateVD->getInit())) {
- CGF.EmitAnyExprToMem(PrivateVD->getInit(), PrivateAddr,
- PrivateVD->getType().getQualifiers(),
- /*IsInitializer=*/false);
- }
-}
-
-bool ReductionCodeGen::needCleanups(unsigned N) {
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
- QualType PrivateType = PrivateVD->getType();
- QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
- return DTorKind != QualType::DK_none;
-}
-
-void ReductionCodeGen::emitCleanups(CodeGenFunction &CGF, unsigned N,
- Address PrivateAddr) {
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
- QualType PrivateType = PrivateVD->getType();
- QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
- if (needCleanups(N)) {
- PrivateAddr = CGF.Builder.CreateElementBitCast(
- PrivateAddr, CGF.ConvertTypeForMem(PrivateType));
- CGF.pushDestroy(DTorKind, PrivateAddr, PrivateType);
- }
-}
-
-static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
- LValue BaseLV) {
- BaseTy = BaseTy.getNonReferenceType();
- while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
- !CGF.getContext().hasSameType(BaseTy, ElTy)) {
- if (const auto *PtrTy = BaseTy->getAs<PointerType>()) {
- BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
- } else {
- LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy);
- BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal);
- }
- BaseTy = BaseTy->getPointeeType();
- }
- return CGF.MakeAddrLValue(
- CGF.Builder.CreateElementBitCast(BaseLV.getAddress(),
- CGF.ConvertTypeForMem(ElTy)),
- BaseLV.getType(), BaseLV.getBaseInfo(),
- CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType()));
-}
-
-static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
- llvm::Type *BaseLVType, CharUnits BaseLVAlignment,
- llvm::Value *Addr) {
- Address Tmp = Address::invalid();
- Address TopTmp = Address::invalid();
- Address MostTopTmp = Address::invalid();
- BaseTy = BaseTy.getNonReferenceType();
- while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
- !CGF.getContext().hasSameType(BaseTy, ElTy)) {
- Tmp = CGF.CreateMemTemp(BaseTy);
- if (TopTmp.isValid())
- CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
- else
- MostTopTmp = Tmp;
- TopTmp = Tmp;
- BaseTy = BaseTy->getPointeeType();
- }
- llvm::Type *Ty = BaseLVType;
- if (Tmp.isValid())
- Ty = Tmp.getElementType();
- Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Ty);
- if (Tmp.isValid()) {
- CGF.Builder.CreateStore(Addr, Tmp);
- return MostTopTmp;
- }
- return Address(Addr, BaseLVAlignment);
-}
-
-static const VarDecl *getBaseDecl(const Expr *Ref, const DeclRefExpr *&DE) {
- const VarDecl *OrigVD = nullptr;
- if (const auto *OASE = dyn_cast<OMPArraySectionExpr>(Ref)) {
- const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
- while (const auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
- Base = TempOASE->getBase()->IgnoreParenImpCasts();
- while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- DE = cast<DeclRefExpr>(Base);
- OrigVD = cast<VarDecl>(DE->getDecl());
- } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Ref)) {
- const Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
- while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- DE = cast<DeclRefExpr>(Base);
- OrigVD = cast<VarDecl>(DE->getDecl());
- }
- return OrigVD;
-}
-
-Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
- Address PrivateAddr) {
- const DeclRefExpr *DE;
- if (const VarDecl *OrigVD = ::getBaseDecl(ClausesData[N].Ref, DE)) {
- BaseDecls.emplace_back(OrigVD);
- LValue OriginalBaseLValue = CGF.EmitLValue(DE);
- LValue BaseLValue =
- loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(),
- OriginalBaseLValue);
- llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
- BaseLValue.getPointer(), SharedAddresses[N].first.getPointer());
- llvm::Value *PrivatePointer =
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- PrivateAddr.getPointer(),
- SharedAddresses[N].first.getAddress().getType());
- llvm::Value *Ptr = CGF.Builder.CreateGEP(PrivatePointer, Adjustment);
- return castToBase(CGF, OrigVD->getType(),
- SharedAddresses[N].first.getType(),
- OriginalBaseLValue.getAddress().getType(),
- OriginalBaseLValue.getAlignment(), Ptr);
- }
- BaseDecls.emplace_back(
- cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Ref)->getDecl()));
- return PrivateAddr;
-}
-
-bool ReductionCodeGen::usesReductionInitializer(unsigned N) const {
- const OMPDeclareReductionDecl *DRD =
- getReductionInit(ClausesData[N].ReductionOp);
- return DRD && DRD->getInitializer();
-}
-
-LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
- return CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(getThreadIDVariable()),
- getThreadIDVariable()->getType()->castAs<PointerType>());
-}
-
-void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt * /*S*/) {
- if (!CGF.HaveInsertPoint())
- return;
- // 1.2.2 OpenMP Language Terminology
- // Structured block - An executable statement with a single entry at the
- // top and a single exit at the bottom.
- // The point of exit cannot be a branch out of the structured block.
- // longjmp() and throw() must not violate the entry/exit criteria.
- CGF.EHStack.pushTerminate();
- CodeGen(CGF);
- CGF.EHStack.popTerminate();
-}
-
-LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue(
- CodeGenFunction &CGF) {
- return CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(getThreadIDVariable()),
- getThreadIDVariable()->getType(),
- AlignmentSource::Decl);
-}
-
-static FieldDecl *addFieldToRecordDecl(ASTContext &C, DeclContext *DC,
- QualType FieldTy) {
- auto *Field = FieldDecl::Create(
- C, DC, SourceLocation(), SourceLocation(), /*Id=*/nullptr, FieldTy,
- C.getTrivialTypeSourceInfo(FieldTy, SourceLocation()),
- /*BW=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit);
- Field->setAccess(AS_public);
- DC->addDecl(Field);
- return Field;
-}
-
-CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
- StringRef Separator)
- : CGM(CGM), FirstSeparator(FirstSeparator), Separator(Separator),
- OffloadEntriesInfoManager(CGM) {
- ASTContext &C = CGM.getContext();
- RecordDecl *RD = C.buildImplicitRecord("ident_t");
- QualType KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
- RD->startDefinition();
- // reserved_1
- addFieldToRecordDecl(C, RD, KmpInt32Ty);
- // flags
- addFieldToRecordDecl(C, RD, KmpInt32Ty);
- // reserved_2
- addFieldToRecordDecl(C, RD, KmpInt32Ty);
- // reserved_3
- addFieldToRecordDecl(C, RD, KmpInt32Ty);
- // psource
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- RD->completeDefinition();
- IdentQTy = C.getRecordType(RD);
- IdentTy = CGM.getTypes().ConvertRecordDeclType(RD);
- KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
-
- loadOffloadInfoMetadata();
-}
-
-void CGOpenMPRuntime::clear() {
- InternalVars.clear();
- // Clean non-target variable declarations possibly used only in debug info.
- for (const auto &Data : EmittedNonTargetVariables) {
- if (!Data.getValue().pointsToAliveValue())
- continue;
- auto *GV = dyn_cast<llvm::GlobalVariable>(Data.getValue());
- if (!GV)
- continue;
- if (!GV->isDeclaration() || GV->getNumUses() > 0)
- continue;
- GV->eraseFromParent();
- }
-}
-
-std::string CGOpenMPRuntime::getName(ArrayRef<StringRef> Parts) const {
- SmallString<128> Buffer;
- llvm::raw_svector_ostream OS(Buffer);
- StringRef Sep = FirstSeparator;
- for (StringRef Part : Parts) {
- OS << Sep << Part;
- Sep = Separator;
- }
- return OS.str();
-}
-
-static llvm::Function *
-emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
- const Expr *CombinerInitializer, const VarDecl *In,
- const VarDecl *Out, bool IsCombiner) {
- // void .omp_combiner.(Ty *in, Ty *out);
- ASTContext &C = CGM.getContext();
- QualType PtrTy = C.getPointerType(Ty).withRestrict();
- FunctionArgList Args;
- ImplicitParamDecl OmpOutParm(C, /*DC=*/nullptr, Out->getLocation(),
- /*Id=*/nullptr, PtrTy, ImplicitParamDecl::Other);
- ImplicitParamDecl OmpInParm(C, /*DC=*/nullptr, In->getLocation(),
- /*Id=*/nullptr, PtrTy, ImplicitParamDecl::Other);
- Args.push_back(&OmpOutParm);
- Args.push_back(&OmpInParm);
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
- std::string Name = CGM.getOpenMPRuntime().getName(
- {IsCombiner ? "omp_combiner" : "omp_initializer", ""});
- auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
- Name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
- Fn->removeFnAttr(llvm::Attribute::NoInline);
- Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
- Fn->addFnAttr(llvm::Attribute::AlwaysInline);
- CodeGenFunction CGF(CGM);
- // Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
- // Map "T omp_out;" variable to "*omp_out_parm" value in all expressions.
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, In->getLocation(),
- Out->getLocation());
- CodeGenFunction::OMPPrivateScope Scope(CGF);
- Address AddrIn = CGF.GetAddrOfLocalVar(&OmpInParm);
- Scope.addPrivate(In, [&CGF, AddrIn, PtrTy]() {
- return CGF.EmitLoadOfPointerLValue(AddrIn, PtrTy->castAs<PointerType>())
- .getAddress();
- });
- Address AddrOut = CGF.GetAddrOfLocalVar(&OmpOutParm);
- Scope.addPrivate(Out, [&CGF, AddrOut, PtrTy]() {
- return CGF.EmitLoadOfPointerLValue(AddrOut, PtrTy->castAs<PointerType>())
- .getAddress();
- });
- (void)Scope.Privatize();
- if (!IsCombiner && Out->hasInit() &&
- !CGF.isTrivialInitializer(Out->getInit())) {
- CGF.EmitAnyExprToMem(Out->getInit(), CGF.GetAddrOfLocalVar(Out),
- Out->getType().getQualifiers(),
- /*IsInitializer=*/true);
- }
- if (CombinerInitializer)
- CGF.EmitIgnoredExpr(CombinerInitializer);
- Scope.ForceCleanup();
- CGF.FinishFunction();
- return Fn;
-}
-
-void CGOpenMPRuntime::emitUserDefinedReduction(
- CodeGenFunction *CGF, const OMPDeclareReductionDecl *D) {
- if (UDRMap.count(D) > 0)
- return;
- llvm::Function *Combiner = emitCombinerOrInitializer(
- CGM, D->getType(), D->getCombiner(),
- cast<VarDecl>(cast<DeclRefExpr>(D->getCombinerIn())->getDecl()),
- cast<VarDecl>(cast<DeclRefExpr>(D->getCombinerOut())->getDecl()),
- /*IsCombiner=*/true);
- llvm::Function *Initializer = nullptr;
- if (const Expr *Init = D->getInitializer()) {
- Initializer = emitCombinerOrInitializer(
- CGM, D->getType(),
- D->getInitializerKind() == OMPDeclareReductionDecl::CallInit ? Init
- : nullptr,
- cast<VarDecl>(cast<DeclRefExpr>(D->getInitOrig())->getDecl()),
- cast<VarDecl>(cast<DeclRefExpr>(D->getInitPriv())->getDecl()),
- /*IsCombiner=*/false);
- }
- UDRMap.try_emplace(D, Combiner, Initializer);
- if (CGF) {
- auto &Decls = FunctionUDRMap.FindAndConstruct(CGF->CurFn);
- Decls.second.push_back(D);
- }
-}
-
-std::pair<llvm::Function *, llvm::Function *>
-CGOpenMPRuntime::getUserDefinedReduction(const OMPDeclareReductionDecl *D) {
- auto I = UDRMap.find(D);
- if (I != UDRMap.end())
- return I->second;
- emitUserDefinedReduction(/*CGF=*/nullptr, D);
- return UDRMap.lookup(D);
-}
-
-static llvm::Value *emitParallelOrTeamsOutlinedFunction(
- CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS,
- const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
- const StringRef OutlinedHelperName, const RegionCodeGenTy &CodeGen) {
- assert(ThreadIDVar->getType()->isPointerType() &&
- "thread id variable must be of type kmp_int32 *");
- CodeGenFunction CGF(CGM, true);
- bool HasCancel = false;
- if (const auto *OPD = dyn_cast<OMPParallelDirective>(&D))
- HasCancel = OPD->hasCancel();
- else if (const auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&D))
- HasCancel = OPSD->hasCancel();
- else if (const auto *OPFD = dyn_cast<OMPParallelForDirective>(&D))
- HasCancel = OPFD->hasCancel();
- else if (const auto *OPFD = dyn_cast<OMPTargetParallelForDirective>(&D))
- HasCancel = OPFD->hasCancel();
- else if (const auto *OPFD = dyn_cast<OMPDistributeParallelForDirective>(&D))
- HasCancel = OPFD->hasCancel();
- else if (const auto *OPFD =
- dyn_cast<OMPTeamsDistributeParallelForDirective>(&D))
- HasCancel = OPFD->hasCancel();
- else if (const auto *OPFD =
- dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&D))
- HasCancel = OPFD->hasCancel();
- CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind,
- HasCancel, OutlinedHelperName);
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
- return CGF.GenerateOpenMPCapturedStmtFunction(*CS);
-}
-
-llvm::Value *CGOpenMPRuntime::emitParallelOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
- const CapturedStmt *CS = D.getCapturedStmt(OMPD_parallel);
- return emitParallelOrTeamsOutlinedFunction(
- CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(), CodeGen);
-}
-
-llvm::Value *CGOpenMPRuntime::emitTeamsOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
- const CapturedStmt *CS = D.getCapturedStmt(OMPD_teams);
- return emitParallelOrTeamsOutlinedFunction(
- CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(), CodeGen);
-}
-
-llvm::Value *CGOpenMPRuntime::emitTaskOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- const VarDecl *PartIDVar, const VarDecl *TaskTVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
- bool Tied, unsigned &NumberOfParts) {
- auto &&UntiedCodeGen = [this, &D, TaskTVar](CodeGenFunction &CGF,
- PrePostActionTy &) {
- llvm::Value *ThreadID = getThreadID(CGF, D.getBeginLoc());
- llvm::Value *UpLoc = emitUpdateLocation(CGF, D.getBeginLoc());
- llvm::Value *TaskArgs[] = {
- UpLoc, ThreadID,
- CGF.EmitLoadOfPointerLValue(CGF.GetAddrOfLocalVar(TaskTVar),
- TaskTVar->getType()->castAs<PointerType>())
- .getPointer()};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task), TaskArgs);
- };
- CGOpenMPTaskOutlinedRegionInfo::UntiedTaskActionTy Action(Tied, PartIDVar,
- UntiedCodeGen);
- CodeGen.setAction(Action);
- assert(!ThreadIDVar->getType()->isPointerType() &&
- "thread id variable must be of type kmp_int32 for tasks");
- const OpenMPDirectiveKind Region =
- isOpenMPTaskLoopDirective(D.getDirectiveKind()) ? OMPD_taskloop
- : OMPD_task;
- const CapturedStmt *CS = D.getCapturedStmt(Region);
- const auto *TD = dyn_cast<OMPTaskDirective>(&D);
- CodeGenFunction CGF(CGM, true);
- CGOpenMPTaskOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen,
- InnermostKind,
- TD ? TD->hasCancel() : false, Action);
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
- llvm::Value *Res = CGF.GenerateCapturedStmtFunction(*CS);
- if (!Tied)
- NumberOfParts = Action.getNumberOfParts();
- return Res;
-}
-
-static void buildStructValue(ConstantStructBuilder &Fields, CodeGenModule &CGM,
- const RecordDecl *RD, const CGRecordLayout &RL,
- ArrayRef<llvm::Constant *> Data) {
- llvm::StructType *StructTy = RL.getLLVMType();
- unsigned PrevIdx = 0;
- ConstantInitBuilder CIBuilder(CGM);
- auto DI = Data.begin();
- for (const FieldDecl *FD : RD->fields()) {
- unsigned Idx = RL.getLLVMFieldNo(FD);
- // Fill the alignment.
- for (unsigned I = PrevIdx; I < Idx; ++I)
- Fields.add(llvm::Constant::getNullValue(StructTy->getElementType(I)));
- PrevIdx = Idx + 1;
- Fields.add(*DI);
- ++DI;
- }
-}
-
-template <class... As>
-static llvm::GlobalVariable *
-createGlobalStruct(CodeGenModule &CGM, QualType Ty, bool IsConstant,
- ArrayRef<llvm::Constant *> Data, const Twine &Name,
- As &&... Args) {
- const auto *RD = cast<RecordDecl>(Ty->getAsTagDecl());
- const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(RD);
- ConstantInitBuilder CIBuilder(CGM);
- ConstantStructBuilder Fields = CIBuilder.beginStruct(RL.getLLVMType());
- buildStructValue(Fields, CGM, RD, RL, Data);
- return Fields.finishAndCreateGlobal(
- Name, CGM.getContext().getAlignOfGlobalVarInChars(Ty), IsConstant,
- std::forward<As>(Args)...);
-}
-
-template <typename T>
-static void
-createConstantGlobalStructAndAddToParent(CodeGenModule &CGM, QualType Ty,
- ArrayRef<llvm::Constant *> Data,
- T &Parent) {
- const auto *RD = cast<RecordDecl>(Ty->getAsTagDecl());
- const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(RD);
- ConstantStructBuilder Fields = Parent.beginStruct(RL.getLLVMType());
- buildStructValue(Fields, CGM, RD, RL, Data);
- Fields.finishAndAddTo(Parent);
-}
-
-Address CGOpenMPRuntime::getOrCreateDefaultLocation(unsigned Flags) {
- CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);
- unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
- FlagsTy FlagsKey(Flags, Reserved2Flags);
- llvm::Value *Entry = OpenMPDefaultLocMap.lookup(FlagsKey);
- if (!Entry) {
- if (!DefaultOpenMPPSource) {
- // Initialize default location for psource field of ident_t structure of
- // all ident_t objects. Format is ";file;function;line;column;;".
- // Taken from
- // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp_str.c
- DefaultOpenMPPSource =
- CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;").getPointer();
- DefaultOpenMPPSource =
- llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
- }
-
- llvm::Constant *Data[] = {
- llvm::ConstantInt::getNullValue(CGM.Int32Ty),
- llvm::ConstantInt::get(CGM.Int32Ty, Flags),
- llvm::ConstantInt::get(CGM.Int32Ty, Reserved2Flags),
- llvm::ConstantInt::getNullValue(CGM.Int32Ty), DefaultOpenMPPSource};
- llvm::GlobalValue *DefaultOpenMPLocation =
- createGlobalStruct(CGM, IdentQTy, isDefaultLocationConstant(), Data, "",
- llvm::GlobalValue::PrivateLinkage);
- DefaultOpenMPLocation->setUnnamedAddr(
- llvm::GlobalValue::UnnamedAddr::Global);
-
- OpenMPDefaultLocMap[FlagsKey] = Entry = DefaultOpenMPLocation;
- }
- return Address(Entry, Align);
-}
-
-void CGOpenMPRuntime::setLocThreadIdInsertPt(CodeGenFunction &CGF,
- bool AtCurrentPoint) {
- auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
- assert(!Elem.second.ServiceInsertPt && "Insert point is set already.");
-
- llvm::Value *Undef = llvm::UndefValue::get(CGF.Int32Ty);
- if (AtCurrentPoint) {
- Elem.second.ServiceInsertPt = new llvm::BitCastInst(
- Undef, CGF.Int32Ty, "svcpt", CGF.Builder.GetInsertBlock());
- } else {
- Elem.second.ServiceInsertPt =
- new llvm::BitCastInst(Undef, CGF.Int32Ty, "svcpt");
- Elem.second.ServiceInsertPt->insertAfter(CGF.AllocaInsertPt);
- }
-}
-
-void CGOpenMPRuntime::clearLocThreadIdInsertPt(CodeGenFunction &CGF) {
- auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
- if (Elem.second.ServiceInsertPt) {
- llvm::Instruction *Ptr = Elem.second.ServiceInsertPt;
- Elem.second.ServiceInsertPt = nullptr;
- Ptr->eraseFromParent();
- }
-}
-
-llvm::Value *CGOpenMPRuntime::emitUpdateLocation(CodeGenFunction &CGF,
- SourceLocation Loc,
- unsigned Flags) {
- Flags |= OMP_IDENT_KMPC;
- // If no debug info is generated - return global default location.
- if (CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo ||
- Loc.isInvalid())
- return getOrCreateDefaultLocation(Flags).getPointer();
-
- assert(CGF.CurFn && "No function in current CodeGenFunction.");
-
- CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);
- Address LocValue = Address::invalid();
- auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
- if (I != OpenMPLocThreadIDMap.end())
- LocValue = Address(I->second.DebugLoc, Align);
-
- // OpenMPLocThreadIDMap may have null DebugLoc and non-null ThreadID, if
- // GetOpenMPThreadID was called before this routine.
- if (!LocValue.isValid()) {
- // Generate "ident_t .kmpc_loc.addr;"
- Address AI = CGF.CreateMemTemp(IdentQTy, ".kmpc_loc.addr");
- auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
- Elem.second.DebugLoc = AI.getPointer();
- LocValue = AI;
-
- if (!Elem.second.ServiceInsertPt)
- setLocThreadIdInsertPt(CGF);
- CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
- CGF.Builder.SetInsertPoint(Elem.second.ServiceInsertPt);
- CGF.Builder.CreateMemCpy(LocValue, getOrCreateDefaultLocation(Flags),
- CGF.getTypeSize(IdentQTy));
- }
-
- // char **psource = &.kmpc_loc_<flags>.addr.psource;
- LValue Base = CGF.MakeAddrLValue(LocValue, IdentQTy);
- auto Fields = cast<RecordDecl>(IdentQTy->getAsTagDecl())->field_begin();
- LValue PSource =
- CGF.EmitLValueForField(Base, *std::next(Fields, IdentField_PSource));
-
- llvm::Value *OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
- if (OMPDebugLoc == nullptr) {
- SmallString<128> Buffer2;
- llvm::raw_svector_ostream OS2(Buffer2);
- // Build debug location
- PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
- OS2 << ";" << PLoc.getFilename() << ";";
- if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
- OS2 << FD->getQualifiedNameAsString();
- OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
- OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str());
- OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc;
- }
- // *psource = ";<File>;<Function>;<Line>;<Column>;;";
- CGF.EmitStoreOfScalar(OMPDebugLoc, PSource);
-
- // Our callers always pass this to a runtime function, so for
- // convenience, go ahead and return a naked pointer.
- return LocValue.getPointer();
-}
-
-llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
- SourceLocation Loc) {
- assert(CGF.CurFn && "No function in current CodeGenFunction.");
-
- llvm::Value *ThreadID = nullptr;
- // Check whether we've already cached a load of the thread id in this
- // function.
- auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
- if (I != OpenMPLocThreadIDMap.end()) {
- ThreadID = I->second.ThreadID;
- if (ThreadID != nullptr)
- return ThreadID;
- }
- // If exceptions are enabled, do not use parameter to avoid possible crash.
- if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions ||
- !CGF.getLangOpts().CXXExceptions ||
- CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- if (OMPRegionInfo->getThreadIDVariable()) {
- // Check if this an outlined function with thread id passed as argument.
- LValue LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
- ThreadID = CGF.EmitLoadOfScalar(LVal, Loc);
- // If value loaded in entry block, cache it and use it everywhere in
- // function.
- if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
- auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
- Elem.second.ThreadID = ThreadID;
- }
- return ThreadID;
- }
- }
- }
-
- // This is not an outlined function region - need to call __kmpc_int32
- // kmpc_global_thread_num(ident_t *loc).
- // Generate thread id value and cache this value for use across the
- // function.
- auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
- if (!Elem.second.ServiceInsertPt)
- setLocThreadIdInsertPt(CGF);
- CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
- CGF.Builder.SetInsertPoint(Elem.second.ServiceInsertPt);
- llvm::CallInst *Call = CGF.Builder.CreateCall(
- createRuntimeFunction(OMPRTL__kmpc_global_thread_num),
- emitUpdateLocation(CGF, Loc));
- Call->setCallingConv(CGF.getRuntimeCC());
- Elem.second.ThreadID = Call;
- return Call;
-}
-
-void CGOpenMPRuntime::functionFinished(CodeGenFunction &CGF) {
- assert(CGF.CurFn && "No function in current CodeGenFunction.");
- if (OpenMPLocThreadIDMap.count(CGF.CurFn)) {
- clearLocThreadIdInsertPt(CGF);
- OpenMPLocThreadIDMap.erase(CGF.CurFn);
- }
- if (FunctionUDRMap.count(CGF.CurFn) > 0) {
- for(auto *D : FunctionUDRMap[CGF.CurFn])
- UDRMap.erase(D);
- FunctionUDRMap.erase(CGF.CurFn);
- }
-}
-
-llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
- return IdentTy->getPointerTo();
-}
-
-llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() {
- if (!Kmpc_MicroTy) {
- // Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...)
- llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty),
- llvm::PointerType::getUnqual(CGM.Int32Ty)};
- Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true);
- }
- return llvm::PointerType::getUnqual(Kmpc_MicroTy);
-}
-
-llvm::Constant *
-CGOpenMPRuntime::createRuntimeFunction(unsigned Function) {
- llvm::Constant *RTLFn = nullptr;
- switch (static_cast<OpenMPRTLFunction>(Function)) {
- case OMPRTL__kmpc_fork_call: {
- // Build void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
- // microtask, ...);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- getKmpc_MicroPointerTy()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
- break;
- }
- case OMPRTL__kmpc_global_thread_num: {
- // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num");
- break;
- }
- case OMPRTL__kmpc_threadprivate_cached: {
- // Build void *__kmpc_threadprivate_cached(ident_t *loc,
- // kmp_int32 global_tid, void *data, size_t size, void ***cache);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.VoidPtrTy, CGM.SizeTy,
- CGM.VoidPtrTy->getPointerTo()->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_cached");
- break;
- }
- case OMPRTL__kmpc_critical: {
- // Build void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *crit);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty,
- llvm::PointerType::getUnqual(KmpCriticalNameTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical");
- break;
- }
- case OMPRTL__kmpc_critical_with_hint: {
- // Build void __kmpc_critical_with_hint(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *crit, uintptr_t hint);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- llvm::PointerType::getUnqual(KmpCriticalNameTy),
- CGM.IntPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical_with_hint");
- break;
- }
- case OMPRTL__kmpc_threadprivate_register: {
- // Build void __kmpc_threadprivate_register(ident_t *, void *data,
- // kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor);
- // typedef void *(*kmpc_ctor)(void *);
- auto *KmpcCtorTy =
- llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy,
- /*isVarArg*/ false)->getPointerTo();
- // typedef void *(*kmpc_cctor)(void *, void *);
- llvm::Type *KmpcCopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
- auto *KmpcCopyCtorTy =
- llvm::FunctionType::get(CGM.VoidPtrTy, KmpcCopyCtorTyArgs,
- /*isVarArg*/ false)
- ->getPointerTo();
- // typedef void (*kmpc_dtor)(void *);
- auto *KmpcDtorTy =
- llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy, /*isVarArg*/ false)
- ->getPointerTo();
- llvm::Type *FnTyArgs[] = {getIdentTyPointerTy(), CGM.VoidPtrTy, KmpcCtorTy,
- KmpcCopyCtorTy, KmpcDtorTy};
- auto *FnTy = llvm::FunctionType::get(CGM.VoidTy, FnTyArgs,
- /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_register");
- break;
- }
- case OMPRTL__kmpc_end_critical: {
- // Build void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *crit);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty,
- llvm::PointerType::getUnqual(KmpCriticalNameTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
- break;
- }
- case OMPRTL__kmpc_cancel_barrier: {
- // Build kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32
- // global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_cancel_barrier");
- break;
- }
- case OMPRTL__kmpc_barrier: {
- // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
- break;
- }
- case OMPRTL__kmpc_for_static_fini: {
- // Build void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_fini");
- break;
- }
- case OMPRTL__kmpc_push_num_threads: {
- // Build void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 num_threads)
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_num_threads");
- break;
- }
- case OMPRTL__kmpc_serialized_parallel: {
- // Build void __kmpc_serialized_parallel(ident_t *loc, kmp_int32
- // global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_serialized_parallel");
- break;
- }
- case OMPRTL__kmpc_end_serialized_parallel: {
- // Build void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32
- // global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_serialized_parallel");
- break;
- }
- case OMPRTL__kmpc_flush: {
- // Build void __kmpc_flush(ident_t *loc);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_flush");
- break;
- }
- case OMPRTL__kmpc_master: {
- // Build kmp_int32 __kmpc_master(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_master");
- break;
- }
- case OMPRTL__kmpc_end_master: {
- // Build void __kmpc_end_master(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_master");
- break;
- }
- case OMPRTL__kmpc_omp_taskyield: {
- // Build kmp_int32 __kmpc_omp_taskyield(ident_t *, kmp_int32 global_tid,
- // int end_part);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_taskyield");
- break;
- }
- case OMPRTL__kmpc_single: {
- // Build kmp_int32 __kmpc_single(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_single");
- break;
- }
- case OMPRTL__kmpc_end_single: {
- // Build void __kmpc_end_single(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_single");
- break;
- }
- case OMPRTL__kmpc_omp_task_alloc: {
- // Build kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
- // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- // kmp_routine_entry_t *task_entry);
- assert(KmpRoutineEntryPtrTy != nullptr &&
- "Type kmp_routine_entry_t must be created.");
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty,
- CGM.SizeTy, CGM.SizeTy, KmpRoutineEntryPtrTy};
- // Return void * and then cast to particular kmp_task_t type.
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_task_alloc");
- break;
- }
- case OMPRTL__kmpc_omp_task: {
- // Build kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t
- // *new_task);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_task");
- break;
- }
- case OMPRTL__kmpc_copyprivate: {
- // Build void __kmpc_copyprivate(ident_t *loc, kmp_int32 global_tid,
- // size_t cpy_size, void *cpy_data, void(*cpy_func)(void *, void *),
- // kmp_int32 didit);
- llvm::Type *CpyTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
- auto *CpyFnTy =
- llvm::FunctionType::get(CGM.VoidTy, CpyTypeParams, /*isVarArg=*/false);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.SizeTy,
- CGM.VoidPtrTy, CpyFnTy->getPointerTo(),
- CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_copyprivate");
- break;
- }
- case OMPRTL__kmpc_reduce: {
- // Build kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void
- // (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck);
- llvm::Type *ReduceTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
- auto *ReduceFnTy = llvm::FunctionType::get(CGM.VoidTy, ReduceTypeParams,
- /*isVarArg=*/false);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty, CGM.SizeTy,
- CGM.VoidPtrTy, ReduceFnTy->getPointerTo(),
- llvm::PointerType::getUnqual(KmpCriticalNameTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_reduce");
- break;
- }
- case OMPRTL__kmpc_reduce_nowait: {
- // Build kmp_int32 __kmpc_reduce_nowait(ident_t *loc, kmp_int32
- // global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data,
- // void (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name
- // *lck);
- llvm::Type *ReduceTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
- auto *ReduceFnTy = llvm::FunctionType::get(CGM.VoidTy, ReduceTypeParams,
- /*isVarArg=*/false);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty, CGM.SizeTy,
- CGM.VoidPtrTy, ReduceFnTy->getPointerTo(),
- llvm::PointerType::getUnqual(KmpCriticalNameTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_reduce_nowait");
- break;
- }
- case OMPRTL__kmpc_end_reduce: {
- // Build void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *lck);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty,
- llvm::PointerType::getUnqual(KmpCriticalNameTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce");
- break;
- }
- case OMPRTL__kmpc_end_reduce_nowait: {
- // Build __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
- // kmp_critical_name *lck);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty,
- llvm::PointerType::getUnqual(KmpCriticalNameTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce_nowait");
- break;
- }
- case OMPRTL__kmpc_omp_task_begin_if0: {
- // Build void __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t
- // *new_task);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_task_begin_if0");
- break;
- }
- case OMPRTL__kmpc_omp_task_complete_if0: {
- // Build void __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t
- // *new_task);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy,
- /*Name=*/"__kmpc_omp_task_complete_if0");
- break;
- }
- case OMPRTL__kmpc_ordered: {
- // Build void __kmpc_ordered(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_ordered");
- break;
- }
- case OMPRTL__kmpc_end_ordered: {
- // Build void __kmpc_end_ordered(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_ordered");
- break;
- }
- case OMPRTL__kmpc_omp_taskwait: {
- // Build kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_omp_taskwait");
- break;
- }
- case OMPRTL__kmpc_taskgroup: {
- // Build void __kmpc_taskgroup(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_taskgroup");
- break;
- }
- case OMPRTL__kmpc_end_taskgroup: {
- // Build void __kmpc_end_taskgroup(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_taskgroup");
- break;
- }
- case OMPRTL__kmpc_push_proc_bind: {
- // Build void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 global_tid,
- // int proc_bind)
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_proc_bind");
- break;
- }
- case OMPRTL__kmpc_omp_task_with_deps: {
- // Build kmp_int32 __kmpc_omp_task_with_deps(ident_t *, kmp_int32 gtid,
- // kmp_task_t *new_task, kmp_int32 ndeps, kmp_depend_info_t *dep_list,
- // kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty, CGM.VoidPtrTy, CGM.Int32Ty,
- CGM.VoidPtrTy, CGM.Int32Ty, CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_task_with_deps");
- break;
- }
- case OMPRTL__kmpc_omp_wait_deps: {
- // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid,
- // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32 ndeps_noalias,
- // kmp_depend_info_t *noalias_dep_list);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.Int32Ty, CGM.VoidPtrTy,
- CGM.Int32Ty, CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_wait_deps");
- break;
- }
- case OMPRTL__kmpc_cancellationpoint: {
- // Build kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
- // global_tid, kmp_int32 cncl_kind)
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancellationpoint");
- break;
- }
- case OMPRTL__kmpc_cancel: {
- // Build kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 cncl_kind)
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancel");
- break;
- }
- case OMPRTL__kmpc_push_num_teams: {
- // Build void kmpc_push_num_teams (ident_t loc, kmp_int32 global_tid,
- // kmp_int32 num_teams, kmp_int32 num_threads)
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty,
- CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_num_teams");
- break;
- }
- case OMPRTL__kmpc_fork_teams: {
- // Build void __kmpc_fork_teams(ident_t *loc, kmp_int32 argc, kmpc_micro
- // microtask, ...);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- getKmpc_MicroPointerTy()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_teams");
- break;
- }
- case OMPRTL__kmpc_taskloop: {
- // Build void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int
- // if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int
- // sched, kmp_uint64 grainsize, void *task_dup);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(),
- CGM.IntTy,
- CGM.VoidPtrTy,
- CGM.IntTy,
- CGM.Int64Ty->getPointerTo(),
- CGM.Int64Ty->getPointerTo(),
- CGM.Int64Ty,
- CGM.IntTy,
- CGM.IntTy,
- CGM.Int64Ty,
- CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_taskloop");
- break;
- }
- case OMPRTL__kmpc_doacross_init: {
- // Build void __kmpc_doacross_init(ident_t *loc, kmp_int32 gtid, kmp_int32
- // num_dims, struct kmp_dim *dims);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(),
- CGM.Int32Ty,
- CGM.Int32Ty,
- CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_doacross_init");
- break;
- }
- case OMPRTL__kmpc_doacross_fini: {
- // Build void __kmpc_doacross_fini(ident_t *loc, kmp_int32 gtid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_doacross_fini");
- break;
- }
- case OMPRTL__kmpc_doacross_post: {
- // Build void __kmpc_doacross_post(ident_t *loc, kmp_int32 gtid, kmp_int64
- // *vec);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_doacross_post");
- break;
- }
- case OMPRTL__kmpc_doacross_wait: {
- // Build void __kmpc_doacross_wait(ident_t *loc, kmp_int32 gtid, kmp_int64
- // *vec);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_doacross_wait");
- break;
- }
- case OMPRTL__kmpc_task_reduction_init: {
- // Build void *__kmpc_task_reduction_init(int gtid, int num_data, void
- // *data);
- llvm::Type *TypeParams[] = {CGM.IntTy, CGM.IntTy, CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_task_reduction_init");
- break;
- }
- case OMPRTL__kmpc_task_reduction_get_th_data: {
- // Build void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
- // *d);
- llvm::Type *TypeParams[] = {CGM.IntTy, CGM.VoidPtrTy, CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(
- FnTy, /*Name=*/"__kmpc_task_reduction_get_th_data");
- break;
- }
- case OMPRTL__kmpc_push_target_tripcount: {
- // Build void __kmpc_push_target_tripcount(int64_t device_id, kmp_uint64
- // size);
- llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.Int64Ty};
- llvm::FunctionType *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_target_tripcount");
- break;
- }
- case OMPRTL__tgt_target: {
- // Build int32_t __tgt_target(int64_t device_id, void *host_ptr, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.VoidPtrTy,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target");
- break;
- }
- case OMPRTL__tgt_target_nowait: {
- // Build int32_t __tgt_target_nowait(int64_t device_id, void *host_ptr,
- // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes,
- // int64_t *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.VoidPtrTy,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_nowait");
- break;
- }
- case OMPRTL__tgt_target_teams: {
- // Build int32_t __tgt_target_teams(int64_t device_id, void *host_ptr,
- // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes,
- // int64_t *arg_types, int32_t num_teams, int32_t thread_limit);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.VoidPtrTy,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo(),
- CGM.Int32Ty,
- CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_teams");
- break;
- }
- case OMPRTL__tgt_target_teams_nowait: {
- // Build int32_t __tgt_target_teams_nowait(int64_t device_id, void
- // *host_ptr, int32_t arg_num, void** args_base, void **args, size_t
- // *arg_sizes, int64_t *arg_types, int32_t num_teams, int32_t thread_limit);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.VoidPtrTy,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo(),
- CGM.Int32Ty,
- CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_teams_nowait");
- break;
- }
- case OMPRTL__tgt_register_lib: {
- // Build void __tgt_register_lib(__tgt_bin_desc *desc);
- QualType ParamTy =
- CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy());
- llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_register_lib");
- break;
- }
- case OMPRTL__tgt_unregister_lib: {
- // Build void __tgt_unregister_lib(__tgt_bin_desc *desc);
- QualType ParamTy =
- CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy());
- llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_unregister_lib");
- break;
- }
- case OMPRTL__tgt_target_data_begin: {
- // Build void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
- // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_begin");
- break;
- }
- case OMPRTL__tgt_target_data_begin_nowait: {
- // Build void __tgt_target_data_begin_nowait(int64_t device_id, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_begin_nowait");
- break;
- }
- case OMPRTL__tgt_target_data_end: {
- // Build void __tgt_target_data_end(int64_t device_id, int32_t arg_num,
- // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_end");
- break;
- }
- case OMPRTL__tgt_target_data_end_nowait: {
- // Build void __tgt_target_data_end_nowait(int64_t device_id, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_end_nowait");
- break;
- }
- case OMPRTL__tgt_target_data_update: {
- // Build void __tgt_target_data_update(int64_t device_id, int32_t arg_num,
- // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_update");
- break;
- }
- case OMPRTL__tgt_target_data_update_nowait: {
- // Build void __tgt_target_data_update_nowait(int64_t device_id, int32_t
- // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t
- // *arg_types);
- llvm::Type *TypeParams[] = {CGM.Int64Ty,
- CGM.Int32Ty,
- CGM.VoidPtrPtrTy,
- CGM.VoidPtrPtrTy,
- CGM.SizeTy->getPointerTo(),
- CGM.Int64Ty->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_update_nowait");
- break;
- }
- }
- assert(RTLFn && "Unable to find OpenMP runtime function");
- return RTLFn;
-}
-
-llvm::Constant *CGOpenMPRuntime::createForStaticInitFunction(unsigned IVSize,
- bool IVSigned) {
- assert((IVSize == 32 || IVSize == 64) &&
- "IV size is not compatible with the omp runtime");
- StringRef Name = IVSize == 32 ? (IVSigned ? "__kmpc_for_static_init_4"
- : "__kmpc_for_static_init_4u")
- : (IVSigned ? "__kmpc_for_static_init_8"
- : "__kmpc_for_static_init_8u");
- llvm::Type *ITy = IVSize == 32 ? CGM.Int32Ty : CGM.Int64Ty;
- auto *PtrTy = llvm::PointerType::getUnqual(ITy);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- CGM.Int32Ty, // schedtype
- llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
- PtrTy, // p_lower
- PtrTy, // p_upper
- PtrTy, // p_stride
- ITy, // incr
- ITy // chunk
- };
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- return CGM.CreateRuntimeFunction(FnTy, Name);
-}
-
-llvm::Constant *CGOpenMPRuntime::createDispatchInitFunction(unsigned IVSize,
- bool IVSigned) {
- assert((IVSize == 32 || IVSize == 64) &&
- "IV size is not compatible with the omp runtime");
- StringRef Name =
- IVSize == 32
- ? (IVSigned ? "__kmpc_dispatch_init_4" : "__kmpc_dispatch_init_4u")
- : (IVSigned ? "__kmpc_dispatch_init_8" : "__kmpc_dispatch_init_8u");
- llvm::Type *ITy = IVSize == 32 ? CGM.Int32Ty : CGM.Int64Ty;
- llvm::Type *TypeParams[] = { getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- CGM.Int32Ty, // schedtype
- ITy, // lower
- ITy, // upper
- ITy, // stride
- ITy // chunk
- };
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- return CGM.CreateRuntimeFunction(FnTy, Name);
-}
-
-llvm::Constant *CGOpenMPRuntime::createDispatchFiniFunction(unsigned IVSize,
- bool IVSigned) {
- assert((IVSize == 32 || IVSize == 64) &&
- "IV size is not compatible with the omp runtime");
- StringRef Name =
- IVSize == 32
- ? (IVSigned ? "__kmpc_dispatch_fini_4" : "__kmpc_dispatch_fini_4u")
- : (IVSigned ? "__kmpc_dispatch_fini_8" : "__kmpc_dispatch_fini_8u");
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- };
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(FnTy, Name);
-}
-
-llvm::Constant *CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize,
- bool IVSigned) {
- assert((IVSize == 32 || IVSize == 64) &&
- "IV size is not compatible with the omp runtime");
- StringRef Name =
- IVSize == 32
- ? (IVSigned ? "__kmpc_dispatch_next_4" : "__kmpc_dispatch_next_4u")
- : (IVSigned ? "__kmpc_dispatch_next_8" : "__kmpc_dispatch_next_8u");
- llvm::Type *ITy = IVSize == 32 ? CGM.Int32Ty : CGM.Int64Ty;
- auto *PtrTy = llvm::PointerType::getUnqual(ITy);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
- PtrTy, // p_lower
- PtrTy, // p_upper
- PtrTy // p_stride
- };
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- return CGM.CreateRuntimeFunction(FnTy, Name);
-}
-
-Address CGOpenMPRuntime::getAddrOfDeclareTargetLink(const VarDecl *VD) {
- if (CGM.getLangOpts().OpenMPSimd)
- return Address::invalid();
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
- SmallString<64> PtrName;
- {
- llvm::raw_svector_ostream OS(PtrName);
- OS << CGM.getMangledName(GlobalDecl(VD)) << "_decl_tgt_link_ptr";
- }
- llvm::Value *Ptr = CGM.getModule().getNamedValue(PtrName);
- if (!Ptr) {
- QualType PtrTy = CGM.getContext().getPointerType(VD->getType());
- Ptr = getOrCreateInternalVariable(CGM.getTypes().ConvertTypeForMem(PtrTy),
- PtrName);
- if (!CGM.getLangOpts().OpenMPIsDevice) {
- auto *GV = cast<llvm::GlobalVariable>(Ptr);
- GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- GV->setInitializer(CGM.GetAddrOfGlobal(VD));
- }
- CGM.addUsedGlobal(cast<llvm::GlobalValue>(Ptr));
- registerTargetGlobalVariable(VD, cast<llvm::Constant>(Ptr));
- }
- return Address(Ptr, CGM.getContext().getDeclAlign(VD));
- }
- return Address::invalid();
-}
-
-llvm::Constant *
-CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) {
- assert(!CGM.getLangOpts().OpenMPUseTLS ||
- !CGM.getContext().getTargetInfo().isTLSSupported());
- // Lookup the entry, lazily creating it if necessary.
- std::string Suffix = getName({"cache", ""});
- return getOrCreateInternalVariable(
- CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)).concat(Suffix));
-}
-
-Address CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF,
- const VarDecl *VD,
- Address VDAddr,
- SourceLocation Loc) {
- if (CGM.getLangOpts().OpenMPUseTLS &&
- CGM.getContext().getTargetInfo().isTLSSupported())
- return VDAddr;
-
- llvm::Type *VarTy = VDAddr.getElementType();
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- CGF.Builder.CreatePointerCast(VDAddr.getPointer(),
- CGM.Int8PtrTy),
- CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)),
- getOrCreateThreadPrivateCache(VD)};
- return Address(CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args),
- VDAddr.getAlignment());
-}
-
-void CGOpenMPRuntime::emitThreadPrivateVarInit(
- CodeGenFunction &CGF, Address VDAddr, llvm::Value *Ctor,
- llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc) {
- // Call kmp_int32 __kmpc_global_thread_num(&loc) to init OpenMP runtime
- // library.
- llvm::Value *OMPLoc = emitUpdateLocation(CGF, Loc);
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_global_thread_num),
- OMPLoc);
- // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor)
- // to register constructor/destructor for variable.
- llvm::Value *Args[] = {
- OMPLoc, CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.VoidPtrTy),
- Ctor, CopyCtor, Dtor};
- CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_threadprivate_register), Args);
-}
-
-llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
- const VarDecl *VD, Address VDAddr, SourceLocation Loc,
- bool PerformInit, CodeGenFunction *CGF) {
- if (CGM.getLangOpts().OpenMPUseTLS &&
- CGM.getContext().getTargetInfo().isTLSSupported())
- return nullptr;
-
- VD = VD->getDefinition(CGM.getContext());
- if (VD && ThreadPrivateWithDefinition.insert(CGM.getMangledName(VD)).second) {
- QualType ASTTy = VD->getType();
-
- llvm::Value *Ctor = nullptr, *CopyCtor = nullptr, *Dtor = nullptr;
- const Expr *Init = VD->getAnyInitializer();
- if (CGM.getLangOpts().CPlusPlus && PerformInit) {
- // Generate function that re-emits the declaration's initializer into the
- // threadprivate copy of the variable VD
- CodeGenFunction CtorCGF(CGM);
- FunctionArgList Args;
- ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, CGM.getContext().VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.push_back(&Dst);
-
- const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
- CGM.getContext().VoidPtrTy, Args);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- std::string Name = getName({"__kmpc_global_ctor_", ""});
- llvm::Function *Fn =
- CGM.CreateGlobalInitOrDestructFunction(FTy, Name, FI, Loc);
- CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI,
- Args, Loc, Loc);
- llvm::Value *ArgVal = CtorCGF.EmitLoadOfScalar(
- CtorCGF.GetAddrOfLocalVar(&Dst), /*Volatile=*/false,
- CGM.getContext().VoidPtrTy, Dst.getLocation());
- Address Arg = Address(ArgVal, VDAddr.getAlignment());
- Arg = CtorCGF.Builder.CreateElementBitCast(
- Arg, CtorCGF.ConvertTypeForMem(ASTTy));
- CtorCGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(),
- /*IsInitializer=*/true);
- ArgVal = CtorCGF.EmitLoadOfScalar(
- CtorCGF.GetAddrOfLocalVar(&Dst), /*Volatile=*/false,
- CGM.getContext().VoidPtrTy, Dst.getLocation());
- CtorCGF.Builder.CreateStore(ArgVal, CtorCGF.ReturnValue);
- CtorCGF.FinishFunction();
- Ctor = Fn;
- }
- if (VD->getType().isDestructedType() != QualType::DK_none) {
- // Generate function that emits destructor call for the threadprivate copy
- // of the variable VD
- CodeGenFunction DtorCGF(CGM);
- FunctionArgList Args;
- ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, CGM.getContext().VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.push_back(&Dst);
-
- const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
- CGM.getContext().VoidTy, Args);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- std::string Name = getName({"__kmpc_global_dtor_", ""});
- llvm::Function *Fn =
- CGM.CreateGlobalInitOrDestructFunction(FTy, Name, FI, Loc);
- auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
- DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args,
- Loc, Loc);
- // Create a scope with an artificial location for the body of this function.
- auto AL = ApplyDebugLocation::CreateArtificial(DtorCGF);
- llvm::Value *ArgVal = DtorCGF.EmitLoadOfScalar(
- DtorCGF.GetAddrOfLocalVar(&Dst),
- /*Volatile=*/false, CGM.getContext().VoidPtrTy, Dst.getLocation());
- DtorCGF.emitDestroy(Address(ArgVal, VDAddr.getAlignment()), ASTTy,
- DtorCGF.getDestroyer(ASTTy.isDestructedType()),
- DtorCGF.needsEHCleanup(ASTTy.isDestructedType()));
- DtorCGF.FinishFunction();
- Dtor = Fn;
- }
- // Do not emit init function if it is not required.
- if (!Ctor && !Dtor)
- return nullptr;
-
- llvm::Type *CopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
- auto *CopyCtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CopyCtorTyArgs,
- /*isVarArg=*/false)
- ->getPointerTo();
- // Copying constructor for the threadprivate variable.
- // Must be NULL - reserved by runtime, but currently it requires that this
- // parameter is always NULL. Otherwise it fires assertion.
- CopyCtor = llvm::Constant::getNullValue(CopyCtorTy);
- if (Ctor == nullptr) {
- auto *CtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy,
- /*isVarArg=*/false)
- ->getPointerTo();
- Ctor = llvm::Constant::getNullValue(CtorTy);
- }
- if (Dtor == nullptr) {
- auto *DtorTy = llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy,
- /*isVarArg=*/false)
- ->getPointerTo();
- Dtor = llvm::Constant::getNullValue(DtorTy);
- }
- if (!CGF) {
- auto *InitFunctionTy =
- llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
- std::string Name = getName({"__omp_threadprivate_init_", ""});
- llvm::Function *InitFunction = CGM.CreateGlobalInitOrDestructFunction(
- InitFunctionTy, Name, CGM.getTypes().arrangeNullaryFunction());
- CodeGenFunction InitCGF(CGM);
- FunctionArgList ArgList;
- InitCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, InitFunction,
- CGM.getTypes().arrangeNullaryFunction(), ArgList,
- Loc, Loc);
- emitThreadPrivateVarInit(InitCGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
- InitCGF.FinishFunction();
- return InitFunction;
- }
- emitThreadPrivateVarInit(*CGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
- }
- return nullptr;
-}
-
-/// Obtain information that uniquely identifies a target entry. This
-/// consists of the file and device IDs as well as line number associated with
-/// the relevant entry source location.
-static void getTargetEntryUniqueInfo(ASTContext &C, SourceLocation Loc,
- unsigned &DeviceID, unsigned &FileID,
- unsigned &LineNum) {
- SourceManager &SM = C.getSourceManager();
-
- // The loc should be always valid and have a file ID (the user cannot use
- // #pragma directives in macros)
-
- assert(Loc.isValid() && "Source location is expected to be always valid.");
-
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
- assert(PLoc.isValid() && "Source location is expected to be always valid.");
-
- llvm::sys::fs::UniqueID ID;
- if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID))
- SM.getDiagnostics().Report(diag::err_cannot_open_file)
- << PLoc.getFilename() << EC.message();
-
- DeviceID = ID.getDevice();
- FileID = ID.getFile();
- LineNum = PLoc.getLine();
-}
-
-bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
- llvm::GlobalVariable *Addr,
- bool PerformInit) {
- Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link)
- return CGM.getLangOpts().OpenMPIsDevice;
- VD = VD->getDefinition(CGM.getContext());
- if (VD && !DeclareTargetWithDefinition.insert(CGM.getMangledName(VD)).second)
- return CGM.getLangOpts().OpenMPIsDevice;
-
- QualType ASTTy = VD->getType();
-
- SourceLocation Loc = VD->getCanonicalDecl()->getBeginLoc();
- // Produce the unique prefix to identify the new target regions. We use
- // the source location of the variable declaration which we know to not
- // conflict with any target region.
- unsigned DeviceID;
- unsigned FileID;
- unsigned Line;
- getTargetEntryUniqueInfo(CGM.getContext(), Loc, DeviceID, FileID, Line);
- SmallString<128> Buffer, Out;
- {
- llvm::raw_svector_ostream OS(Buffer);
- OS << "__omp_offloading_" << llvm::format("_%x", DeviceID)
- << llvm::format("_%x_", FileID) << VD->getName() << "_l" << Line;
- }
-
- const Expr *Init = VD->getAnyInitializer();
- if (CGM.getLangOpts().CPlusPlus && PerformInit) {
- llvm::Constant *Ctor;
- llvm::Constant *ID;
- if (CGM.getLangOpts().OpenMPIsDevice) {
- // Generate function that re-emits the declaration's initializer into
- // the threadprivate copy of the variable VD
- CodeGenFunction CtorCGF(CGM);
-
- const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *Fn = CGM.CreateGlobalInitOrDestructFunction(
- FTy, Twine(Buffer, "_ctor"), FI, Loc);
- auto NL = ApplyDebugLocation::CreateEmpty(CtorCGF);
- CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI,
- FunctionArgList(), Loc, Loc);
- auto AL = ApplyDebugLocation::CreateArtificial(CtorCGF);
- CtorCGF.EmitAnyExprToMem(Init,
- Address(Addr, CGM.getContext().getDeclAlign(VD)),
- Init->getType().getQualifiers(),
- /*IsInitializer=*/true);
- CtorCGF.FinishFunction();
- Ctor = Fn;
- ID = llvm::ConstantExpr::getBitCast(Fn, CGM.Int8PtrTy);
- CGM.addUsedGlobal(cast<llvm::GlobalValue>(Ctor));
- } else {
- Ctor = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage,
- llvm::Constant::getNullValue(CGM.Int8Ty), Twine(Buffer, "_ctor"));
- ID = Ctor;
- }
-
- // Register the information for the entry associated with the constructor.
- Out.clear();
- OffloadEntriesInfoManager.registerTargetRegionEntryInfo(
- DeviceID, FileID, Twine(Buffer, "_ctor").toStringRef(Out), Line, Ctor,
- ID, OffloadEntriesInfoManagerTy::OMPTargetRegionEntryCtor);
- }
- if (VD->getType().isDestructedType() != QualType::DK_none) {
- llvm::Constant *Dtor;
- llvm::Constant *ID;
- if (CGM.getLangOpts().OpenMPIsDevice) {
- // Generate function that emits destructor call for the threadprivate
- // copy of the variable VD
- CodeGenFunction DtorCGF(CGM);
-
- const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *Fn = CGM.CreateGlobalInitOrDestructFunction(
- FTy, Twine(Buffer, "_dtor"), FI, Loc);
- auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
- DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI,
- FunctionArgList(), Loc, Loc);
- // Create a scope with an artificial location for the body of this
- // function.
- auto AL = ApplyDebugLocation::CreateArtificial(DtorCGF);
- DtorCGF.emitDestroy(Address(Addr, CGM.getContext().getDeclAlign(VD)),
- ASTTy, DtorCGF.getDestroyer(ASTTy.isDestructedType()),
- DtorCGF.needsEHCleanup(ASTTy.isDestructedType()));
- DtorCGF.FinishFunction();
- Dtor = Fn;
- ID = llvm::ConstantExpr::getBitCast(Fn, CGM.Int8PtrTy);
- CGM.addUsedGlobal(cast<llvm::GlobalValue>(Dtor));
- } else {
- Dtor = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage,
- llvm::Constant::getNullValue(CGM.Int8Ty), Twine(Buffer, "_dtor"));
- ID = Dtor;
- }
- // Register the information for the entry associated with the destructor.
- Out.clear();
- OffloadEntriesInfoManager.registerTargetRegionEntryInfo(
- DeviceID, FileID, Twine(Buffer, "_dtor").toStringRef(Out), Line, Dtor,
- ID, OffloadEntriesInfoManagerTy::OMPTargetRegionEntryDtor);
- }
- return CGM.getLangOpts().OpenMPIsDevice;
-}
-
-Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
- QualType VarType,
- StringRef Name) {
- std::string Suffix = getName({"artificial", ""});
- std::string CacheSuffix = getName({"cache", ""});
- llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
- llvm::Value *GAddr =
- getOrCreateInternalVariable(VarLVType, Twine(Name).concat(Suffix));
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, SourceLocation()),
- getThreadID(CGF, SourceLocation()),
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(GAddr, CGM.VoidPtrTy),
- CGF.Builder.CreateIntCast(CGF.getTypeSize(VarType), CGM.SizeTy,
- /*IsSigned=*/false),
- getOrCreateInternalVariable(
- CGM.VoidPtrPtrTy, Twine(Name).concat(Suffix).concat(CacheSuffix))};
- return Address(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args),
- VarLVType->getPointerTo(/*AddrSpace=*/0)),
- CGM.getPointerAlign());
-}
-
-void CGOpenMPRuntime::emitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond,
- const RegionCodeGenTy &ThenGen,
- const RegionCodeGenTy &ElseGen) {
- CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange());
-
- // If the condition constant folds and can be elided, try to avoid emitting
- // the condition and the dead arm of the if/else.
- bool CondConstant;
- if (CGF.ConstantFoldsToSimpleInteger(Cond, CondConstant)) {
- if (CondConstant)
- ThenGen(CGF);
- else
- ElseGen(CGF);
- return;
- }
-
- // Otherwise, the condition did not fold, or we couldn't elide it. Just
- // emit the conditional branch.
- llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("omp_if.then");
- llvm::BasicBlock *ElseBlock = CGF.createBasicBlock("omp_if.else");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("omp_if.end");
- CGF.EmitBranchOnBoolExpr(Cond, ThenBlock, ElseBlock, /*TrueCount=*/0);
-
- // Emit the 'then' code.
- CGF.EmitBlock(ThenBlock);
- ThenGen(CGF);
- CGF.EmitBranch(ContBlock);
- // Emit the 'else' code if present.
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(ElseBlock);
- ElseGen(CGF);
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBranch(ContBlock);
- // Emit the continuation block for code after the if.
- CGF.EmitBlock(ContBlock, /*IsFinished=*/true);
-}
-
-void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars,
- const Expr *IfCond) {
- if (!CGF.HaveInsertPoint())
- return;
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- auto &&ThenGen = [OutlinedFn, CapturedVars, RTLoc](CodeGenFunction &CGF,
- PrePostActionTy &) {
- // Build call __kmpc_fork_call(loc, n, microtask, var1, .., varn);
- CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
- llvm::Value *Args[] = {
- RTLoc,
- CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
- CGF.Builder.CreateBitCast(OutlinedFn, RT.getKmpc_MicroPointerTy())};
- llvm::SmallVector<llvm::Value *, 16> RealArgs;
- RealArgs.append(std::begin(Args), std::end(Args));
- RealArgs.append(CapturedVars.begin(), CapturedVars.end());
-
- llvm::Value *RTLFn = RT.createRuntimeFunction(OMPRTL__kmpc_fork_call);
- CGF.EmitRuntimeCall(RTLFn, RealArgs);
- };
- auto &&ElseGen = [OutlinedFn, CapturedVars, RTLoc, Loc](CodeGenFunction &CGF,
- PrePostActionTy &) {
- CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
- llvm::Value *ThreadID = RT.getThreadID(CGF, Loc);
- // Build calls:
- // __kmpc_serialized_parallel(&Loc, GTid);
- llvm::Value *Args[] = {RTLoc, ThreadID};
- CGF.EmitRuntimeCall(
- RT.createRuntimeFunction(OMPRTL__kmpc_serialized_parallel), Args);
-
- // OutlinedFn(&GTid, &zero, CapturedStruct);
- Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
- /*Name*/ ".zero.addr");
- CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
- llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
- // ThreadId for serialized parallels is 0.
- OutlinedFnArgs.push_back(ZeroAddr.getPointer());
- OutlinedFnArgs.push_back(ZeroAddr.getPointer());
- OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
-
- // __kmpc_end_serialized_parallel(&Loc, GTid);
- llvm::Value *EndArgs[] = {RT.emitUpdateLocation(CGF, Loc), ThreadID};
- CGF.EmitRuntimeCall(
- RT.createRuntimeFunction(OMPRTL__kmpc_end_serialized_parallel),
- EndArgs);
- };
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, ThenGen, ElseGen);
- } else {
- RegionCodeGenTy ThenRCG(ThenGen);
- ThenRCG(CGF);
- }
-}
-
-// If we're inside an (outlined) parallel region, use the region info's
-// thread-ID variable (it is passed in a first argument of the outlined function
-// as "kmp_int32 *gtid"). Otherwise, if we're not inside parallel region, but in
-// regular serial code region, get thread ID by calling kmp_int32
-// kmpc_global_thread_num(ident_t *loc), stash this thread ID in a temporary and
-// return the address of that temp.
-Address CGOpenMPRuntime::emitThreadIDAddress(CodeGenFunction &CGF,
- SourceLocation Loc) {
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
- if (OMPRegionInfo->getThreadIDVariable())
- return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress();
-
- llvm::Value *ThreadID = getThreadID(CGF, Loc);
- QualType Int32Ty =
- CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true);
- Address ThreadIDTemp = CGF.CreateMemTemp(Int32Ty, /*Name*/ ".threadid_temp.");
- CGF.EmitStoreOfScalar(ThreadID,
- CGF.MakeAddrLValue(ThreadIDTemp, Int32Ty));
-
- return ThreadIDTemp;
-}
-
-llvm::Constant *
-CGOpenMPRuntime::getOrCreateInternalVariable(llvm::Type *Ty,
- const llvm::Twine &Name) {
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- Out << Name;
- StringRef RuntimeName = Out.str();
- auto &Elem = *InternalVars.try_emplace(RuntimeName, nullptr).first;
- if (Elem.second) {
- assert(Elem.second->getType()->getPointerElementType() == Ty &&
- "OMP internal variable has different type than requested");
- return &*Elem.second;
- }
-
- return Elem.second = new llvm::GlobalVariable(
- CGM.getModule(), Ty, /*IsConstant*/ false,
- llvm::GlobalValue::CommonLinkage, llvm::Constant::getNullValue(Ty),
- Elem.first());
-}
-
-llvm::Value *CGOpenMPRuntime::getCriticalRegionLock(StringRef CriticalName) {
- std::string Prefix = Twine("gomp_critical_user_", CriticalName).str();
- std::string Name = getName({Prefix, "var"});
- return getOrCreateInternalVariable(KmpCriticalNameTy, Name);
-}
-
-namespace {
-/// Common pre(post)-action for different OpenMP constructs.
-class CommonActionTy final : public PrePostActionTy {
- llvm::Value *EnterCallee;
- ArrayRef<llvm::Value *> EnterArgs;
- llvm::Value *ExitCallee;
- ArrayRef<llvm::Value *> ExitArgs;
- bool Conditional;
- llvm::BasicBlock *ContBlock = nullptr;
-
-public:
- CommonActionTy(llvm::Value *EnterCallee, ArrayRef<llvm::Value *> EnterArgs,
- llvm::Value *ExitCallee, ArrayRef<llvm::Value *> ExitArgs,
- bool Conditional = false)
- : EnterCallee(EnterCallee), EnterArgs(EnterArgs), ExitCallee(ExitCallee),
- ExitArgs(ExitArgs), Conditional(Conditional) {}
- void Enter(CodeGenFunction &CGF) override {
- llvm::Value *EnterRes = CGF.EmitRuntimeCall(EnterCallee, EnterArgs);
- if (Conditional) {
- llvm::Value *CallBool = CGF.Builder.CreateIsNotNull(EnterRes);
- auto *ThenBlock = CGF.createBasicBlock("omp_if.then");
- ContBlock = CGF.createBasicBlock("omp_if.end");
- // Generate the branch (If-stmt)
- CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
- CGF.EmitBlock(ThenBlock);
- }
- }
- void Done(CodeGenFunction &CGF) {
- // Emit the rest of blocks/branches
- CGF.EmitBranch(ContBlock);
- CGF.EmitBlock(ContBlock, true);
- }
- void Exit(CodeGenFunction &CGF) override {
- CGF.EmitRuntimeCall(ExitCallee, ExitArgs);
- }
-};
-} // anonymous namespace
-
-void CGOpenMPRuntime::emitCriticalRegion(CodeGenFunction &CGF,
- StringRef CriticalName,
- const RegionCodeGenTy &CriticalOpGen,
- SourceLocation Loc, const Expr *Hint) {
- // __kmpc_critical[_with_hint](ident_t *, gtid, Lock[, hint]);
- // CriticalOpGen();
- // __kmpc_end_critical(ident_t *, gtid, Lock);
- // Prepare arguments and build a call to __kmpc_critical
- if (!CGF.HaveInsertPoint())
- return;
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- getCriticalRegionLock(CriticalName)};
- llvm::SmallVector<llvm::Value *, 4> EnterArgs(std::begin(Args),
- std::end(Args));
- if (Hint) {
- EnterArgs.push_back(CGF.Builder.CreateIntCast(
- CGF.EmitScalarExpr(Hint), CGM.IntPtrTy, /*isSigned=*/false));
- }
- CommonActionTy Action(
- createRuntimeFunction(Hint ? OMPRTL__kmpc_critical_with_hint
- : OMPRTL__kmpc_critical),
- EnterArgs, createRuntimeFunction(OMPRTL__kmpc_end_critical), Args);
- CriticalOpGen.setAction(Action);
- emitInlinedDirective(CGF, OMPD_critical, CriticalOpGen);
-}
-
-void CGOpenMPRuntime::emitMasterRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &MasterOpGen,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
- // if(__kmpc_master(ident_t *, gtid)) {
- // MasterOpGen();
- // __kmpc_end_master(ident_t *, gtid);
- // }
- // Prepare arguments and build a call to __kmpc_master
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
- CommonActionTy Action(createRuntimeFunction(OMPRTL__kmpc_master), Args,
- createRuntimeFunction(OMPRTL__kmpc_end_master), Args,
- /*Conditional=*/true);
- MasterOpGen.setAction(Action);
- emitInlinedDirective(CGF, OMPD_master, MasterOpGen);
- Action.Done(CGF);
-}
-
-void CGOpenMPRuntime::emitTaskyieldCall(CodeGenFunction &CGF,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
- // Build call __kmpc_omp_taskyield(loc, thread_id, 0);
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- llvm::ConstantInt::get(CGM.IntTy, /*V=*/0, /*isSigned=*/true)};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_taskyield), Args);
- if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
- Region->emitUntiedSwitch(CGF);
-}
-
-void CGOpenMPRuntime::emitTaskgroupRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &TaskgroupOpGen,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
- // __kmpc_taskgroup(ident_t *, gtid);
- // TaskgroupOpGen();
- // __kmpc_end_taskgroup(ident_t *, gtid);
- // Prepare arguments and build a call to __kmpc_taskgroup
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
- CommonActionTy Action(createRuntimeFunction(OMPRTL__kmpc_taskgroup), Args,
- createRuntimeFunction(OMPRTL__kmpc_end_taskgroup),
- Args);
- TaskgroupOpGen.setAction(Action);
- emitInlinedDirective(CGF, OMPD_taskgroup, TaskgroupOpGen);
-}
-
-/// Given an array of pointers to variables, project the address of a
-/// given variable.
-static Address emitAddrOfVarFromArray(CodeGenFunction &CGF, Address Array,
- unsigned Index, const VarDecl *Var) {
- // Pull out the pointer to the variable.
- Address PtrAddr =
- CGF.Builder.CreateConstArrayGEP(Array, Index, CGF.getPointerSize());
- llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr);
-
- Address Addr = Address(Ptr, CGF.getContext().getDeclAlign(Var));
- Addr = CGF.Builder.CreateElementBitCast(
- Addr, CGF.ConvertTypeForMem(Var->getType()));
- return Addr;
-}
-
-static llvm::Value *emitCopyprivateCopyFunction(
- CodeGenModule &CGM, llvm::Type *ArgsType,
- ArrayRef<const Expr *> CopyprivateVars, ArrayRef<const Expr *> DestExprs,
- ArrayRef<const Expr *> SrcExprs, ArrayRef<const Expr *> AssignmentOps,
- SourceLocation Loc) {
- ASTContext &C = CGM.getContext();
- // void copy_func(void *LHSArg, void *RHSArg);
- FunctionArgList Args;
- ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
- ImplicitParamDecl::Other);
- ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.push_back(&LHSArg);
- Args.push_back(&RHSArg);
- const auto &CGFI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- std::string Name =
- CGM.getOpenMPRuntime().getName({"omp", "copyprivate", "copy_func"});
- auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
- llvm::GlobalValue::InternalLinkage, Name,
- &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
- Fn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
- // Dest = (void*[n])(LHSArg);
- // Src = (void*[n])(RHSArg);
- Address LHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&LHSArg)),
- ArgsType), CGF.getPointerAlign());
- Address RHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&RHSArg)),
- ArgsType), CGF.getPointerAlign());
- // *(Type0*)Dst[0] = *(Type0*)Src[0];
- // *(Type1*)Dst[1] = *(Type1*)Src[1];
- // ...
- // *(Typen*)Dst[n] = *(Typen*)Src[n];
- for (unsigned I = 0, E = AssignmentOps.size(); I < E; ++I) {
- const auto *DestVar =
- cast<VarDecl>(cast<DeclRefExpr>(DestExprs[I])->getDecl());
- Address DestAddr = emitAddrOfVarFromArray(CGF, LHS, I, DestVar);
-
- const auto *SrcVar =
- cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl());
- Address SrcAddr = emitAddrOfVarFromArray(CGF, RHS, I, SrcVar);
-
- const auto *VD = cast<DeclRefExpr>(CopyprivateVars[I])->getDecl();
- QualType Type = VD->getType();
- CGF.EmitOMPCopy(Type, DestAddr, SrcAddr, DestVar, SrcVar, AssignmentOps[I]);
- }
- CGF.FinishFunction();
- return Fn;
-}
-
-void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &SingleOpGen,
- SourceLocation Loc,
- ArrayRef<const Expr *> CopyprivateVars,
- ArrayRef<const Expr *> SrcExprs,
- ArrayRef<const Expr *> DstExprs,
- ArrayRef<const Expr *> AssignmentOps) {
- if (!CGF.HaveInsertPoint())
- return;
- assert(CopyprivateVars.size() == SrcExprs.size() &&
- CopyprivateVars.size() == DstExprs.size() &&
- CopyprivateVars.size() == AssignmentOps.size());
- ASTContext &C = CGM.getContext();
- // int32 did_it = 0;
- // if(__kmpc_single(ident_t *, gtid)) {
- // SingleOpGen();
- // __kmpc_end_single(ident_t *, gtid);
- // did_it = 1;
- // }
- // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
- // <copy_func>, did_it);
-
- Address DidIt = Address::invalid();
- if (!CopyprivateVars.empty()) {
- // int32 did_it = 0;
- QualType KmpInt32Ty =
- C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
- DidIt = CGF.CreateMemTemp(KmpInt32Ty, ".omp.copyprivate.did_it");
- CGF.Builder.CreateStore(CGF.Builder.getInt32(0), DidIt);
- }
- // Prepare arguments and build a call to __kmpc_single
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
- CommonActionTy Action(createRuntimeFunction(OMPRTL__kmpc_single), Args,
- createRuntimeFunction(OMPRTL__kmpc_end_single), Args,
- /*Conditional=*/true);
- SingleOpGen.setAction(Action);
- emitInlinedDirective(CGF, OMPD_single, SingleOpGen);
- if (DidIt.isValid()) {
- // did_it = 1;
- CGF.Builder.CreateStore(CGF.Builder.getInt32(1), DidIt);
- }
- Action.Done(CGF);
- // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
- // <copy_func>, did_it);
- if (DidIt.isValid()) {
- llvm::APInt ArraySize(/*unsigned int numBits=*/32, CopyprivateVars.size());
- QualType CopyprivateArrayTy =
- C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- // Create a list of all private variables for copyprivate.
- Address CopyprivateList =
- CGF.CreateMemTemp(CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
- for (unsigned I = 0, E = CopyprivateVars.size(); I < E; ++I) {
- Address Elem = CGF.Builder.CreateConstArrayGEP(
- CopyprivateList, I, CGF.getPointerSize());
- CGF.Builder.CreateStore(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLValue(CopyprivateVars[I]).getPointer(), CGF.VoidPtrTy),
- Elem);
- }
- // Build function that copies private values from single region to all other
- // threads in the corresponding parallel region.
- llvm::Value *CpyFn = emitCopyprivateCopyFunction(
- CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy)->getPointerTo(),
- CopyprivateVars, SrcExprs, DstExprs, AssignmentOps, Loc);
- llvm::Value *BufSize = CGF.getTypeSize(CopyprivateArrayTy);
- Address CL =
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(CopyprivateList,
- CGF.VoidPtrTy);
- llvm::Value *DidItVal = CGF.Builder.CreateLoad(DidIt);
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc), // ident_t *<loc>
- getThreadID(CGF, Loc), // i32 <gtid>
- BufSize, // size_t <buf_size>
- CL.getPointer(), // void *<copyprivate list>
- CpyFn, // void (*) (void *, void *) <copy_func>
- DidItVal // i32 did_it
- };
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_copyprivate), Args);
- }
-}
-
-void CGOpenMPRuntime::emitOrderedRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &OrderedOpGen,
- SourceLocation Loc, bool IsThreads) {
- if (!CGF.HaveInsertPoint())
- return;
- // __kmpc_ordered(ident_t *, gtid);
- // OrderedOpGen();
- // __kmpc_end_ordered(ident_t *, gtid);
- // Prepare arguments and build a call to __kmpc_ordered
- if (IsThreads) {
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
- CommonActionTy Action(createRuntimeFunction(OMPRTL__kmpc_ordered), Args,
- createRuntimeFunction(OMPRTL__kmpc_end_ordered),
- Args);
- OrderedOpGen.setAction(Action);
- emitInlinedDirective(CGF, OMPD_ordered, OrderedOpGen);
- return;
- }
- emitInlinedDirective(CGF, OMPD_ordered, OrderedOpGen);
-}
-
-unsigned CGOpenMPRuntime::getDefaultFlagsForBarriers(OpenMPDirectiveKind Kind) {
- unsigned Flags;
- if (Kind == OMPD_for)
- Flags = OMP_IDENT_BARRIER_IMPL_FOR;
- else if (Kind == OMPD_sections)
- Flags = OMP_IDENT_BARRIER_IMPL_SECTIONS;
- else if (Kind == OMPD_single)
- Flags = OMP_IDENT_BARRIER_IMPL_SINGLE;
- else if (Kind == OMPD_barrier)
- Flags = OMP_IDENT_BARRIER_EXPL;
- else
- Flags = OMP_IDENT_BARRIER_IMPL;
- return Flags;
-}
-
-void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind Kind, bool EmitChecks,
- bool ForceSimpleCall) {
- if (!CGF.HaveInsertPoint())
- return;
- // Build call __kmpc_cancel_barrier(loc, thread_id);
- // Build call __kmpc_barrier(loc, thread_id);
- unsigned Flags = getDefaultFlagsForBarriers(Kind);
- // Build call __kmpc_cancel_barrier(loc, thread_id) or __kmpc_barrier(loc,
- // thread_id);
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
- getThreadID(CGF, Loc)};
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- if (!ForceSimpleCall && OMPRegionInfo->hasCancel()) {
- llvm::Value *Result = CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_cancel_barrier), Args);
- if (EmitChecks) {
- // if (__kmpc_cancel_barrier()) {
- // exit from construct;
- // }
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
- llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
- llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
- CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
- CGF.EmitBlock(ExitBB);
- // exit from construct;
- CodeGenFunction::JumpDest CancelDestination =
- CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
- CGF.EmitBranchThroughCleanup(CancelDestination);
- CGF.EmitBlock(ContBB, /*IsFinished=*/true);
- }
- return;
- }
- }
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_barrier), Args);
-}
-
-/// Map the OpenMP loop schedule to the runtime enumeration.
-static OpenMPSchedType getRuntimeSchedule(OpenMPScheduleClauseKind ScheduleKind,
- bool Chunked, bool Ordered) {
- switch (ScheduleKind) {
- case OMPC_SCHEDULE_static:
- return Chunked ? (Ordered ? OMP_ord_static_chunked : OMP_sch_static_chunked)
- : (Ordered ? OMP_ord_static : OMP_sch_static);
- case OMPC_SCHEDULE_dynamic:
- return Ordered ? OMP_ord_dynamic_chunked : OMP_sch_dynamic_chunked;
- case OMPC_SCHEDULE_guided:
- return Ordered ? OMP_ord_guided_chunked : OMP_sch_guided_chunked;
- case OMPC_SCHEDULE_runtime:
- return Ordered ? OMP_ord_runtime : OMP_sch_runtime;
- case OMPC_SCHEDULE_auto:
- return Ordered ? OMP_ord_auto : OMP_sch_auto;
- case OMPC_SCHEDULE_unknown:
- assert(!Chunked && "chunk was specified but schedule kind not known");
- return Ordered ? OMP_ord_static : OMP_sch_static;
- }
- llvm_unreachable("Unexpected runtime schedule");
-}
-
-/// Map the OpenMP distribute schedule to the runtime enumeration.
-static OpenMPSchedType
-getRuntimeSchedule(OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) {
- // only static is allowed for dist_schedule
- return Chunked ? OMP_dist_sch_static_chunked : OMP_dist_sch_static;
-}
-
-bool CGOpenMPRuntime::isStaticNonchunked(OpenMPScheduleClauseKind ScheduleKind,
- bool Chunked) const {
- OpenMPSchedType Schedule =
- getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
- return Schedule == OMP_sch_static;
-}
-
-bool CGOpenMPRuntime::isStaticNonchunked(
- OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
- OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
- return Schedule == OMP_dist_sch_static;
-}
-
-bool CGOpenMPRuntime::isStaticChunked(OpenMPScheduleClauseKind ScheduleKind,
- bool Chunked) const {
- OpenMPSchedType Schedule =
- getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
- return Schedule == OMP_sch_static_chunked;
-}
-
-bool CGOpenMPRuntime::isStaticChunked(
- OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
- OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
- return Schedule == OMP_dist_sch_static_chunked;
-}
-
-bool CGOpenMPRuntime::isDynamic(OpenMPScheduleClauseKind ScheduleKind) const {
- OpenMPSchedType Schedule =
- getRuntimeSchedule(ScheduleKind, /*Chunked=*/false, /*Ordered=*/false);
- assert(Schedule != OMP_sch_static_chunked && "cannot be chunked here");
- return Schedule != OMP_sch_static;
-}
-
-static int addMonoNonMonoModifier(OpenMPSchedType Schedule,
- OpenMPScheduleClauseModifier M1,
- OpenMPScheduleClauseModifier M2) {
- int Modifier = 0;
- switch (M1) {
- case OMPC_SCHEDULE_MODIFIER_monotonic:
- Modifier = OMP_sch_modifier_monotonic;
- break;
- case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
- Modifier = OMP_sch_modifier_nonmonotonic;
- break;
- case OMPC_SCHEDULE_MODIFIER_simd:
- if (Schedule == OMP_sch_static_chunked)
- Schedule = OMP_sch_static_balanced_chunked;
- break;
- case OMPC_SCHEDULE_MODIFIER_last:
- case OMPC_SCHEDULE_MODIFIER_unknown:
- break;
- }
- switch (M2) {
- case OMPC_SCHEDULE_MODIFIER_monotonic:
- Modifier = OMP_sch_modifier_monotonic;
- break;
- case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
- Modifier = OMP_sch_modifier_nonmonotonic;
- break;
- case OMPC_SCHEDULE_MODIFIER_simd:
- if (Schedule == OMP_sch_static_chunked)
- Schedule = OMP_sch_static_balanced_chunked;
- break;
- case OMPC_SCHEDULE_MODIFIER_last:
- case OMPC_SCHEDULE_MODIFIER_unknown:
- break;
- }
- return Schedule | Modifier;
-}
-
-void CGOpenMPRuntime::emitForDispatchInit(
- CodeGenFunction &CGF, SourceLocation Loc,
- const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
- bool Ordered, const DispatchRTInput &DispatchValues) {
- if (!CGF.HaveInsertPoint())
- return;
- OpenMPSchedType Schedule = getRuntimeSchedule(
- ScheduleKind.Schedule, DispatchValues.Chunk != nullptr, Ordered);
- assert(Ordered ||
- (Schedule != OMP_sch_static && Schedule != OMP_sch_static_chunked &&
- Schedule != OMP_ord_static && Schedule != OMP_ord_static_chunked &&
- Schedule != OMP_sch_static_balanced_chunked));
- // Call __kmpc_dispatch_init(
- // ident_t *loc, kmp_int32 tid, kmp_int32 schedule,
- // kmp_int[32|64] lower, kmp_int[32|64] upper,
- // kmp_int[32|64] stride, kmp_int[32|64] chunk);
-
- // If the Chunk was not specified in the clause - use default value 1.
- llvm::Value *Chunk = DispatchValues.Chunk ? DispatchValues.Chunk
- : CGF.Builder.getIntN(IVSize, 1);
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- CGF.Builder.getInt32(addMonoNonMonoModifier(
- Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
- DispatchValues.LB, // Lower
- DispatchValues.UB, // Upper
- CGF.Builder.getIntN(IVSize, 1), // Stride
- Chunk // Chunk
- };
- CGF.EmitRuntimeCall(createDispatchInitFunction(IVSize, IVSigned), Args);
-}
-
-static void emitForStaticInitCall(
- CodeGenFunction &CGF, llvm::Value *UpdateLocation, llvm::Value *ThreadId,
- llvm::Constant *ForStaticInitFunction, OpenMPSchedType Schedule,
- OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2,
- const CGOpenMPRuntime::StaticRTInput &Values) {
- if (!CGF.HaveInsertPoint())
- return;
-
- assert(!Values.Ordered);
- assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked ||
- Schedule == OMP_sch_static_balanced_chunked ||
- Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked ||
- Schedule == OMP_dist_sch_static ||
- Schedule == OMP_dist_sch_static_chunked);
-
- // Call __kmpc_for_static_init(
- // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
- // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
- // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
- // kmp_int[32|64] incr, kmp_int[32|64] chunk);
- llvm::Value *Chunk = Values.Chunk;
- if (Chunk == nullptr) {
- assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static ||
- Schedule == OMP_dist_sch_static) &&
- "expected static non-chunked schedule");
- // If the Chunk was not specified in the clause - use default value 1.
- Chunk = CGF.Builder.getIntN(Values.IVSize, 1);
- } else {
- assert((Schedule == OMP_sch_static_chunked ||
- Schedule == OMP_sch_static_balanced_chunked ||
- Schedule == OMP_ord_static_chunked ||
- Schedule == OMP_dist_sch_static_chunked) &&
- "expected static chunked schedule");
- }
- llvm::Value *Args[] = {
- UpdateLocation,
- ThreadId,
- CGF.Builder.getInt32(addMonoNonMonoModifier(Schedule, M1,
- M2)), // Schedule type
- Values.IL.getPointer(), // &isLastIter
- Values.LB.getPointer(), // &LB
- Values.UB.getPointer(), // &UB
- Values.ST.getPointer(), // &Stride
- CGF.Builder.getIntN(Values.IVSize, 1), // Incr
- Chunk // Chunk
- };
- CGF.EmitRuntimeCall(ForStaticInitFunction, Args);
-}
-
-void CGOpenMPRuntime::emitForStaticInit(CodeGenFunction &CGF,
- SourceLocation Loc,
- OpenMPDirectiveKind DKind,
- const OpenMPScheduleTy &ScheduleKind,
- const StaticRTInput &Values) {
- OpenMPSchedType ScheduleNum = getRuntimeSchedule(
- ScheduleKind.Schedule, Values.Chunk != nullptr, Values.Ordered);
- assert(isOpenMPWorksharingDirective(DKind) &&
- "Expected loop-based or sections-based directive.");
- llvm::Value *UpdatedLocation = emitUpdateLocation(CGF, Loc,
- isOpenMPLoopDirective(DKind)
- ? OMP_IDENT_WORK_LOOP
- : OMP_IDENT_WORK_SECTIONS);
- llvm::Value *ThreadId = getThreadID(CGF, Loc);
- llvm::Constant *StaticInitFunction =
- createForStaticInitFunction(Values.IVSize, Values.IVSigned);
- emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
- ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, Values);
-}
-
-void CGOpenMPRuntime::emitDistributeStaticInit(
- CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDistScheduleClauseKind SchedKind,
- const CGOpenMPRuntime::StaticRTInput &Values) {
- OpenMPSchedType ScheduleNum =
- getRuntimeSchedule(SchedKind, Values.Chunk != nullptr);
- llvm::Value *UpdatedLocation =
- emitUpdateLocation(CGF, Loc, OMP_IDENT_WORK_DISTRIBUTE);
- llvm::Value *ThreadId = getThreadID(CGF, Loc);
- llvm::Constant *StaticInitFunction =
- createForStaticInitFunction(Values.IVSize, Values.IVSigned);
- emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
- ScheduleNum, OMPC_SCHEDULE_MODIFIER_unknown,
- OMPC_SCHEDULE_MODIFIER_unknown, Values);
-}
-
-void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF,
- SourceLocation Loc,
- OpenMPDirectiveKind DKind) {
- if (!CGF.HaveInsertPoint())
- return;
- // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc,
- isOpenMPDistributeDirective(DKind)
- ? OMP_IDENT_WORK_DISTRIBUTE
- : isOpenMPLoopDirective(DKind)
- ? OMP_IDENT_WORK_LOOP
- : OMP_IDENT_WORK_SECTIONS),
- getThreadID(CGF, Loc)};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_for_static_fini),
- Args);
-}
-
-void CGOpenMPRuntime::emitForOrderedIterationEnd(CodeGenFunction &CGF,
- SourceLocation Loc,
- unsigned IVSize,
- bool IVSigned) {
- if (!CGF.HaveInsertPoint())
- return;
- // Call __kmpc_for_dynamic_fini_(4|8)[u](ident_t *loc, kmp_int32 tid);
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
- CGF.EmitRuntimeCall(createDispatchFiniFunction(IVSize, IVSigned), Args);
-}
-
-llvm::Value *CGOpenMPRuntime::emitForNext(CodeGenFunction &CGF,
- SourceLocation Loc, unsigned IVSize,
- bool IVSigned, Address IL,
- Address LB, Address UB,
- Address ST) {
- // Call __kmpc_dispatch_next(
- // ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
- // kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
- // kmp_int[32|64] *p_stride);
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc),
- getThreadID(CGF, Loc),
- IL.getPointer(), // &isLastIter
- LB.getPointer(), // &Lower
- UB.getPointer(), // &Upper
- ST.getPointer() // &Stride
- };
- llvm::Value *Call =
- CGF.EmitRuntimeCall(createDispatchNextFunction(IVSize, IVSigned), Args);
- return CGF.EmitScalarConversion(
- Call, CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/1),
- CGF.getContext().BoolTy, Loc);
-}
-
-void CGOpenMPRuntime::emitNumThreadsClause(CodeGenFunction &CGF,
- llvm::Value *NumThreads,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
- // Build call __kmpc_push_num_threads(&loc, global_tid, num_threads)
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- CGF.Builder.CreateIntCast(NumThreads, CGF.Int32Ty, /*isSigned*/ true)};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_push_num_threads),
- Args);
-}
-
-void CGOpenMPRuntime::emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
- // Constants for proc bind value accepted by the runtime.
- enum ProcBindTy {
- ProcBindFalse = 0,
- ProcBindTrue,
- ProcBindMaster,
- ProcBindClose,
- ProcBindSpread,
- ProcBindIntel,
- ProcBindDefault
- } RuntimeProcBind;
- switch (ProcBind) {
- case OMPC_PROC_BIND_master:
- RuntimeProcBind = ProcBindMaster;
- break;
- case OMPC_PROC_BIND_close:
- RuntimeProcBind = ProcBindClose;
- break;
- case OMPC_PROC_BIND_spread:
- RuntimeProcBind = ProcBindSpread;
- break;
- case OMPC_PROC_BIND_unknown:
- llvm_unreachable("Unsupported proc_bind value.");
- }
- // Build call __kmpc_push_proc_bind(&loc, global_tid, proc_bind)
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- llvm::ConstantInt::get(CGM.IntTy, RuntimeProcBind, /*isSigned=*/true)};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_push_proc_bind), Args);
-}
-
-void CGOpenMPRuntime::emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *>,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
- // Build call void __kmpc_flush(ident_t *loc)
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_flush),
- emitUpdateLocation(CGF, Loc));
-}
-
-namespace {
-/// Indexes of fields for type kmp_task_t.
-enum KmpTaskTFields {
- /// List of shared variables.
- KmpTaskTShareds,
- /// Task routine.
- KmpTaskTRoutine,
- /// Partition id for the untied tasks.
- KmpTaskTPartId,
- /// Function with call of destructors for private variables.
- Data1,
- /// Task priority.
- Data2,
- /// (Taskloops only) Lower bound.
- KmpTaskTLowerBound,
- /// (Taskloops only) Upper bound.
- KmpTaskTUpperBound,
- /// (Taskloops only) Stride.
- KmpTaskTStride,
- /// (Taskloops only) Is last iteration flag.
- KmpTaskTLastIter,
- /// (Taskloops only) Reduction data.
- KmpTaskTReductions,
-};
-} // anonymous namespace
-
-bool CGOpenMPRuntime::OffloadEntriesInfoManagerTy::empty() const {
- return OffloadEntriesTargetRegion.empty() &&
- OffloadEntriesDeviceGlobalVar.empty();
-}
-
-/// Initialize target region entry.
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- initializeTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- unsigned Order) {
- assert(CGM.getLangOpts().OpenMPIsDevice && "Initialization of entries is "
- "only required for the device "
- "code generation.");
- OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum] =
- OffloadEntryInfoTargetRegion(Order, /*Addr=*/nullptr, /*ID=*/nullptr,
- OMPTargetRegionEntryTargetRegion);
- ++OffloadingEntriesNum;
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- registerTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- llvm::Constant *Addr, llvm::Constant *ID,
- OMPTargetRegionEntryKind Flags) {
- // If we are emitting code for a target, the entry is already initialized,
- // only has to be registered.
- if (CGM.getLangOpts().OpenMPIsDevice) {
- if (!hasTargetRegionEntryInfo(DeviceID, FileID, ParentName, LineNum)) {
- unsigned DiagID = CGM.getDiags().getCustomDiagID(
- DiagnosticsEngine::Error,
- "Unable to find target region on line '%0' in the device code.");
- CGM.getDiags().Report(DiagID) << LineNum;
- return;
- }
- auto &Entry =
- OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum];
- assert(Entry.isValid() && "Entry not initialized!");
- Entry.setAddress(Addr);
- Entry.setID(ID);
- Entry.setFlags(Flags);
- } else {
- OffloadEntryInfoTargetRegion Entry(OffloadingEntriesNum, Addr, ID, Flags);
- OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum] = Entry;
- ++OffloadingEntriesNum;
- }
-}
-
-bool CGOpenMPRuntime::OffloadEntriesInfoManagerTy::hasTargetRegionEntryInfo(
- unsigned DeviceID, unsigned FileID, StringRef ParentName,
- unsigned LineNum) const {
- auto PerDevice = OffloadEntriesTargetRegion.find(DeviceID);
- if (PerDevice == OffloadEntriesTargetRegion.end())
- return false;
- auto PerFile = PerDevice->second.find(FileID);
- if (PerFile == PerDevice->second.end())
- return false;
- auto PerParentName = PerFile->second.find(ParentName);
- if (PerParentName == PerFile->second.end())
- return false;
- auto PerLine = PerParentName->second.find(LineNum);
- if (PerLine == PerParentName->second.end())
- return false;
- // Fail if this entry is already registered.
- if (PerLine->second.getAddress() || PerLine->second.getID())
- return false;
- return true;
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::actOnTargetRegionEntriesInfo(
- const OffloadTargetRegionEntryInfoActTy &Action) {
- // Scan all target region entries and perform the provided action.
- for (const auto &D : OffloadEntriesTargetRegion)
- for (const auto &F : D.second)
- for (const auto &P : F.second)
- for (const auto &L : P.second)
- Action(D.first, F.first, P.first(), L.first, L.second);
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- initializeDeviceGlobalVarEntryInfo(StringRef Name,
- OMPTargetGlobalVarEntryKind Flags,
- unsigned Order) {
- assert(CGM.getLangOpts().OpenMPIsDevice && "Initialization of entries is "
- "only required for the device "
- "code generation.");
- OffloadEntriesDeviceGlobalVar.try_emplace(Name, Order, Flags);
- ++OffloadingEntriesNum;
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- registerDeviceGlobalVarEntryInfo(StringRef VarName, llvm::Constant *Addr,
- CharUnits VarSize,
- OMPTargetGlobalVarEntryKind Flags,
- llvm::GlobalValue::LinkageTypes Linkage) {
- if (CGM.getLangOpts().OpenMPIsDevice) {
- auto &Entry = OffloadEntriesDeviceGlobalVar[VarName];
- assert(Entry.isValid() && Entry.getFlags() == Flags &&
- "Entry not initialized!");
- assert((!Entry.getAddress() || Entry.getAddress() == Addr) &&
- "Resetting with the new address.");
- if (Entry.getAddress() && hasDeviceGlobalVarEntryInfo(VarName))
- return;
- Entry.setAddress(Addr);
- Entry.setVarSize(VarSize);
- Entry.setLinkage(Linkage);
- } else {
- if (hasDeviceGlobalVarEntryInfo(VarName))
- return;
- OffloadEntriesDeviceGlobalVar.try_emplace(
- VarName, OffloadingEntriesNum, Addr, VarSize, Flags, Linkage);
- ++OffloadingEntriesNum;
- }
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- actOnDeviceGlobalVarEntriesInfo(
- const OffloadDeviceGlobalVarEntryInfoActTy &Action) {
- // Scan all target region entries and perform the provided action.
- for (const auto &E : OffloadEntriesDeviceGlobalVar)
- Action(E.getKey(), E.getValue());
-}
-
-llvm::Function *
-CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() {
- // If we don't have entries or if we are emitting code for the device, we
- // don't need to do anything.
- if (CGM.getLangOpts().OpenMPIsDevice || OffloadEntriesInfoManager.empty())
- return nullptr;
-
- llvm::Module &M = CGM.getModule();
- ASTContext &C = CGM.getContext();
-
- // Get list of devices we care about
- const std::vector<llvm::Triple> &Devices = CGM.getLangOpts().OMPTargetTriples;
-
- // We should be creating an offloading descriptor only if there are devices
- // specified.
- assert(!Devices.empty() && "No OpenMP offloading devices??");
-
- // Create the external variables that will point to the begin and end of the
- // host entries section. These will be defined by the linker.
- llvm::Type *OffloadEntryTy =
- CGM.getTypes().ConvertTypeForMem(getTgtOffloadEntryQTy());
- std::string EntriesBeginName = getName({"omp_offloading", "entries_begin"});
- auto *HostEntriesBegin = new llvm::GlobalVariable(
- M, OffloadEntryTy, /*isConstant=*/true,
- llvm::GlobalValue::ExternalLinkage, /*Initializer=*/nullptr,
- EntriesBeginName);
- std::string EntriesEndName = getName({"omp_offloading", "entries_end"});
- auto *HostEntriesEnd =
- new llvm::GlobalVariable(M, OffloadEntryTy, /*isConstant=*/true,
- llvm::GlobalValue::ExternalLinkage,
- /*Initializer=*/nullptr, EntriesEndName);
-
- // Create all device images
- auto *DeviceImageTy = cast<llvm::StructType>(
- CGM.getTypes().ConvertTypeForMem(getTgtDeviceImageQTy()));
- ConstantInitBuilder DeviceImagesBuilder(CGM);
- ConstantArrayBuilder DeviceImagesEntries =
- DeviceImagesBuilder.beginArray(DeviceImageTy);
-
- for (const llvm::Triple &Device : Devices) {
- StringRef T = Device.getTriple();
- std::string BeginName = getName({"omp_offloading", "img_start", ""});
- auto *ImgBegin = new llvm::GlobalVariable(
- M, CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::ExternalWeakLinkage,
- /*Initializer=*/nullptr, Twine(BeginName).concat(T));
- std::string EndName = getName({"omp_offloading", "img_end", ""});
- auto *ImgEnd = new llvm::GlobalVariable(
- M, CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::ExternalWeakLinkage,
- /*Initializer=*/nullptr, Twine(EndName).concat(T));
-
- llvm::Constant *Data[] = {ImgBegin, ImgEnd, HostEntriesBegin,
- HostEntriesEnd};
- createConstantGlobalStructAndAddToParent(CGM, getTgtDeviceImageQTy(), Data,
- DeviceImagesEntries);
- }
-
- // Create device images global array.
- std::string ImagesName = getName({"omp_offloading", "device_images"});
- llvm::GlobalVariable *DeviceImages =
- DeviceImagesEntries.finishAndCreateGlobal(ImagesName,
- CGM.getPointerAlign(),
- /*isConstant=*/true);
- DeviceImages->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- // This is a Zero array to be used in the creation of the constant expressions
- llvm::Constant *Index[] = {llvm::Constant::getNullValue(CGM.Int32Ty),
- llvm::Constant::getNullValue(CGM.Int32Ty)};
-
- // Create the target region descriptor.
- llvm::Constant *Data[] = {
- llvm::ConstantInt::get(CGM.Int32Ty, Devices.size()),
- llvm::ConstantExpr::getGetElementPtr(DeviceImages->getValueType(),
- DeviceImages, Index),
- HostEntriesBegin, HostEntriesEnd};
- std::string Descriptor = getName({"omp_offloading", "descriptor"});
- llvm::GlobalVariable *Desc = createGlobalStruct(
- CGM, getTgtBinaryDescriptorQTy(), /*IsConstant=*/true, Data, Descriptor);
-
- // Emit code to register or unregister the descriptor at execution
- // startup or closing, respectively.
-
- llvm::Function *UnRegFn;
- {
- FunctionArgList Args;
- ImplicitParamDecl DummyPtr(C, C.VoidPtrTy, ImplicitParamDecl::Other);
- Args.push_back(&DummyPtr);
-
- CodeGenFunction CGF(CGM);
- // Disable debug info for global (de-)initializer because they are not part
- // of some particular construct.
- CGF.disableDebugInfo();
- const auto &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- std::string UnregName = getName({"omp_offloading", "descriptor_unreg"});
- UnRegFn = CGM.CreateGlobalInitOrDestructFunction(FTy, UnregName, FI);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, UnRegFn, FI, Args);
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_unregister_lib),
- Desc);
- CGF.FinishFunction();
- }
- llvm::Function *RegFn;
- {
- CodeGenFunction CGF(CGM);
- // Disable debug info for global (de-)initializer because they are not part
- // of some particular construct.
- CGF.disableDebugInfo();
- const auto &FI = CGM.getTypes().arrangeNullaryFunction();
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
-
- // Encode offload target triples into the registration function name. It
- // will serve as a comdat key for the registration/unregistration code for
- // this particular combination of offloading targets.
- SmallVector<StringRef, 4U> RegFnNameParts(Devices.size() + 2U);
- RegFnNameParts[0] = "omp_offloading";
- RegFnNameParts[1] = "descriptor_reg";
- llvm::transform(Devices, std::next(RegFnNameParts.begin(), 2),
- [](const llvm::Triple &T) -> const std::string& {
- return T.getTriple();
- });
- llvm::sort(std::next(RegFnNameParts.begin(), 2), RegFnNameParts.end());
- std::string Descriptor = getName(RegFnNameParts);
- RegFn = CGM.CreateGlobalInitOrDestructFunction(FTy, Descriptor, FI);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, RegFn, FI, FunctionArgList());
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_register_lib), Desc);
- // Create a variable to drive the registration and unregistration of the
- // descriptor, so we can reuse the logic that emits Ctors and Dtors.
- ImplicitParamDecl RegUnregVar(C, C.getTranslationUnitDecl(),
- SourceLocation(), nullptr, C.CharTy,
- ImplicitParamDecl::Other);
- CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc);
- CGF.FinishFunction();
- }
- if (CGM.supportsCOMDAT()) {
- // It is sufficient to call registration function only once, so create a
- // COMDAT group for registration/unregistration functions and associated
- // data. That would reduce startup time and code size. Registration
- // function serves as a COMDAT group key.
- llvm::Comdat *ComdatKey = M.getOrInsertComdat(RegFn->getName());
- RegFn->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
- RegFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
- RegFn->setComdat(ComdatKey);
- UnRegFn->setComdat(ComdatKey);
- DeviceImages->setComdat(ComdatKey);
- Desc->setComdat(ComdatKey);
- }
- return RegFn;
-}
-
-void CGOpenMPRuntime::createOffloadEntry(
- llvm::Constant *ID, llvm::Constant *Addr, uint64_t Size, int32_t Flags,
- llvm::GlobalValue::LinkageTypes Linkage) {
- StringRef Name = Addr->getName();
- llvm::Module &M = CGM.getModule();
- llvm::LLVMContext &C = M.getContext();
-
- // Create constant string with the name.
- llvm::Constant *StrPtrInit = llvm::ConstantDataArray::getString(C, Name);
-
- std::string StringName = getName({"omp_offloading", "entry_name"});
- auto *Str = new llvm::GlobalVariable(
- M, StrPtrInit->getType(), /*isConstant=*/true,
- llvm::GlobalValue::InternalLinkage, StrPtrInit, StringName);
- Str->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- llvm::Constant *Data[] = {llvm::ConstantExpr::getBitCast(ID, CGM.VoidPtrTy),
- llvm::ConstantExpr::getBitCast(Str, CGM.Int8PtrTy),
- llvm::ConstantInt::get(CGM.SizeTy, Size),
- llvm::ConstantInt::get(CGM.Int32Ty, Flags),
- llvm::ConstantInt::get(CGM.Int32Ty, 0)};
- std::string EntryName = getName({"omp_offloading", "entry", ""});
- llvm::GlobalVariable *Entry = createGlobalStruct(
- CGM, getTgtOffloadEntryQTy(), /*IsConstant=*/true, Data,
- Twine(EntryName).concat(Name), llvm::GlobalValue::WeakAnyLinkage);
-
- // The entry has to be created in the section the linker expects it to be.
- std::string Section = getName({"omp_offloading", "entries"});
- Entry->setSection(Section);
-}
-
-void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
- // Emit the offloading entries and metadata so that the device codegen side
- // can easily figure out what to emit. The produced metadata looks like
- // this:
- //
- // !omp_offload.info = !{!1, ...}
- //
- // Right now we only generate metadata for function that contain target
- // regions.
-
- // If we do not have entries, we don't need to do anything.
- if (OffloadEntriesInfoManager.empty())
- return;
-
- llvm::Module &M = CGM.getModule();
- llvm::LLVMContext &C = M.getContext();
- SmallVector<const OffloadEntriesInfoManagerTy::OffloadEntryInfo *, 16>
- OrderedEntries(OffloadEntriesInfoManager.size());
- llvm::SmallVector<StringRef, 16> ParentFunctions(
- OffloadEntriesInfoManager.size());
-
- // Auxiliary methods to create metadata values and strings.
- auto &&GetMDInt = [this](unsigned V) {
- return llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(CGM.Int32Ty, V));
- };
-
- auto &&GetMDString = [&C](StringRef V) { return llvm::MDString::get(C, V); };
-
- // Create the offloading info metadata node.
- llvm::NamedMDNode *MD = M.getOrInsertNamedMetadata("omp_offload.info");
-
- // Create function that emits metadata for each target region entry;
- auto &&TargetRegionMetadataEmitter =
- [&C, MD, &OrderedEntries, &ParentFunctions, &GetMDInt, &GetMDString](
- unsigned DeviceID, unsigned FileID, StringRef ParentName,
- unsigned Line,
- const OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion &E) {
- // Generate metadata for target regions. Each entry of this metadata
- // contains:
- // - Entry 0 -> Kind of this type of metadata (0).
- // - Entry 1 -> Device ID of the file where the entry was identified.
- // - Entry 2 -> File ID of the file where the entry was identified.
- // - Entry 3 -> Mangled name of the function where the entry was
- // identified.
- // - Entry 4 -> Line in the file where the entry was identified.
- // - Entry 5 -> Order the entry was created.
- // The first element of the metadata node is the kind.
- llvm::Metadata *Ops[] = {GetMDInt(E.getKind()), GetMDInt(DeviceID),
- GetMDInt(FileID), GetMDString(ParentName),
- GetMDInt(Line), GetMDInt(E.getOrder())};
-
- // Save this entry in the right position of the ordered entries array.
- OrderedEntries[E.getOrder()] = &E;
- ParentFunctions[E.getOrder()] = ParentName;
-
- // Add metadata to the named metadata node.
- MD->addOperand(llvm::MDNode::get(C, Ops));
- };
-
- OffloadEntriesInfoManager.actOnTargetRegionEntriesInfo(
- TargetRegionMetadataEmitter);
-
- // Create function that emits metadata for each device global variable entry;
- auto &&DeviceGlobalVarMetadataEmitter =
- [&C, &OrderedEntries, &GetMDInt, &GetMDString,
- MD](StringRef MangledName,
- const OffloadEntriesInfoManagerTy::OffloadEntryInfoDeviceGlobalVar
- &E) {
- // Generate metadata for global variables. Each entry of this metadata
- // contains:
- // - Entry 0 -> Kind of this type of metadata (1).
- // - Entry 1 -> Mangled name of the variable.
- // - Entry 2 -> Declare target kind.
- // - Entry 3 -> Order the entry was created.
- // The first element of the metadata node is the kind.
- llvm::Metadata *Ops[] = {
- GetMDInt(E.getKind()), GetMDString(MangledName),
- GetMDInt(E.getFlags()), GetMDInt(E.getOrder())};
-
- // Save this entry in the right position of the ordered entries array.
- OrderedEntries[E.getOrder()] = &E;
-
- // Add metadata to the named metadata node.
- MD->addOperand(llvm::MDNode::get(C, Ops));
- };
-
- OffloadEntriesInfoManager.actOnDeviceGlobalVarEntriesInfo(
- DeviceGlobalVarMetadataEmitter);
-
- for (const auto *E : OrderedEntries) {
- assert(E && "All ordered entries must exist!");
- if (const auto *CE =
- dyn_cast<OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion>(
- E)) {
- if (!CE->getID() || !CE->getAddress()) {
- // Do not blame the entry if the parent funtion is not emitted.
- StringRef FnName = ParentFunctions[CE->getOrder()];
- if (!CGM.GetGlobalValue(FnName))
- continue;
- unsigned DiagID = CGM.getDiags().getCustomDiagID(
- DiagnosticsEngine::Error,
- "Offloading entry for target region is incorrect: either the "
- "address or the ID is invalid.");
- CGM.getDiags().Report(DiagID);
- continue;
- }
- createOffloadEntry(CE->getID(), CE->getAddress(), /*Size=*/0,
- CE->getFlags(), llvm::GlobalValue::WeakAnyLinkage);
- } else if (const auto *CE =
- dyn_cast<OffloadEntriesInfoManagerTy::
- OffloadEntryInfoDeviceGlobalVar>(E)) {
- OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind Flags =
- static_cast<OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind>(
- CE->getFlags());
- switch (Flags) {
- case OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryTo: {
- if (!CE->getAddress()) {
- unsigned DiagID = CGM.getDiags().getCustomDiagID(
- DiagnosticsEngine::Error,
- "Offloading entry for declare target variable is incorrect: the "
- "address is invalid.");
- CGM.getDiags().Report(DiagID);
- continue;
- }
- // The vaiable has no definition - no need to add the entry.
- if (CE->getVarSize().isZero())
- continue;
- break;
- }
- case OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryLink:
- assert(((CGM.getLangOpts().OpenMPIsDevice && !CE->getAddress()) ||
- (!CGM.getLangOpts().OpenMPIsDevice && CE->getAddress())) &&
- "Declaret target link address is set.");
- if (CGM.getLangOpts().OpenMPIsDevice)
- continue;
- if (!CE->getAddress()) {
- unsigned DiagID = CGM.getDiags().getCustomDiagID(
- DiagnosticsEngine::Error,
- "Offloading entry for declare target variable is incorrect: the "
- "address is invalid.");
- CGM.getDiags().Report(DiagID);
- continue;
- }
- break;
- }
- createOffloadEntry(CE->getAddress(), CE->getAddress(),
- CE->getVarSize().getQuantity(), Flags,
- CE->getLinkage());
- } else {
- llvm_unreachable("Unsupported entry kind.");
- }
- }
-}
-
-/// Loads all the offload entries information from the host IR
-/// metadata.
-void CGOpenMPRuntime::loadOffloadInfoMetadata() {
- // If we are in target mode, load the metadata from the host IR. This code has
- // to match the metadaata creation in createOffloadEntriesAndInfoMetadata().
-
- if (!CGM.getLangOpts().OpenMPIsDevice)
- return;
-
- if (CGM.getLangOpts().OMPHostIRFile.empty())
- return;
-
- auto Buf = llvm::MemoryBuffer::getFile(CGM.getLangOpts().OMPHostIRFile);
- if (auto EC = Buf.getError()) {
- CGM.getDiags().Report(diag::err_cannot_open_file)
- << CGM.getLangOpts().OMPHostIRFile << EC.message();
- return;
- }
-
- llvm::LLVMContext C;
- auto ME = expectedToErrorOrAndEmitErrors(
- C, llvm::parseBitcodeFile(Buf.get()->getMemBufferRef(), C));
-
- if (auto EC = ME.getError()) {
- unsigned DiagID = CGM.getDiags().getCustomDiagID(
- DiagnosticsEngine::Error, "Unable to parse host IR file '%0':'%1'");
- CGM.getDiags().Report(DiagID)
- << CGM.getLangOpts().OMPHostIRFile << EC.message();
- return;
- }
-
- llvm::NamedMDNode *MD = ME.get()->getNamedMetadata("omp_offload.info");
- if (!MD)
- return;
-
- for (llvm::MDNode *MN : MD->operands()) {
- auto &&GetMDInt = [MN](unsigned Idx) {
- auto *V = cast<llvm::ConstantAsMetadata>(MN->getOperand(Idx));
- return cast<llvm::ConstantInt>(V->getValue())->getZExtValue();
- };
-
- auto &&GetMDString = [MN](unsigned Idx) {
- auto *V = cast<llvm::MDString>(MN->getOperand(Idx));
- return V->getString();
- };
-
- switch (GetMDInt(0)) {
- default:
- llvm_unreachable("Unexpected metadata!");
- break;
- case OffloadEntriesInfoManagerTy::OffloadEntryInfo::
- OffloadingEntryInfoTargetRegion:
- OffloadEntriesInfoManager.initializeTargetRegionEntryInfo(
- /*DeviceID=*/GetMDInt(1), /*FileID=*/GetMDInt(2),
- /*ParentName=*/GetMDString(3), /*Line=*/GetMDInt(4),
- /*Order=*/GetMDInt(5));
- break;
- case OffloadEntriesInfoManagerTy::OffloadEntryInfo::
- OffloadingEntryInfoDeviceGlobalVar:
- OffloadEntriesInfoManager.initializeDeviceGlobalVarEntryInfo(
- /*MangledName=*/GetMDString(1),
- static_cast<OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind>(
- /*Flags=*/GetMDInt(2)),
- /*Order=*/GetMDInt(3));
- break;
- }
- }
-}
-
-void CGOpenMPRuntime::emitKmpRoutineEntryT(QualType KmpInt32Ty) {
- if (!KmpRoutineEntryPtrTy) {
- // Build typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *); type.
- ASTContext &C = CGM.getContext();
- QualType KmpRoutineEntryTyArgs[] = {KmpInt32Ty, C.VoidPtrTy};
- FunctionProtoType::ExtProtoInfo EPI;
- KmpRoutineEntryPtrQTy = C.getPointerType(
- C.getFunctionType(KmpInt32Ty, KmpRoutineEntryTyArgs, EPI));
- KmpRoutineEntryPtrTy = CGM.getTypes().ConvertType(KmpRoutineEntryPtrQTy);
- }
-}
-
-QualType CGOpenMPRuntime::getTgtOffloadEntryQTy() {
- // Make sure the type of the entry is already created. This is the type we
- // have to create:
- // struct __tgt_offload_entry{
- // void *addr; // Pointer to the offload entry info.
- // // (function or global)
- // char *name; // Name of the function or global.
- // size_t size; // Size of the entry info (0 if it a function).
- // int32_t flags; // Flags associated with the entry, e.g. 'link'.
- // int32_t reserved; // Reserved, to use by the runtime library.
- // };
- if (TgtOffloadEntryQTy.isNull()) {
- ASTContext &C = CGM.getContext();
- RecordDecl *RD = C.buildImplicitRecord("__tgt_offload_entry");
- RD->startDefinition();
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- addFieldToRecordDecl(C, RD, C.getPointerType(C.CharTy));
- addFieldToRecordDecl(C, RD, C.getSizeType());
- addFieldToRecordDecl(
- C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true));
- addFieldToRecordDecl(
- C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true));
- RD->completeDefinition();
- RD->addAttr(PackedAttr::CreateImplicit(C));
- TgtOffloadEntryQTy = C.getRecordType(RD);
- }
- return TgtOffloadEntryQTy;
-}
-
-QualType CGOpenMPRuntime::getTgtDeviceImageQTy() {
- // These are the types we need to build:
- // struct __tgt_device_image{
- // void *ImageStart; // Pointer to the target code start.
- // void *ImageEnd; // Pointer to the target code end.
- // // We also add the host entries to the device image, as it may be useful
- // // for the target runtime to have access to that information.
- // __tgt_offload_entry *EntriesBegin; // Begin of the table with all
- // // the entries.
- // __tgt_offload_entry *EntriesEnd; // End of the table with all the
- // // entries (non inclusive).
- // };
- if (TgtDeviceImageQTy.isNull()) {
- ASTContext &C = CGM.getContext();
- RecordDecl *RD = C.buildImplicitRecord("__tgt_device_image");
- RD->startDefinition();
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- RD->completeDefinition();
- TgtDeviceImageQTy = C.getRecordType(RD);
- }
- return TgtDeviceImageQTy;
-}
-
-QualType CGOpenMPRuntime::getTgtBinaryDescriptorQTy() {
- // struct __tgt_bin_desc{
- // int32_t NumDevices; // Number of devices supported.
- // __tgt_device_image *DeviceImages; // Arrays of device images
- // // (one per device).
- // __tgt_offload_entry *EntriesBegin; // Begin of the table with all the
- // // entries.
- // __tgt_offload_entry *EntriesEnd; // End of the table with all the
- // // entries (non inclusive).
- // };
- if (TgtBinaryDescriptorQTy.isNull()) {
- ASTContext &C = CGM.getContext();
- RecordDecl *RD = C.buildImplicitRecord("__tgt_bin_desc");
- RD->startDefinition();
- addFieldToRecordDecl(
- C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtDeviceImageQTy()));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
- RD->completeDefinition();
- TgtBinaryDescriptorQTy = C.getRecordType(RD);
- }
- return TgtBinaryDescriptorQTy;
-}
-
-namespace {
-struct PrivateHelpersTy {
- PrivateHelpersTy(const VarDecl *Original, const VarDecl *PrivateCopy,
- const VarDecl *PrivateElemInit)
- : Original(Original), PrivateCopy(PrivateCopy),
- PrivateElemInit(PrivateElemInit) {}
- const VarDecl *Original;
- const VarDecl *PrivateCopy;
- const VarDecl *PrivateElemInit;
-};
-typedef std::pair<CharUnits /*Align*/, PrivateHelpersTy> PrivateDataTy;
-} // anonymous namespace
-
-static RecordDecl *
-createPrivatesRecordDecl(CodeGenModule &CGM, ArrayRef<PrivateDataTy> Privates) {
- if (!Privates.empty()) {
- ASTContext &C = CGM.getContext();
- // Build struct .kmp_privates_t. {
- // /* private vars */
- // };
- RecordDecl *RD = C.buildImplicitRecord(".kmp_privates.t");
- RD->startDefinition();
- for (const auto &Pair : Privates) {
- const VarDecl *VD = Pair.second.Original;
- QualType Type = VD->getType().getNonReferenceType();
- FieldDecl *FD = addFieldToRecordDecl(C, RD, Type);
- if (VD->hasAttrs()) {
- for (specific_attr_iterator<AlignedAttr> I(VD->getAttrs().begin()),
- E(VD->getAttrs().end());
- I != E; ++I)
- FD->addAttr(*I);
- }
- }
- RD->completeDefinition();
- return RD;
- }
- return nullptr;
-}
-
-static RecordDecl *
-createKmpTaskTRecordDecl(CodeGenModule &CGM, OpenMPDirectiveKind Kind,
- QualType KmpInt32Ty,
- QualType KmpRoutineEntryPointerQTy) {
- ASTContext &C = CGM.getContext();
- // Build struct kmp_task_t {
- // void * shareds;
- // kmp_routine_entry_t routine;
- // kmp_int32 part_id;
- // kmp_cmplrdata_t data1;
- // kmp_cmplrdata_t data2;
- // For taskloops additional fields:
- // kmp_uint64 lb;
- // kmp_uint64 ub;
- // kmp_int64 st;
- // kmp_int32 liter;
- // void * reductions;
- // };
- RecordDecl *UD = C.buildImplicitRecord("kmp_cmplrdata_t", TTK_Union);
- UD->startDefinition();
- addFieldToRecordDecl(C, UD, KmpInt32Ty);
- addFieldToRecordDecl(C, UD, KmpRoutineEntryPointerQTy);
- UD->completeDefinition();
- QualType KmpCmplrdataTy = C.getRecordType(UD);
- RecordDecl *RD = C.buildImplicitRecord("kmp_task_t");
- RD->startDefinition();
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- addFieldToRecordDecl(C, RD, KmpRoutineEntryPointerQTy);
- addFieldToRecordDecl(C, RD, KmpInt32Ty);
- addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
- addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
- if (isOpenMPTaskLoopDirective(Kind)) {
- QualType KmpUInt64Ty =
- CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
- QualType KmpInt64Ty =
- CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
- addFieldToRecordDecl(C, RD, KmpUInt64Ty);
- addFieldToRecordDecl(C, RD, KmpUInt64Ty);
- addFieldToRecordDecl(C, RD, KmpInt64Ty);
- addFieldToRecordDecl(C, RD, KmpInt32Ty);
- addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- }
- RD->completeDefinition();
- return RD;
-}
-
-static RecordDecl *
-createKmpTaskTWithPrivatesRecordDecl(CodeGenModule &CGM, QualType KmpTaskTQTy,
- ArrayRef<PrivateDataTy> Privates) {
- ASTContext &C = CGM.getContext();
- // Build struct kmp_task_t_with_privates {
- // kmp_task_t task_data;
- // .kmp_privates_t. privates;
- // };
- RecordDecl *RD = C.buildImplicitRecord("kmp_task_t_with_privates");
- RD->startDefinition();
- addFieldToRecordDecl(C, RD, KmpTaskTQTy);
- if (const RecordDecl *PrivateRD = createPrivatesRecordDecl(CGM, Privates))
- addFieldToRecordDecl(C, RD, C.getRecordType(PrivateRD));
- RD->completeDefinition();
- return RD;
-}
-
-/// Emit a proxy function which accepts kmp_task_t as the second
-/// argument.
-/// \code
-/// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
-/// TaskFunction(gtid, tt->part_id, &tt->privates, task_privates_map, tt,
-/// For taskloops:
-/// tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
-/// tt->reductions, tt->shareds);
-/// return 0;
-/// }
-/// \endcode
-static llvm::Value *
-emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
- OpenMPDirectiveKind Kind, QualType KmpInt32Ty,
- QualType KmpTaskTWithPrivatesPtrQTy,
- QualType KmpTaskTWithPrivatesQTy, QualType KmpTaskTQTy,
- QualType SharedsPtrTy, llvm::Value *TaskFunction,
- llvm::Value *TaskPrivatesMap) {
- ASTContext &C = CGM.getContext();
- FunctionArgList Args;
- ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty,
- ImplicitParamDecl::Other);
- ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy.withRestrict(),
- ImplicitParamDecl::Other);
- Args.push_back(&GtidArg);
- Args.push_back(&TaskTypeArg);
- const auto &TaskEntryFnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
- llvm::FunctionType *TaskEntryTy =
- CGM.getTypes().GetFunctionType(TaskEntryFnInfo);
- std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_entry", ""});
- auto *TaskEntry = llvm::Function::Create(
- TaskEntryTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskEntry, TaskEntryFnInfo);
- TaskEntry->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), KmpInt32Ty, TaskEntry, TaskEntryFnInfo, Args,
- Loc, Loc);
-
- // TaskFunction(gtid, tt->task_data.part_id, &tt->privates, task_privates_map,
- // tt,
- // For taskloops:
- // tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
- // tt->task_data.shareds);
- llvm::Value *GtidParam = CGF.EmitLoadOfScalar(
- CGF.GetAddrOfLocalVar(&GtidArg), /*Volatile=*/false, KmpInt32Ty, Loc);
- LValue TDBase = CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(&TaskTypeArg),
- KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
- const auto *KmpTaskTWithPrivatesQTyRD =
- cast<RecordDecl>(KmpTaskTWithPrivatesQTy->getAsTagDecl());
- LValue Base =
- CGF.EmitLValueForField(TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
- const auto *KmpTaskTQTyRD = cast<RecordDecl>(KmpTaskTQTy->getAsTagDecl());
- auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
- LValue PartIdLVal = CGF.EmitLValueForField(Base, *PartIdFI);
- llvm::Value *PartidParam = PartIdLVal.getPointer();
-
- auto SharedsFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds);
- LValue SharedsLVal = CGF.EmitLValueForField(Base, *SharedsFI);
- llvm::Value *SharedsParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLoadOfScalar(SharedsLVal, Loc),
- CGF.ConvertTypeForMem(SharedsPtrTy));
-
- auto PrivatesFI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin(), 1);
- llvm::Value *PrivatesParam;
- if (PrivatesFI != KmpTaskTWithPrivatesQTyRD->field_end()) {
- LValue PrivatesLVal = CGF.EmitLValueForField(TDBase, *PrivatesFI);
- PrivatesParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- PrivatesLVal.getPointer(), CGF.VoidPtrTy);
- } else {
- PrivatesParam = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
- }
-
- llvm::Value *CommonArgs[] = {GtidParam, PartidParam, PrivatesParam,
- TaskPrivatesMap,
- CGF.Builder
- .CreatePointerBitCastOrAddrSpaceCast(
- TDBase.getAddress(), CGF.VoidPtrTy)
- .getPointer()};
- SmallVector<llvm::Value *, 16> CallArgs(std::begin(CommonArgs),
- std::end(CommonArgs));
- if (isOpenMPTaskLoopDirective(Kind)) {
- auto LBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound);
- LValue LBLVal = CGF.EmitLValueForField(Base, *LBFI);
- llvm::Value *LBParam = CGF.EmitLoadOfScalar(LBLVal, Loc);
- auto UBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound);
- LValue UBLVal = CGF.EmitLValueForField(Base, *UBFI);
- llvm::Value *UBParam = CGF.EmitLoadOfScalar(UBLVal, Loc);
- auto StFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTStride);
- LValue StLVal = CGF.EmitLValueForField(Base, *StFI);
- llvm::Value *StParam = CGF.EmitLoadOfScalar(StLVal, Loc);
- auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
- LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
- llvm::Value *LIParam = CGF.EmitLoadOfScalar(LILVal, Loc);
- auto RFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTReductions);
- LValue RLVal = CGF.EmitLValueForField(Base, *RFI);
- llvm::Value *RParam = CGF.EmitLoadOfScalar(RLVal, Loc);
- CallArgs.push_back(LBParam);
- CallArgs.push_back(UBParam);
- CallArgs.push_back(StParam);
- CallArgs.push_back(LIParam);
- CallArgs.push_back(RParam);
- }
- CallArgs.push_back(SharedsParam);
-
- CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskFunction,
- CallArgs);
- CGF.EmitStoreThroughLValue(RValue::get(CGF.Builder.getInt32(/*C=*/0)),
- CGF.MakeAddrLValue(CGF.ReturnValue, KmpInt32Ty));
- CGF.FinishFunction();
- return TaskEntry;
-}
-
-static llvm::Value *emitDestructorsFunction(CodeGenModule &CGM,
- SourceLocation Loc,
- QualType KmpInt32Ty,
- QualType KmpTaskTWithPrivatesPtrQTy,
- QualType KmpTaskTWithPrivatesQTy) {
- ASTContext &C = CGM.getContext();
- FunctionArgList Args;
- ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty,
- ImplicitParamDecl::Other);
- ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy.withRestrict(),
- ImplicitParamDecl::Other);
- Args.push_back(&GtidArg);
- Args.push_back(&TaskTypeArg);
- const auto &DestructorFnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
- llvm::FunctionType *DestructorFnTy =
- CGM.getTypes().GetFunctionType(DestructorFnInfo);
- std::string Name =
- CGM.getOpenMPRuntime().getName({"omp_task_destructor", ""});
- auto *DestructorFn =
- llvm::Function::Create(DestructorFnTy, llvm::GlobalValue::InternalLinkage,
- Name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), DestructorFn,
- DestructorFnInfo);
- DestructorFn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), KmpInt32Ty, DestructorFn, DestructorFnInfo,
- Args, Loc, Loc);
-
- LValue Base = CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(&TaskTypeArg),
- KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
- const auto *KmpTaskTWithPrivatesQTyRD =
- cast<RecordDecl>(KmpTaskTWithPrivatesQTy->getAsTagDecl());
- auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
- Base = CGF.EmitLValueForField(Base, *FI);
- for (const auto *Field :
- cast<RecordDecl>(FI->getType()->getAsTagDecl())->fields()) {
- if (QualType::DestructionKind DtorKind =
- Field->getType().isDestructedType()) {
- LValue FieldLValue = CGF.EmitLValueForField(Base, Field);
- CGF.pushDestroy(DtorKind, FieldLValue.getAddress(), Field->getType());
- }
- }
- CGF.FinishFunction();
- return DestructorFn;
-}
-
-/// Emit a privates mapping function for correct handling of private and
-/// firstprivate variables.
-/// \code
-/// void .omp_task_privates_map.(const .privates. *noalias privs, <ty1>
-/// **noalias priv1,..., <tyn> **noalias privn) {
-/// *priv1 = &.privates.priv1;
-/// ...;
-/// *privn = &.privates.privn;
-/// }
-/// \endcode
-static llvm::Value *
-emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
- ArrayRef<const Expr *> PrivateVars,
- ArrayRef<const Expr *> FirstprivateVars,
- ArrayRef<const Expr *> LastprivateVars,
- QualType PrivatesQTy,
- ArrayRef<PrivateDataTy> Privates) {
- ASTContext &C = CGM.getContext();
- FunctionArgList Args;
- ImplicitParamDecl TaskPrivatesArg(
- C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.getPointerType(PrivatesQTy).withConst().withRestrict(),
- ImplicitParamDecl::Other);
- Args.push_back(&TaskPrivatesArg);
- llvm::DenseMap<const VarDecl *, unsigned> PrivateVarsPos;
- unsigned Counter = 1;
- for (const Expr *E : PrivateVars) {
- Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict(),
- ImplicitParamDecl::Other));
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- PrivateVarsPos[VD] = Counter;
- ++Counter;
- }
- for (const Expr *E : FirstprivateVars) {
- Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict(),
- ImplicitParamDecl::Other));
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- PrivateVarsPos[VD] = Counter;
- ++Counter;
- }
- for (const Expr *E : LastprivateVars) {
- Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict(),
- ImplicitParamDecl::Other));
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- PrivateVarsPos[VD] = Counter;
- ++Counter;
- }
- const auto &TaskPrivatesMapFnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *TaskPrivatesMapTy =
- CGM.getTypes().GetFunctionType(TaskPrivatesMapFnInfo);
- std::string Name =
- CGM.getOpenMPRuntime().getName({"omp_task_privates_map", ""});
- auto *TaskPrivatesMap = llvm::Function::Create(
- TaskPrivatesMapTy, llvm::GlobalValue::InternalLinkage, Name,
- &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskPrivatesMap,
- TaskPrivatesMapFnInfo);
- TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
- TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone);
- TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskPrivatesMap,
- TaskPrivatesMapFnInfo, Args, Loc, Loc);
-
- // *privi = &.privates.privi;
- LValue Base = CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(&TaskPrivatesArg),
- TaskPrivatesArg.getType()->castAs<PointerType>());
- const auto *PrivatesQTyRD = cast<RecordDecl>(PrivatesQTy->getAsTagDecl());
- Counter = 0;
- for (const FieldDecl *Field : PrivatesQTyRD->fields()) {
- LValue FieldLVal = CGF.EmitLValueForField(Base, Field);
- const VarDecl *VD = Args[PrivateVarsPos[Privates[Counter].second.Original]];
- LValue RefLVal =
- CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType());
- LValue RefLoadLVal = CGF.EmitLoadOfPointerLValue(
- RefLVal.getAddress(), RefLVal.getType()->castAs<PointerType>());
- CGF.EmitStoreOfScalar(FieldLVal.getPointer(), RefLoadLVal);
- ++Counter;
- }
- CGF.FinishFunction();
- return TaskPrivatesMap;
-}
-
-static bool stable_sort_comparator(const PrivateDataTy P1,
- const PrivateDataTy P2) {
- return P1.first > P2.first;
-}
-
-/// Emit initialization for private variables in task-based directives.
-static void emitPrivatesInit(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- Address KmpTaskSharedsPtr, LValue TDBase,
- const RecordDecl *KmpTaskTWithPrivatesQTyRD,
- QualType SharedsTy, QualType SharedsPtrTy,
- const OMPTaskDataTy &Data,
- ArrayRef<PrivateDataTy> Privates, bool ForDup) {
- ASTContext &C = CGF.getContext();
- auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
- LValue PrivatesBase = CGF.EmitLValueForField(TDBase, *FI);
- OpenMPDirectiveKind Kind = isOpenMPTaskLoopDirective(D.getDirectiveKind())
- ? OMPD_taskloop
- : OMPD_task;
- const CapturedStmt &CS = *D.getCapturedStmt(Kind);
- CodeGenFunction::CGCapturedStmtInfo CapturesInfo(CS);
- LValue SrcBase;
- bool IsTargetTask =
- isOpenMPTargetDataManagementDirective(D.getDirectiveKind()) ||
- isOpenMPTargetExecutionDirective(D.getDirectiveKind());
- // For target-based directives skip 3 firstprivate arrays BasePointersArray,
- // PointersArray and SizesArray. The original variables for these arrays are
- // not captured and we get their addresses explicitly.
- if ((!IsTargetTask && !Data.FirstprivateVars.empty()) ||
- (IsTargetTask && KmpTaskSharedsPtr.isValid())) {
- SrcBase = CGF.MakeAddrLValue(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- KmpTaskSharedsPtr, CGF.ConvertTypeForMem(SharedsPtrTy)),
- SharedsTy);
- }
- FI = cast<RecordDecl>(FI->getType()->getAsTagDecl())->field_begin();
- for (const PrivateDataTy &Pair : Privates) {
- const VarDecl *VD = Pair.second.PrivateCopy;
- const Expr *Init = VD->getAnyInitializer();
- if (Init && (!ForDup || (isa<CXXConstructExpr>(Init) &&
- !CGF.isTrivialInitializer(Init)))) {
- LValue PrivateLValue = CGF.EmitLValueForField(PrivatesBase, *FI);
- if (const VarDecl *Elem = Pair.second.PrivateElemInit) {
- const VarDecl *OriginalVD = Pair.second.Original;
- // Check if the variable is the target-based BasePointersArray,
- // PointersArray or SizesArray.
- LValue SharedRefLValue;
- QualType Type = OriginalVD->getType();
- const FieldDecl *SharedField = CapturesInfo.lookup(OriginalVD);
- if (IsTargetTask && !SharedField) {
- assert(isa<ImplicitParamDecl>(OriginalVD) &&
- isa<CapturedDecl>(OriginalVD->getDeclContext()) &&
- cast<CapturedDecl>(OriginalVD->getDeclContext())
- ->getNumParams() == 0 &&
- isa<TranslationUnitDecl>(
- cast<CapturedDecl>(OriginalVD->getDeclContext())
- ->getDeclContext()) &&
- "Expected artificial target data variable.");
- SharedRefLValue =
- CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(OriginalVD), Type);
- } else {
- SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
- SharedRefLValue = CGF.MakeAddrLValue(
- Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)),
- SharedRefLValue.getType(), LValueBaseInfo(AlignmentSource::Decl),
- SharedRefLValue.getTBAAInfo());
- }
- if (Type->isArrayType()) {
- // Initialize firstprivate array.
- if (!isa<CXXConstructExpr>(Init) || CGF.isTrivialInitializer(Init)) {
- // Perform simple memcpy.
- CGF.EmitAggregateAssign(PrivateLValue, SharedRefLValue, Type);
- } else {
- // Initialize firstprivate array using element-by-element
- // initialization.
- CGF.EmitOMPAggregateAssign(
- PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type,
- [&CGF, Elem, Init, &CapturesInfo](Address DestElement,
- Address SrcElement) {
- // Clean up any temporaries needed by the initialization.
- CodeGenFunction::OMPPrivateScope InitScope(CGF);
- InitScope.addPrivate(
- Elem, [SrcElement]() -> Address { return SrcElement; });
- (void)InitScope.Privatize();
- // Emit initialization for single element.
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(
- CGF, &CapturesInfo);
- CGF.EmitAnyExprToMem(Init, DestElement,
- Init->getType().getQualifiers(),
- /*IsInitializer=*/false);
- });
- }
- } else {
- CodeGenFunction::OMPPrivateScope InitScope(CGF);
- InitScope.addPrivate(Elem, [SharedRefLValue]() -> Address {
- return SharedRefLValue.getAddress();
- });
- (void)InitScope.Privatize();
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo);
- CGF.EmitExprAsInit(Init, VD, PrivateLValue,
- /*capturedByInit=*/false);
- }
- } else {
- CGF.EmitExprAsInit(Init, VD, PrivateLValue, /*capturedByInit=*/false);
- }
- }
- ++FI;
- }
-}
-
-/// Check if duplication function is required for taskloops.
-static bool checkInitIsRequired(CodeGenFunction &CGF,
- ArrayRef<PrivateDataTy> Privates) {
- bool InitRequired = false;
- for (const PrivateDataTy &Pair : Privates) {
- const VarDecl *VD = Pair.second.PrivateCopy;
- const Expr *Init = VD->getAnyInitializer();
- InitRequired = InitRequired || (Init && isa<CXXConstructExpr>(Init) &&
- !CGF.isTrivialInitializer(Init));
- if (InitRequired)
- break;
- }
- return InitRequired;
-}
-
-
-/// Emit task_dup function (for initialization of
-/// private/firstprivate/lastprivate vars and last_iter flag)
-/// \code
-/// void __task_dup_entry(kmp_task_t *task_dst, const kmp_task_t *task_src, int
-/// lastpriv) {
-/// // setup lastprivate flag
-/// task_dst->last = lastpriv;
-/// // could be constructor calls here...
-/// }
-/// \endcode
-static llvm::Value *
-emitTaskDupFunction(CodeGenModule &CGM, SourceLocation Loc,
- const OMPExecutableDirective &D,
- QualType KmpTaskTWithPrivatesPtrQTy,
- const RecordDecl *KmpTaskTWithPrivatesQTyRD,
- const RecordDecl *KmpTaskTQTyRD, QualType SharedsTy,
- QualType SharedsPtrTy, const OMPTaskDataTy &Data,
- ArrayRef<PrivateDataTy> Privates, bool WithLastIter) {
- ASTContext &C = CGM.getContext();
- FunctionArgList Args;
- ImplicitParamDecl DstArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy,
- ImplicitParamDecl::Other);
- ImplicitParamDecl SrcArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy,
- ImplicitParamDecl::Other);
- ImplicitParamDecl LastprivArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy,
- ImplicitParamDecl::Other);
- Args.push_back(&DstArg);
- Args.push_back(&SrcArg);
- Args.push_back(&LastprivArg);
- const auto &TaskDupFnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *TaskDupTy = CGM.getTypes().GetFunctionType(TaskDupFnInfo);
- std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_dup", ""});
- auto *TaskDup = llvm::Function::Create(
- TaskDupTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskDup, TaskDupFnInfo);
- TaskDup->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskDup, TaskDupFnInfo, Args, Loc,
- Loc);
-
- LValue TDBase = CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(&DstArg),
- KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
- // task_dst->liter = lastpriv;
- if (WithLastIter) {
- auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
- LValue Base = CGF.EmitLValueForField(
- TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
- LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
- llvm::Value *Lastpriv = CGF.EmitLoadOfScalar(
- CGF.GetAddrOfLocalVar(&LastprivArg), /*Volatile=*/false, C.IntTy, Loc);
- CGF.EmitStoreOfScalar(Lastpriv, LILVal);
- }
-
- // Emit initial values for private copies (if any).
- assert(!Privates.empty());
- Address KmpTaskSharedsPtr = Address::invalid();
- if (!Data.FirstprivateVars.empty()) {
- LValue TDBase = CGF.EmitLoadOfPointerLValue(
- CGF.GetAddrOfLocalVar(&SrcArg),
- KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
- LValue Base = CGF.EmitLValueForField(
- TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
- KmpTaskSharedsPtr = Address(
- CGF.EmitLoadOfScalar(CGF.EmitLValueForField(
- Base, *std::next(KmpTaskTQTyRD->field_begin(),
- KmpTaskTShareds)),
- Loc),
- CGF.getNaturalTypeAlignment(SharedsTy));
- }
- emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, TDBase, KmpTaskTWithPrivatesQTyRD,
- SharedsTy, SharedsPtrTy, Data, Privates, /*ForDup=*/true);
- CGF.FinishFunction();
- return TaskDup;
-}
-
-/// Checks if destructor function is required to be generated.
-/// \return true if cleanups are required, false otherwise.
-static bool
-checkDestructorsRequired(const RecordDecl *KmpTaskTWithPrivatesQTyRD) {
- bool NeedsCleanup = false;
- auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin(), 1);
- const auto *PrivateRD = cast<RecordDecl>(FI->getType()->getAsTagDecl());
- for (const FieldDecl *FD : PrivateRD->fields()) {
- NeedsCleanup = NeedsCleanup || FD->getType().isDestructedType();
- if (NeedsCleanup)
- break;
- }
- return NeedsCleanup;
-}
-
-CGOpenMPRuntime::TaskResultTy
-CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPExecutableDirective &D,
- llvm::Value *TaskFunction, QualType SharedsTy,
- Address Shareds, const OMPTaskDataTy &Data) {
- ASTContext &C = CGM.getContext();
- llvm::SmallVector<PrivateDataTy, 4> Privates;
- // Aggregate privates and sort them by the alignment.
- auto I = Data.PrivateCopies.begin();
- for (const Expr *E : Data.PrivateVars) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- Privates.emplace_back(
- C.getDeclAlign(VD),
- PrivateHelpersTy(VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
- /*PrivateElemInit=*/nullptr));
- ++I;
- }
- I = Data.FirstprivateCopies.begin();
- auto IElemInitRef = Data.FirstprivateInits.begin();
- for (const Expr *E : Data.FirstprivateVars) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- Privates.emplace_back(
- C.getDeclAlign(VD),
- PrivateHelpersTy(
- VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
- cast<VarDecl>(cast<DeclRefExpr>(*IElemInitRef)->getDecl())));
- ++I;
- ++IElemInitRef;
- }
- I = Data.LastprivateCopies.begin();
- for (const Expr *E : Data.LastprivateVars) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- Privates.emplace_back(
- C.getDeclAlign(VD),
- PrivateHelpersTy(VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
- /*PrivateElemInit=*/nullptr));
- ++I;
- }
- std::stable_sort(Privates.begin(), Privates.end(), stable_sort_comparator);
- QualType KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
- // Build type kmp_routine_entry_t (if not built yet).
- emitKmpRoutineEntryT(KmpInt32Ty);
- // Build type kmp_task_t (if not built yet).
- if (isOpenMPTaskLoopDirective(D.getDirectiveKind())) {
- if (SavedKmpTaskloopTQTy.isNull()) {
- SavedKmpTaskloopTQTy = C.getRecordType(createKmpTaskTRecordDecl(
- CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
- }
- KmpTaskTQTy = SavedKmpTaskloopTQTy;
- } else {
- assert((D.getDirectiveKind() == OMPD_task ||
- isOpenMPTargetExecutionDirective(D.getDirectiveKind()) ||
- isOpenMPTargetDataManagementDirective(D.getDirectiveKind())) &&
- "Expected taskloop, task or target directive");
- if (SavedKmpTaskTQTy.isNull()) {
- SavedKmpTaskTQTy = C.getRecordType(createKmpTaskTRecordDecl(
- CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
- }
- KmpTaskTQTy = SavedKmpTaskTQTy;
- }
- const auto *KmpTaskTQTyRD = cast<RecordDecl>(KmpTaskTQTy->getAsTagDecl());
- // Build particular struct kmp_task_t for the given task.
- const RecordDecl *KmpTaskTWithPrivatesQTyRD =
- createKmpTaskTWithPrivatesRecordDecl(CGM, KmpTaskTQTy, Privates);
- QualType KmpTaskTWithPrivatesQTy = C.getRecordType(KmpTaskTWithPrivatesQTyRD);
- QualType KmpTaskTWithPrivatesPtrQTy =
- C.getPointerType(KmpTaskTWithPrivatesQTy);
- llvm::Type *KmpTaskTWithPrivatesTy = CGF.ConvertType(KmpTaskTWithPrivatesQTy);
- llvm::Type *KmpTaskTWithPrivatesPtrTy =
- KmpTaskTWithPrivatesTy->getPointerTo();
- llvm::Value *KmpTaskTWithPrivatesTySize =
- CGF.getTypeSize(KmpTaskTWithPrivatesQTy);
- QualType SharedsPtrTy = C.getPointerType(SharedsTy);
-
- // Emit initial values for private copies (if any).
- llvm::Value *TaskPrivatesMap = nullptr;
- llvm::Type *TaskPrivatesMapTy =
- std::next(cast<llvm::Function>(TaskFunction)->arg_begin(), 3)->getType();
- if (!Privates.empty()) {
- auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
- TaskPrivatesMap = emitTaskPrivateMappingFunction(
- CGM, Loc, Data.PrivateVars, Data.FirstprivateVars, Data.LastprivateVars,
- FI->getType(), Privates);
- TaskPrivatesMap = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- TaskPrivatesMap, TaskPrivatesMapTy);
- } else {
- TaskPrivatesMap = llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(TaskPrivatesMapTy));
- }
- // Build a proxy function kmp_int32 .omp_task_entry.(kmp_int32 gtid,
- // kmp_task_t *tt);
- llvm::Value *TaskEntry = emitProxyTaskFunction(
- CGM, Loc, D.getDirectiveKind(), KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
- KmpTaskTWithPrivatesQTy, KmpTaskTQTy, SharedsPtrTy, TaskFunction,
- TaskPrivatesMap);
-
- // Build call kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
- // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- // kmp_routine_entry_t *task_entry);
- // Task flags. Format is taken from
- // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h,
- // description of kmp_tasking_flags struct.
- enum {
- TiedFlag = 0x1,
- FinalFlag = 0x2,
- DestructorsFlag = 0x8,
- PriorityFlag = 0x20
- };
- unsigned Flags = Data.Tied ? TiedFlag : 0;
- bool NeedsCleanup = false;
- if (!Privates.empty()) {
- NeedsCleanup = checkDestructorsRequired(KmpTaskTWithPrivatesQTyRD);
- if (NeedsCleanup)
- Flags = Flags | DestructorsFlag;
- }
- if (Data.Priority.getInt())
- Flags = Flags | PriorityFlag;
- llvm::Value *TaskFlags =
- Data.Final.getPointer()
- ? CGF.Builder.CreateSelect(Data.Final.getPointer(),
- CGF.Builder.getInt32(FinalFlag),
- CGF.Builder.getInt32(/*C=*/0))
- : CGF.Builder.getInt32(Data.Final.getInt() ? FinalFlag : 0);
- TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
- llvm::Value *SharedsSize = CGM.getSize(C.getTypeSizeInChars(SharedsTy));
- llvm::Value *AllocArgs[] = {emitUpdateLocation(CGF, Loc),
- getThreadID(CGF, Loc), TaskFlags,
- KmpTaskTWithPrivatesTySize, SharedsSize,
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- TaskEntry, KmpRoutineEntryPtrTy)};
- llvm::Value *NewTask = CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_omp_task_alloc), AllocArgs);
- llvm::Value *NewTaskNewTaskTTy =
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- NewTask, KmpTaskTWithPrivatesPtrTy);
- LValue Base = CGF.MakeNaturalAlignAddrLValue(NewTaskNewTaskTTy,
- KmpTaskTWithPrivatesQTy);
- LValue TDBase =
- CGF.EmitLValueForField(Base, *KmpTaskTWithPrivatesQTyRD->field_begin());
- // Fill the data in the resulting kmp_task_t record.
- // Copy shareds if there are any.
- Address KmpTaskSharedsPtr = Address::invalid();
- if (!SharedsTy->getAsStructureType()->getDecl()->field_empty()) {
- KmpTaskSharedsPtr =
- Address(CGF.EmitLoadOfScalar(
- CGF.EmitLValueForField(
- TDBase, *std::next(KmpTaskTQTyRD->field_begin(),
- KmpTaskTShareds)),
- Loc),
- CGF.getNaturalTypeAlignment(SharedsTy));
- LValue Dest = CGF.MakeAddrLValue(KmpTaskSharedsPtr, SharedsTy);
- LValue Src = CGF.MakeAddrLValue(Shareds, SharedsTy);
- CGF.EmitAggregateCopy(Dest, Src, SharedsTy, AggValueSlot::DoesNotOverlap);
- }
- // Emit initial values for private copies (if any).
- TaskResultTy Result;
- if (!Privates.empty()) {
- emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, Base, KmpTaskTWithPrivatesQTyRD,
- SharedsTy, SharedsPtrTy, Data, Privates,
- /*ForDup=*/false);
- if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) &&
- (!Data.LastprivateVars.empty() || checkInitIsRequired(CGF, Privates))) {
- Result.TaskDupFn = emitTaskDupFunction(
- CGM, Loc, D, KmpTaskTWithPrivatesPtrQTy, KmpTaskTWithPrivatesQTyRD,
- KmpTaskTQTyRD, SharedsTy, SharedsPtrTy, Data, Privates,
- /*WithLastIter=*/!Data.LastprivateVars.empty());
- }
- }
- // Fields of union "kmp_cmplrdata_t" for destructors and priority.
- enum { Priority = 0, Destructors = 1 };
- // Provide pointer to function with destructors for privates.
- auto FI = std::next(KmpTaskTQTyRD->field_begin(), Data1);
- const RecordDecl *KmpCmplrdataUD =
- (*FI)->getType()->getAsUnionType()->getDecl();
- if (NeedsCleanup) {
- llvm::Value *DestructorFn = emitDestructorsFunction(
- CGM, Loc, KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
- KmpTaskTWithPrivatesQTy);
- LValue Data1LV = CGF.EmitLValueForField(TDBase, *FI);
- LValue DestructorsLV = CGF.EmitLValueForField(
- Data1LV, *std::next(KmpCmplrdataUD->field_begin(), Destructors));
- CGF.EmitStoreOfScalar(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- DestructorFn, KmpRoutineEntryPtrTy),
- DestructorsLV);
- }
- // Set priority.
- if (Data.Priority.getInt()) {
- LValue Data2LV = CGF.EmitLValueForField(
- TDBase, *std::next(KmpTaskTQTyRD->field_begin(), Data2));
- LValue PriorityLV = CGF.EmitLValueForField(
- Data2LV, *std::next(KmpCmplrdataUD->field_begin(), Priority));
- CGF.EmitStoreOfScalar(Data.Priority.getPointer(), PriorityLV);
- }
- Result.NewTask = NewTask;
- Result.TaskEntry = TaskEntry;
- Result.NewTaskNewTaskTTy = NewTaskNewTaskTTy;
- Result.TDBase = TDBase;
- Result.KmpTaskTQTyRD = KmpTaskTQTyRD;
- return Result;
-}
-
-void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPExecutableDirective &D,
- llvm::Value *TaskFunction,
- QualType SharedsTy, Address Shareds,
- const Expr *IfCond,
- const OMPTaskDataTy &Data) {
- if (!CGF.HaveInsertPoint())
- return;
-
- TaskResultTy Result =
- emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
- llvm::Value *NewTask = Result.NewTask;
- llvm::Value *TaskEntry = Result.TaskEntry;
- llvm::Value *NewTaskNewTaskTTy = Result.NewTaskNewTaskTTy;
- LValue TDBase = Result.TDBase;
- const RecordDecl *KmpTaskTQTyRD = Result.KmpTaskTQTyRD;
- ASTContext &C = CGM.getContext();
- // Process list of dependences.
- Address DependenciesArray = Address::invalid();
- unsigned NumDependencies = Data.Dependences.size();
- if (NumDependencies) {
- // Dependence kind for RTL.
- enum RTLDependenceKindTy { DepIn = 0x01, DepInOut = 0x3 };
- enum RTLDependInfoFieldsTy { BaseAddr, Len, Flags };
- RecordDecl *KmpDependInfoRD;
- QualType FlagsTy =
- C.getIntTypeForBitwidth(C.getTypeSize(C.BoolTy), /*Signed=*/false);
- llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
- if (KmpDependInfoTy.isNull()) {
- KmpDependInfoRD = C.buildImplicitRecord("kmp_depend_info");
- KmpDependInfoRD->startDefinition();
- addFieldToRecordDecl(C, KmpDependInfoRD, C.getIntPtrType());
- addFieldToRecordDecl(C, KmpDependInfoRD, C.getSizeType());
- addFieldToRecordDecl(C, KmpDependInfoRD, FlagsTy);
- KmpDependInfoRD->completeDefinition();
- KmpDependInfoTy = C.getRecordType(KmpDependInfoRD);
- } else {
- KmpDependInfoRD = cast<RecordDecl>(KmpDependInfoTy->getAsTagDecl());
- }
- CharUnits DependencySize = C.getTypeSizeInChars(KmpDependInfoTy);
- // Define type kmp_depend_info[<Dependences.size()>];
- QualType KmpDependInfoArrayTy = C.getConstantArrayType(
- KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies),
- ArrayType::Normal, /*IndexTypeQuals=*/0);
- // kmp_depend_info[<Dependences.size()>] deps;
- DependenciesArray =
- CGF.CreateMemTemp(KmpDependInfoArrayTy, ".dep.arr.addr");
- for (unsigned I = 0; I < NumDependencies; ++I) {
- const Expr *E = Data.Dependences[I].second;
- LValue Addr = CGF.EmitLValue(E);
- llvm::Value *Size;
- QualType Ty = E->getType();
- if (const auto *ASE =
- dyn_cast<OMPArraySectionExpr>(E->IgnoreParenImpCasts())) {
- LValue UpAddrLVal =
- CGF.EmitOMPArraySectionExpr(ASE, /*LowerBound=*/false);
- llvm::Value *UpAddr =
- CGF.Builder.CreateConstGEP1_32(UpAddrLVal.getPointer(), /*Idx0=*/1);
- llvm::Value *LowIntPtr =
- CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGM.SizeTy);
- llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGM.SizeTy);
- Size = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr);
- } else {
- Size = CGF.getTypeSize(Ty);
- }
- LValue Base = CGF.MakeAddrLValue(
- CGF.Builder.CreateConstArrayGEP(DependenciesArray, I, DependencySize),
- KmpDependInfoTy);
- // deps[i].base_addr = &<Dependences[i].second>;
- LValue BaseAddrLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), BaseAddr));
- CGF.EmitStoreOfScalar(
- CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGF.IntPtrTy),
- BaseAddrLVal);
- // deps[i].len = sizeof(<Dependences[i].second>);
- LValue LenLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), Len));
- CGF.EmitStoreOfScalar(Size, LenLVal);
- // deps[i].flags = <Dependences[i].first>;
- RTLDependenceKindTy DepKind;
- switch (Data.Dependences[I].first) {
- case OMPC_DEPEND_in:
- DepKind = DepIn;
- break;
- // Out and InOut dependencies must use the same code.
- case OMPC_DEPEND_out:
- case OMPC_DEPEND_inout:
- DepKind = DepInOut;
- break;
- case OMPC_DEPEND_source:
- case OMPC_DEPEND_sink:
- case OMPC_DEPEND_unknown:
- llvm_unreachable("Unknown task dependence type");
- }
- LValue FlagsLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), Flags));
- CGF.EmitStoreOfScalar(llvm::ConstantInt::get(LLVMFlagsTy, DepKind),
- FlagsLVal);
- }
- DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder.CreateStructGEP(DependenciesArray, 0, CharUnits::Zero()),
- CGF.VoidPtrTy);
- }
-
- // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
- // libcall.
- // Build kmp_int32 __kmpc_omp_task_with_deps(ident_t *, kmp_int32 gtid,
- // kmp_task_t *new_task, kmp_int32 ndeps, kmp_depend_info_t *dep_list,
- // kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list) if dependence
- // list is not empty
- llvm::Value *ThreadID = getThreadID(CGF, Loc);
- llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
- llvm::Value *TaskArgs[] = { UpLoc, ThreadID, NewTask };
- llvm::Value *DepTaskArgs[7];
- if (NumDependencies) {
- DepTaskArgs[0] = UpLoc;
- DepTaskArgs[1] = ThreadID;
- DepTaskArgs[2] = NewTask;
- DepTaskArgs[3] = CGF.Builder.getInt32(NumDependencies);
- DepTaskArgs[4] = DependenciesArray.getPointer();
- DepTaskArgs[5] = CGF.Builder.getInt32(0);
- DepTaskArgs[6] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
- }
- auto &&ThenCodeGen = [this, &Data, TDBase, KmpTaskTQTyRD, NumDependencies,
- &TaskArgs,
- &DepTaskArgs](CodeGenFunction &CGF, PrePostActionTy &) {
- if (!Data.Tied) {
- auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
- LValue PartIdLVal = CGF.EmitLValueForField(TDBase, *PartIdFI);
- CGF.EmitStoreOfScalar(CGF.Builder.getInt32(0), PartIdLVal);
- }
- if (NumDependencies) {
- CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_omp_task_with_deps), DepTaskArgs);
- } else {
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task),
- TaskArgs);
- }
- // Check if parent region is untied and build return for untied task;
- if (auto *Region =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
- Region->emitUntiedSwitch(CGF);
- };
-
- llvm::Value *DepWaitTaskArgs[6];
- if (NumDependencies) {
- DepWaitTaskArgs[0] = UpLoc;
- DepWaitTaskArgs[1] = ThreadID;
- DepWaitTaskArgs[2] = CGF.Builder.getInt32(NumDependencies);
- DepWaitTaskArgs[3] = DependenciesArray.getPointer();
- DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
- DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
- }
- auto &&ElseCodeGen = [&TaskArgs, ThreadID, NewTaskNewTaskTTy, TaskEntry,
- NumDependencies, &DepWaitTaskArgs,
- Loc](CodeGenFunction &CGF, PrePostActionTy &) {
- CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
- CodeGenFunction::RunCleanupsScope LocalScope(CGF);
- // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid,
- // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
- // ndeps_noalias, kmp_depend_info_t *noalias_dep_list); if dependence info
- // is specified.
- if (NumDependencies)
- CGF.EmitRuntimeCall(RT.createRuntimeFunction(OMPRTL__kmpc_omp_wait_deps),
- DepWaitTaskArgs);
- // Call proxy_task_entry(gtid, new_task);
- auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy,
- Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- llvm::Value *OutlinedFnArgs[] = {ThreadID, NewTaskNewTaskTTy};
- CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskEntry,
- OutlinedFnArgs);
- };
-
- // Build void __kmpc_omp_task_begin_if0(ident_t *, kmp_int32 gtid,
- // kmp_task_t *new_task);
- // Build void __kmpc_omp_task_complete_if0(ident_t *, kmp_int32 gtid,
- // kmp_task_t *new_task);
- RegionCodeGenTy RCG(CodeGen);
- CommonActionTy Action(
- RT.createRuntimeFunction(OMPRTL__kmpc_omp_task_begin_if0), TaskArgs,
- RT.createRuntimeFunction(OMPRTL__kmpc_omp_task_complete_if0), TaskArgs);
- RCG.setAction(Action);
- RCG(CGF);
- };
-
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen);
- } else {
- RegionCodeGenTy ThenRCG(ThenCodeGen);
- ThenRCG(CGF);
- }
-}
-
-void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPLoopDirective &D,
- llvm::Value *TaskFunction,
- QualType SharedsTy, Address Shareds,
- const Expr *IfCond,
- const OMPTaskDataTy &Data) {
- if (!CGF.HaveInsertPoint())
- return;
- TaskResultTy Result =
- emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
- // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
- // libcall.
- // Call to void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int
- // if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int
- // sched, kmp_uint64 grainsize, void *task_dup);
- llvm::Value *ThreadID = getThreadID(CGF, Loc);
- llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
- llvm::Value *IfVal;
- if (IfCond) {
- IfVal = CGF.Builder.CreateIntCast(CGF.EvaluateExprAsBool(IfCond), CGF.IntTy,
- /*isSigned=*/true);
- } else {
- IfVal = llvm::ConstantInt::getSigned(CGF.IntTy, /*V=*/1);
- }
-
- LValue LBLVal = CGF.EmitLValueForField(
- Result.TDBase,
- *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound));
- const auto *LBVar =
- cast<VarDecl>(cast<DeclRefExpr>(D.getLowerBoundVariable())->getDecl());
- CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(), LBLVal.getQuals(),
- /*IsInitializer=*/true);
- LValue UBLVal = CGF.EmitLValueForField(
- Result.TDBase,
- *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound));
- const auto *UBVar =
- cast<VarDecl>(cast<DeclRefExpr>(D.getUpperBoundVariable())->getDecl());
- CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(), UBLVal.getQuals(),
- /*IsInitializer=*/true);
- LValue StLVal = CGF.EmitLValueForField(
- Result.TDBase,
- *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTStride));
- const auto *StVar =
- cast<VarDecl>(cast<DeclRefExpr>(D.getStrideVariable())->getDecl());
- CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(),
- /*IsInitializer=*/true);
- // Store reductions address.
- LValue RedLVal = CGF.EmitLValueForField(
- Result.TDBase,
- *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTReductions));
- if (Data.Reductions) {
- CGF.EmitStoreOfScalar(Data.Reductions, RedLVal);
- } else {
- CGF.EmitNullInitialization(RedLVal.getAddress(),
- CGF.getContext().VoidPtrTy);
- }
- enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
- llvm::Value *TaskArgs[] = {
- UpLoc,
- ThreadID,
- Result.NewTask,
- IfVal,
- LBLVal.getPointer(),
- UBLVal.getPointer(),
- CGF.EmitLoadOfScalar(StLVal, Loc),
- llvm::ConstantInt::getSigned(
- CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler
- llvm::ConstantInt::getSigned(
- CGF.IntTy, Data.Schedule.getPointer()
- ? Data.Schedule.getInt() ? NumTasks : Grainsize
- : NoSchedule),
- Data.Schedule.getPointer()
- ? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty,
- /*isSigned=*/false)
- : llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0),
- Result.TaskDupFn ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- Result.TaskDupFn, CGF.VoidPtrTy)
- : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_taskloop), TaskArgs);
-}
-
-/// Emit reduction operation for each element of array (required for
-/// array sections) LHS op = RHS.
-/// \param Type Type of array.
-/// \param LHSVar Variable on the left side of the reduction operation
-/// (references element of array in original variable).
-/// \param RHSVar Variable on the right side of the reduction operation
-/// (references element of array in original variable).
-/// \param RedOpGen Generator of reduction operation with use of LHSVar and
-/// RHSVar.
-static void EmitOMPAggregateReduction(
- CodeGenFunction &CGF, QualType Type, const VarDecl *LHSVar,
- const VarDecl *RHSVar,
- const llvm::function_ref<void(CodeGenFunction &CGF, const Expr *,
- const Expr *, const Expr *)> &RedOpGen,
- const Expr *XExpr = nullptr, const Expr *EExpr = nullptr,
- const Expr *UpExpr = nullptr) {
- // Perform element-by-element initialization.
- QualType ElementTy;
- Address LHSAddr = CGF.GetAddrOfLocalVar(LHSVar);
- Address RHSAddr = CGF.GetAddrOfLocalVar(RHSVar);
-
- // Drill down to the base element type on both arrays.
- const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
- llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, LHSAddr);
-
- llvm::Value *RHSBegin = RHSAddr.getPointer();
- llvm::Value *LHSBegin = LHSAddr.getPointer();
- // Cast from pointer to array type to pointer to single element.
- llvm::Value *LHSEnd = CGF.Builder.CreateGEP(LHSBegin, NumElements);
- // The basic structure here is a while-do loop.
- llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arraycpy.body");
- llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arraycpy.done");
- llvm::Value *IsEmpty =
- CGF.Builder.CreateICmpEQ(LHSBegin, LHSEnd, "omp.arraycpy.isempty");
- CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
-
- // Enter the loop body, making that address the current address.
- llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(BodyBB);
-
- CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
-
- llvm::PHINode *RHSElementPHI = CGF.Builder.CreatePHI(
- RHSBegin->getType(), 2, "omp.arraycpy.srcElementPast");
- RHSElementPHI->addIncoming(RHSBegin, EntryBB);
- Address RHSElementCurrent =
- Address(RHSElementPHI,
- RHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
-
- llvm::PHINode *LHSElementPHI = CGF.Builder.CreatePHI(
- LHSBegin->getType(), 2, "omp.arraycpy.destElementPast");
- LHSElementPHI->addIncoming(LHSBegin, EntryBB);
- Address LHSElementCurrent =
- Address(LHSElementPHI,
- LHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
-
- // Emit copy.
- CodeGenFunction::OMPPrivateScope Scope(CGF);
- Scope.addPrivate(LHSVar, [=]() { return LHSElementCurrent; });
- Scope.addPrivate(RHSVar, [=]() { return RHSElementCurrent; });
- Scope.Privatize();
- RedOpGen(CGF, XExpr, EExpr, UpExpr);
- Scope.ForceCleanup();
-
- // Shift the address forward by one element.
- llvm::Value *LHSElementNext = CGF.Builder.CreateConstGEP1_32(
- LHSElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- llvm::Value *RHSElementNext = CGF.Builder.CreateConstGEP1_32(
- RHSElementPHI, /*Idx0=*/1, "omp.arraycpy.src.element");
- // Check whether we've reached the end.
- llvm::Value *Done =
- CGF.Builder.CreateICmpEQ(LHSElementNext, LHSEnd, "omp.arraycpy.done");
- CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
- LHSElementPHI->addIncoming(LHSElementNext, CGF.Builder.GetInsertBlock());
- RHSElementPHI->addIncoming(RHSElementNext, CGF.Builder.GetInsertBlock());
-
- // Done.
- CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
-/// Emit reduction combiner. If the combiner is a simple expression emit it as
-/// is, otherwise consider it as combiner of UDR decl and emit it as a call of
-/// UDR combiner function.
-static void emitReductionCombiner(CodeGenFunction &CGF,
- const Expr *ReductionOp) {
- if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
- if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
- if (const auto *DRE =
- dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
- if (const auto *DRD =
- dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl())) {
- std::pair<llvm::Function *, llvm::Function *> Reduction =
- CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
- RValue Func = RValue::get(Reduction.first);
- CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
- CGF.EmitIgnoredExpr(ReductionOp);
- return;
- }
- CGF.EmitIgnoredExpr(ReductionOp);
-}
-
-llvm::Value *CGOpenMPRuntime::emitReductionFunction(
- CodeGenModule &CGM, SourceLocation Loc, llvm::Type *ArgsType,
- ArrayRef<const Expr *> Privates, ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs, ArrayRef<const Expr *> ReductionOps) {
- ASTContext &C = CGM.getContext();
-
- // void reduction_func(void *LHSArg, void *RHSArg);
- FunctionArgList Args;
- ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
- ImplicitParamDecl::Other);
- ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.push_back(&LHSArg);
- Args.push_back(&RHSArg);
- const auto &CGFI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- std::string Name = getName({"omp", "reduction", "reduction_func"});
- auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
- llvm::GlobalValue::InternalLinkage, Name,
- &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
- Fn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
-
- // Dst = (void*[n])(LHSArg);
- // Src = (void*[n])(RHSArg);
- Address LHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&LHSArg)),
- ArgsType), CGF.getPointerAlign());
- Address RHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&RHSArg)),
- ArgsType), CGF.getPointerAlign());
-
- // ...
- // *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
- // ...
- CodeGenFunction::OMPPrivateScope Scope(CGF);
- auto IPriv = Privates.begin();
- unsigned Idx = 0;
- for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I, ++IPriv, ++Idx) {
- const auto *RHSVar =
- cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl());
- Scope.addPrivate(RHSVar, [&CGF, RHS, Idx, RHSVar]() {
- return emitAddrOfVarFromArray(CGF, RHS, Idx, RHSVar);
- });
- const auto *LHSVar =
- cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl());
- Scope.addPrivate(LHSVar, [&CGF, LHS, Idx, LHSVar]() {
- return emitAddrOfVarFromArray(CGF, LHS, Idx, LHSVar);
- });
- QualType PrivTy = (*IPriv)->getType();
- if (PrivTy->isVariablyModifiedType()) {
- // Get array size and emit VLA type.
- ++Idx;
- Address Elem =
- CGF.Builder.CreateConstArrayGEP(LHS, Idx, CGF.getPointerSize());
- llvm::Value *Ptr = CGF.Builder.CreateLoad(Elem);
- const VariableArrayType *VLA =
- CGF.getContext().getAsVariableArrayType(PrivTy);
- const auto *OVE = cast<OpaqueValueExpr>(VLA->getSizeExpr());
- CodeGenFunction::OpaqueValueMapping OpaqueMap(
- CGF, OVE, RValue::get(CGF.Builder.CreatePtrToInt(Ptr, CGF.SizeTy)));
- CGF.EmitVariablyModifiedType(PrivTy);
- }
- }
- Scope.Privatize();
- IPriv = Privates.begin();
- auto ILHS = LHSExprs.begin();
- auto IRHS = RHSExprs.begin();
- for (const Expr *E : ReductionOps) {
- if ((*IPriv)->getType()->isArrayType()) {
- // Emit reduction for array section.
- const auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
- const auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
- EmitOMPAggregateReduction(
- CGF, (*IPriv)->getType(), LHSVar, RHSVar,
- [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
- emitReductionCombiner(CGF, E);
- });
- } else {
- // Emit reduction for array subscript or single variable.
- emitReductionCombiner(CGF, E);
- }
- ++IPriv;
- ++ILHS;
- ++IRHS;
- }
- Scope.ForceCleanup();
- CGF.FinishFunction();
- return Fn;
-}
-
-void CGOpenMPRuntime::emitSingleReductionCombiner(CodeGenFunction &CGF,
- const Expr *ReductionOp,
- const Expr *PrivateRef,
- const DeclRefExpr *LHS,
- const DeclRefExpr *RHS) {
- if (PrivateRef->getType()->isArrayType()) {
- // Emit reduction for array section.
- const auto *LHSVar = cast<VarDecl>(LHS->getDecl());
- const auto *RHSVar = cast<VarDecl>(RHS->getDecl());
- EmitOMPAggregateReduction(
- CGF, PrivateRef->getType(), LHSVar, RHSVar,
- [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
- emitReductionCombiner(CGF, ReductionOp);
- });
- } else {
- // Emit reduction for array subscript or single variable.
- emitReductionCombiner(CGF, ReductionOp);
- }
-}
-
-void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps,
- ReductionOptionsTy Options) {
- if (!CGF.HaveInsertPoint())
- return;
-
- bool WithNowait = Options.WithNowait;
- bool SimpleReduction = Options.SimpleReduction;
-
- // Next code should be emitted for reduction:
- //
- // static kmp_critical_name lock = { 0 };
- //
- // void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
- // *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
- // ...
- // *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
- // *(Type<n>-1*)rhs[<n>-1]);
- // }
- //
- // ...
- // void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
- // switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
- // RedList, reduce_func, &<lock>)) {
- // case 1:
- // ...
- // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
- // ...
- // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
- // break;
- // case 2:
- // ...
- // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
- // ...
- // [__kmpc_end_reduce(<loc>, <gtid>, &<lock>);]
- // break;
- // default:;
- // }
- //
- // if SimpleReduction is true, only the next code is generated:
- // ...
- // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
- // ...
-
- ASTContext &C = CGM.getContext();
-
- if (SimpleReduction) {
- CodeGenFunction::RunCleanupsScope Scope(CGF);
- auto IPriv = Privates.begin();
- auto ILHS = LHSExprs.begin();
- auto IRHS = RHSExprs.begin();
- for (const Expr *E : ReductionOps) {
- emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
- cast<DeclRefExpr>(*IRHS));
- ++IPriv;
- ++ILHS;
- ++IRHS;
- }
- return;
- }
-
- // 1. Build a list of reduction variables.
- // void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
- auto Size = RHSExprs.size();
- for (const Expr *E : Privates) {
- if (E->getType()->isVariablyModifiedType())
- // Reserve place for array size.
- ++Size;
- }
- llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
- QualType ReductionArrayTy =
- C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- Address ReductionList =
- CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
- auto IPriv = Privates.begin();
- unsigned Idx = 0;
- for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) {
- Address Elem =
- CGF.Builder.CreateConstArrayGEP(ReductionList, Idx, CGF.getPointerSize());
- CGF.Builder.CreateStore(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy),
- Elem);
- if ((*IPriv)->getType()->isVariablyModifiedType()) {
- // Store array size.
- ++Idx;
- Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx,
- CGF.getPointerSize());
- llvm::Value *Size = CGF.Builder.CreateIntCast(
- CGF.getVLASize(
- CGF.getContext().getAsVariableArrayType((*IPriv)->getType()))
- .NumElts,
- CGF.SizeTy, /*isSigned=*/false);
- CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy),
- Elem);
- }
- }
-
- // 2. Emit reduce_func().
- llvm::Value *ReductionFn = emitReductionFunction(
- CGM, Loc, CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo(),
- Privates, LHSExprs, RHSExprs, ReductionOps);
-
- // 3. Create static kmp_critical_name lock = { 0 };
- std::string Name = getName({"reduction"});
- llvm::Value *Lock = getCriticalRegionLock(Name);
-
- // 4. Build res = __kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
- // RedList, reduce_func, &<lock>);
- llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE);
- llvm::Value *ThreadId = getThreadID(CGF, Loc);
- llvm::Value *ReductionArrayTySize = CGF.getTypeSize(ReductionArrayTy);
- llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- ReductionList.getPointer(), CGF.VoidPtrTy);
- llvm::Value *Args[] = {
- IdentTLoc, // ident_t *<loc>
- ThreadId, // i32 <gtid>
- CGF.Builder.getInt32(RHSExprs.size()), // i32 <n>
- ReductionArrayTySize, // size_type sizeof(RedList)
- RL, // void *RedList
- ReductionFn, // void (*) (void *, void *) <reduce_func>
- Lock // kmp_critical_name *&<lock>
- };
- llvm::Value *Res = CGF.EmitRuntimeCall(
- createRuntimeFunction(WithNowait ? OMPRTL__kmpc_reduce_nowait
- : OMPRTL__kmpc_reduce),
- Args);
-
- // 5. Build switch(res)
- llvm::BasicBlock *DefaultBB = CGF.createBasicBlock(".omp.reduction.default");
- llvm::SwitchInst *SwInst =
- CGF.Builder.CreateSwitch(Res, DefaultBB, /*NumCases=*/2);
-
- // 6. Build case 1:
- // ...
- // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
- // ...
- // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
- // break;
- llvm::BasicBlock *Case1BB = CGF.createBasicBlock(".omp.reduction.case1");
- SwInst->addCase(CGF.Builder.getInt32(1), Case1BB);
- CGF.EmitBlock(Case1BB);
-
- // Add emission of __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
- llvm::Value *EndArgs[] = {
- IdentTLoc, // ident_t *<loc>
- ThreadId, // i32 <gtid>
- Lock // kmp_critical_name *&<lock>
- };
- auto &&CodeGen = [Privates, LHSExprs, RHSExprs, ReductionOps](
- CodeGenFunction &CGF, PrePostActionTy &Action) {
- CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
- auto IPriv = Privates.begin();
- auto ILHS = LHSExprs.begin();
- auto IRHS = RHSExprs.begin();
- for (const Expr *E : ReductionOps) {
- RT.emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
- cast<DeclRefExpr>(*IRHS));
- ++IPriv;
- ++ILHS;
- ++IRHS;
- }
- };
- RegionCodeGenTy RCG(CodeGen);
- CommonActionTy Action(
- nullptr, llvm::None,
- createRuntimeFunction(WithNowait ? OMPRTL__kmpc_end_reduce_nowait
- : OMPRTL__kmpc_end_reduce),
- EndArgs);
- RCG.setAction(Action);
- RCG(CGF);
-
- CGF.EmitBranch(DefaultBB);
-
- // 7. Build case 2:
- // ...
- // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
- // ...
- // break;
- llvm::BasicBlock *Case2BB = CGF.createBasicBlock(".omp.reduction.case2");
- SwInst->addCase(CGF.Builder.getInt32(2), Case2BB);
- CGF.EmitBlock(Case2BB);
-
- auto &&AtomicCodeGen = [Loc, Privates, LHSExprs, RHSExprs, ReductionOps](
- CodeGenFunction &CGF, PrePostActionTy &Action) {
- auto ILHS = LHSExprs.begin();
- auto IRHS = RHSExprs.begin();
- auto IPriv = Privates.begin();
- for (const Expr *E : ReductionOps) {
- const Expr *XExpr = nullptr;
- const Expr *EExpr = nullptr;
- const Expr *UpExpr = nullptr;
- BinaryOperatorKind BO = BO_Comma;
- if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
- if (BO->getOpcode() == BO_Assign) {
- XExpr = BO->getLHS();
- UpExpr = BO->getRHS();
- }
- }
- // Try to emit update expression as a simple atomic.
- const Expr *RHSExpr = UpExpr;
- if (RHSExpr) {
- // Analyze RHS part of the whole expression.
- if (const auto *ACO = dyn_cast<AbstractConditionalOperator>(
- RHSExpr->IgnoreParenImpCasts())) {
- // If this is a conditional operator, analyze its condition for
- // min/max reduction operator.
- RHSExpr = ACO->getCond();
- }
- if (const auto *BORHS =
- dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) {
- EExpr = BORHS->getRHS();
- BO = BORHS->getOpcode();
- }
- }
- if (XExpr) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
- auto &&AtomicRedGen = [BO, VD,
- Loc](CodeGenFunction &CGF, const Expr *XExpr,
- const Expr *EExpr, const Expr *UpExpr) {
- LValue X = CGF.EmitLValue(XExpr);
- RValue E;
- if (EExpr)
- E = CGF.EmitAnyExpr(EExpr);
- CGF.EmitOMPAtomicSimpleUpdateExpr(
- X, E, BO, /*IsXLHSInRHSPart=*/true,
- llvm::AtomicOrdering::Monotonic, Loc,
- [&CGF, UpExpr, VD, Loc](RValue XRValue) {
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- PrivateScope.addPrivate(
- VD, [&CGF, VD, XRValue, Loc]() {
- Address LHSTemp = CGF.CreateMemTemp(VD->getType());
- CGF.emitOMPSimpleStore(
- CGF.MakeAddrLValue(LHSTemp, VD->getType()), XRValue,
- VD->getType().getNonReferenceType(), Loc);
- return LHSTemp;
- });
- (void)PrivateScope.Privatize();
- return CGF.EmitAnyExpr(UpExpr);
- });
- };
- if ((*IPriv)->getType()->isArrayType()) {
- // Emit atomic reduction for array section.
- const auto *RHSVar =
- cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
- EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), VD, RHSVar,
- AtomicRedGen, XExpr, EExpr, UpExpr);
- } else {
- // Emit atomic reduction for array subscript or single variable.
- AtomicRedGen(CGF, XExpr, EExpr, UpExpr);
- }
- } else {
- // Emit as a critical region.
- auto &&CritRedGen = [E, Loc](CodeGenFunction &CGF, const Expr *,
- const Expr *, const Expr *) {
- CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
- std::string Name = RT.getName({"atomic_reduction"});
- RT.emitCriticalRegion(
- CGF, Name,
- [=](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- emitReductionCombiner(CGF, E);
- },
- Loc);
- };
- if ((*IPriv)->getType()->isArrayType()) {
- const auto *LHSVar =
- cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
- const auto *RHSVar =
- cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
- EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), LHSVar, RHSVar,
- CritRedGen);
- } else {
- CritRedGen(CGF, nullptr, nullptr, nullptr);
- }
- }
- ++ILHS;
- ++IRHS;
- ++IPriv;
- }
- };
- RegionCodeGenTy AtomicRCG(AtomicCodeGen);
- if (!WithNowait) {
- // Add emission of __kmpc_end_reduce(<loc>, <gtid>, &<lock>);
- llvm::Value *EndArgs[] = {
- IdentTLoc, // ident_t *<loc>
- ThreadId, // i32 <gtid>
- Lock // kmp_critical_name *&<lock>
- };
- CommonActionTy Action(nullptr, llvm::None,
- createRuntimeFunction(OMPRTL__kmpc_end_reduce),
- EndArgs);
- AtomicRCG.setAction(Action);
- AtomicRCG(CGF);
- } else {
- AtomicRCG(CGF);
- }
-
- CGF.EmitBranch(DefaultBB);
- CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
-}
-
-/// Generates unique name for artificial threadprivate variables.
-/// Format is: <Prefix> "." <Decl_mangled_name> "_" "<Decl_start_loc_raw_enc>"
-static std::string generateUniqueName(CodeGenModule &CGM, StringRef Prefix,
- const Expr *Ref) {
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- const clang::DeclRefExpr *DE;
- const VarDecl *D = ::getBaseDecl(Ref, DE);
- if (!D)
- D = cast<VarDecl>(cast<DeclRefExpr>(Ref)->getDecl());
- D = D->getCanonicalDecl();
- std::string Name = CGM.getOpenMPRuntime().getName(
- {D->isLocalVarDeclOrParm() ? D->getName() : CGM.getMangledName(D)});
- Out << Prefix << Name << "_"
- << D->getCanonicalDecl()->getBeginLoc().getRawEncoding();
- return Out.str();
-}
-
-/// Emits reduction initializer function:
-/// \code
-/// void @.red_init(void* %arg) {
-/// %0 = bitcast void* %arg to <type>*
-/// store <type> <init>, <type>* %0
-/// ret void
-/// }
-/// \endcode
-static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM,
- SourceLocation Loc,
- ReductionCodeGen &RCG, unsigned N) {
- ASTContext &C = CGM.getContext();
- FunctionArgList Args;
- ImplicitParamDecl Param(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.emplace_back(&Param);
- const auto &FnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
- std::string Name = CGM.getOpenMPRuntime().getName({"red_init", ""});
- auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
- Name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
- Fn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
- Address PrivateAddr = CGF.EmitLoadOfPointer(
- CGF.GetAddrOfLocalVar(&Param),
- C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
- llvm::Value *Size = nullptr;
- // If the size of the reduction item is non-constant, load it from global
- // threadprivate variable.
- if (RCG.getSizes(N).second) {
- Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
- CGF, CGM.getContext().getSizeType(),
- generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
- Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
- CGM.getContext().getSizeType(), Loc);
- }
- RCG.emitAggregateType(CGF, N, Size);
- LValue SharedLVal;
- // If initializer uses initializer from declare reduction construct, emit a
- // pointer to the address of the original reduction item (reuired by reduction
- // initializer)
- if (RCG.usesReductionInitializer(N)) {
- Address SharedAddr =
- CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
- CGF, CGM.getContext().VoidPtrTy,
- generateUniqueName(CGM, "reduction", RCG.getRefExpr(N)));
- SharedAddr = CGF.EmitLoadOfPointer(
- SharedAddr,
- CGM.getContext().VoidPtrTy.castAs<PointerType>()->getTypePtr());
- SharedLVal = CGF.MakeAddrLValue(SharedAddr, CGM.getContext().VoidPtrTy);
- } else {
- SharedLVal = CGF.MakeNaturalAlignAddrLValue(
- llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
- CGM.getContext().VoidPtrTy);
- }
- // Emit the initializer:
- // %0 = bitcast void* %arg to <type>*
- // store <type> <init>, <type>* %0
- RCG.emitInitialization(CGF, N, PrivateAddr, SharedLVal,
- [](CodeGenFunction &) { return false; });
- CGF.FinishFunction();
- return Fn;
-}
-
-/// Emits reduction combiner function:
-/// \code
-/// void @.red_comb(void* %arg0, void* %arg1) {
-/// %lhs = bitcast void* %arg0 to <type>*
-/// %rhs = bitcast void* %arg1 to <type>*
-/// %2 = <ReductionOp>(<type>* %lhs, <type>* %rhs)
-/// store <type> %2, <type>* %lhs
-/// ret void
-/// }
-/// \endcode
-static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM,
- SourceLocation Loc,
- ReductionCodeGen &RCG, unsigned N,
- const Expr *ReductionOp,
- const Expr *LHS, const Expr *RHS,
- const Expr *PrivateRef) {
- ASTContext &C = CGM.getContext();
- const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(LHS)->getDecl());
- const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(RHS)->getDecl());
- FunctionArgList Args;
- ImplicitParamDecl ParamInOut(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.VoidPtrTy, ImplicitParamDecl::Other);
- ImplicitParamDecl ParamIn(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.emplace_back(&ParamInOut);
- Args.emplace_back(&ParamIn);
- const auto &FnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
- std::string Name = CGM.getOpenMPRuntime().getName({"red_comb", ""});
- auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
- Name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
- Fn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
- llvm::Value *Size = nullptr;
- // If the size of the reduction item is non-constant, load it from global
- // threadprivate variable.
- if (RCG.getSizes(N).second) {
- Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
- CGF, CGM.getContext().getSizeType(),
- generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
- Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
- CGM.getContext().getSizeType(), Loc);
- }
- RCG.emitAggregateType(CGF, N, Size);
- // Remap lhs and rhs variables to the addresses of the function arguments.
- // %lhs = bitcast void* %arg0 to <type>*
- // %rhs = bitcast void* %arg1 to <type>*
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- PrivateScope.addPrivate(LHSVD, [&C, &CGF, &ParamInOut, LHSVD]() {
- // Pull out the pointer to the variable.
- Address PtrAddr = CGF.EmitLoadOfPointer(
- CGF.GetAddrOfLocalVar(&ParamInOut),
- C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
- return CGF.Builder.CreateElementBitCast(
- PtrAddr, CGF.ConvertTypeForMem(LHSVD->getType()));
- });
- PrivateScope.addPrivate(RHSVD, [&C, &CGF, &ParamIn, RHSVD]() {
- // Pull out the pointer to the variable.
- Address PtrAddr = CGF.EmitLoadOfPointer(
- CGF.GetAddrOfLocalVar(&ParamIn),
- C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
- return CGF.Builder.CreateElementBitCast(
- PtrAddr, CGF.ConvertTypeForMem(RHSVD->getType()));
- });
- PrivateScope.Privatize();
- // Emit the combiner body:
- // %2 = <ReductionOp>(<type> *%lhs, <type> *%rhs)
- // store <type> %2, <type>* %lhs
- CGM.getOpenMPRuntime().emitSingleReductionCombiner(
- CGF, ReductionOp, PrivateRef, cast<DeclRefExpr>(LHS),
- cast<DeclRefExpr>(RHS));
- CGF.FinishFunction();
- return Fn;
-}
-
-/// Emits reduction finalizer function:
-/// \code
-/// void @.red_fini(void* %arg) {
-/// %0 = bitcast void* %arg to <type>*
-/// <destroy>(<type>* %0)
-/// ret void
-/// }
-/// \endcode
-static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM,
- SourceLocation Loc,
- ReductionCodeGen &RCG, unsigned N) {
- if (!RCG.needCleanups(N))
- return nullptr;
- ASTContext &C = CGM.getContext();
- FunctionArgList Args;
- ImplicitParamDecl Param(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
- ImplicitParamDecl::Other);
- Args.emplace_back(&Param);
- const auto &FnInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
- std::string Name = CGM.getOpenMPRuntime().getName({"red_fini", ""});
- auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
- Name, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
- Fn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
- Address PrivateAddr = CGF.EmitLoadOfPointer(
- CGF.GetAddrOfLocalVar(&Param),
- C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
- llvm::Value *Size = nullptr;
- // If the size of the reduction item is non-constant, load it from global
- // threadprivate variable.
- if (RCG.getSizes(N).second) {
- Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
- CGF, CGM.getContext().getSizeType(),
- generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
- Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
- CGM.getContext().getSizeType(), Loc);
- }
- RCG.emitAggregateType(CGF, N, Size);
- // Emit the finalizer body:
- // <destroy>(<type>* %0)
- RCG.emitCleanups(CGF, N, PrivateAddr);
- CGF.FinishFunction();
- return Fn;
-}
-
-llvm::Value *CGOpenMPRuntime::emitTaskReductionInit(
- CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
- if (!CGF.HaveInsertPoint() || Data.ReductionVars.empty())
- return nullptr;
-
- // Build typedef struct:
- // kmp_task_red_input {
- // void *reduce_shar; // shared reduction item
- // size_t reduce_size; // size of data item
- // void *reduce_init; // data initialization routine
- // void *reduce_fini; // data finalization routine
- // void *reduce_comb; // data combiner routine
- // kmp_task_red_flags_t flags; // flags for additional info from compiler
- // } kmp_task_red_input_t;
- ASTContext &C = CGM.getContext();
- RecordDecl *RD = C.buildImplicitRecord("kmp_task_red_input_t");
- RD->startDefinition();
- const FieldDecl *SharedFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- const FieldDecl *SizeFD = addFieldToRecordDecl(C, RD, C.getSizeType());
- const FieldDecl *InitFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- const FieldDecl *FiniFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- const FieldDecl *CombFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
- const FieldDecl *FlagsFD = addFieldToRecordDecl(
- C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false));
- RD->completeDefinition();
- QualType RDType = C.getRecordType(RD);
- unsigned Size = Data.ReductionVars.size();
- llvm::APInt ArraySize(/*numBits=*/64, Size);
- QualType ArrayRDType = C.getConstantArrayType(
- RDType, ArraySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
- // kmp_task_red_input_t .rd_input.[Size];
- Address TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input.");
- ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionCopies,
- Data.ReductionOps);
- for (unsigned Cnt = 0; Cnt < Size; ++Cnt) {
- // kmp_task_red_input_t &ElemLVal = .rd_input.[Cnt];
- llvm::Value *Idxs[] = {llvm::ConstantInt::get(CGM.SizeTy, /*V=*/0),
- llvm::ConstantInt::get(CGM.SizeTy, Cnt)};
- llvm::Value *GEP = CGF.EmitCheckedInBoundsGEP(
- TaskRedInput.getPointer(), Idxs,
- /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc,
- ".rd_input.gep.");
- LValue ElemLVal = CGF.MakeNaturalAlignAddrLValue(GEP, RDType);
- // ElemLVal.reduce_shar = &Shareds[Cnt];
- LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD);
- RCG.emitSharedLValue(CGF, Cnt);
- llvm::Value *CastedShared =
- CGF.EmitCastToVoidPtr(RCG.getSharedLValue(Cnt).getPointer());
- CGF.EmitStoreOfScalar(CastedShared, SharedLVal);
- RCG.emitAggregateType(CGF, Cnt);
- llvm::Value *SizeValInChars;
- llvm::Value *SizeVal;
- std::tie(SizeValInChars, SizeVal) = RCG.getSizes(Cnt);
- // We use delayed creation/initialization for VLAs, array sections and
- // custom reduction initializations. It is required because runtime does not
- // provide the way to pass the sizes of VLAs/array sections to
- // initializer/combiner/finalizer functions and does not pass the pointer to
- // original reduction item to the initializer. Instead threadprivate global
- // variables are used to store these values and use them in the functions.
- bool DelayedCreation = !!SizeVal;
- SizeValInChars = CGF.Builder.CreateIntCast(SizeValInChars, CGM.SizeTy,
- /*isSigned=*/false);
- LValue SizeLVal = CGF.EmitLValueForField(ElemLVal, SizeFD);
- CGF.EmitStoreOfScalar(SizeValInChars, SizeLVal);
- // ElemLVal.reduce_init = init;
- LValue InitLVal = CGF.EmitLValueForField(ElemLVal, InitFD);
- llvm::Value *InitAddr =
- CGF.EmitCastToVoidPtr(emitReduceInitFunction(CGM, Loc, RCG, Cnt));
- CGF.EmitStoreOfScalar(InitAddr, InitLVal);
- DelayedCreation = DelayedCreation || RCG.usesReductionInitializer(Cnt);
- // ElemLVal.reduce_fini = fini;
- LValue FiniLVal = CGF.EmitLValueForField(ElemLVal, FiniFD);
- llvm::Value *Fini = emitReduceFiniFunction(CGM, Loc, RCG, Cnt);
- llvm::Value *FiniAddr = Fini
- ? CGF.EmitCastToVoidPtr(Fini)
- : llvm::ConstantPointerNull::get(CGM.VoidPtrTy);
- CGF.EmitStoreOfScalar(FiniAddr, FiniLVal);
- // ElemLVal.reduce_comb = comb;
- LValue CombLVal = CGF.EmitLValueForField(ElemLVal, CombFD);
- llvm::Value *CombAddr = CGF.EmitCastToVoidPtr(emitReduceCombFunction(
- CGM, Loc, RCG, Cnt, Data.ReductionOps[Cnt], LHSExprs[Cnt],
- RHSExprs[Cnt], Data.ReductionCopies[Cnt]));
- CGF.EmitStoreOfScalar(CombAddr, CombLVal);
- // ElemLVal.flags = 0;
- LValue FlagsLVal = CGF.EmitLValueForField(ElemLVal, FlagsFD);
- if (DelayedCreation) {
- CGF.EmitStoreOfScalar(
- llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*IsSigned=*/true),
- FlagsLVal);
- } else
- CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType());
- }
- // Build call void *__kmpc_task_reduction_init(int gtid, int num_data, void
- // *data);
- llvm::Value *Args[] = {
- CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
- /*isSigned=*/true),
- llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TaskRedInput.getPointer(),
- CGM.VoidPtrTy)};
- return CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_task_reduction_init), Args);
-}
-
-void CGOpenMPRuntime::emitTaskReductionFixups(CodeGenFunction &CGF,
- SourceLocation Loc,
- ReductionCodeGen &RCG,
- unsigned N) {
- auto Sizes = RCG.getSizes(N);
- // Emit threadprivate global variable if the type is non-constant
- // (Sizes.second = nullptr).
- if (Sizes.second) {
- llvm::Value *SizeVal = CGF.Builder.CreateIntCast(Sizes.second, CGM.SizeTy,
- /*isSigned=*/false);
- Address SizeAddr = getAddrOfArtificialThreadPrivate(
- CGF, CGM.getContext().getSizeType(),
- generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
- CGF.Builder.CreateStore(SizeVal, SizeAddr, /*IsVolatile=*/false);
- }
- // Store address of the original reduction item if custom initializer is used.
- if (RCG.usesReductionInitializer(N)) {
- Address SharedAddr = getAddrOfArtificialThreadPrivate(
- CGF, CGM.getContext().VoidPtrTy,
- generateUniqueName(CGM, "reduction", RCG.getRefExpr(N)));
- CGF.Builder.CreateStore(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- RCG.getSharedLValue(N).getPointer(), CGM.VoidPtrTy),
- SharedAddr, /*IsVolatile=*/false);
- }
-}
-
-Address CGOpenMPRuntime::getTaskReductionItem(CodeGenFunction &CGF,
- SourceLocation Loc,
- llvm::Value *ReductionsPtr,
- LValue SharedLVal) {
- // Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
- // *d);
- llvm::Value *Args[] = {
- CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
- /*isSigned=*/true),
- ReductionsPtr,
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(SharedLVal.getPointer(),
- CGM.VoidPtrTy)};
- return Address(
- CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_task_reduction_get_th_data), Args),
- SharedLVal.getAlignment());
-}
-
-void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
- // Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32
- // global_tid);
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
- // Ignore return result until untied tasks are supported.
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_taskwait), Args);
- if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
- Region->emitUntiedSwitch(CGF);
-}
-
-void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF,
- OpenMPDirectiveKind InnerKind,
- const RegionCodeGenTy &CodeGen,
- bool HasCancel) {
- if (!CGF.HaveInsertPoint())
- return;
- InlinedOpenMPRegionRAII Region(CGF, CodeGen, InnerKind, HasCancel);
- CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
-}
-
-namespace {
-enum RTCancelKind {
- CancelNoreq = 0,
- CancelParallel = 1,
- CancelLoop = 2,
- CancelSections = 3,
- CancelTaskgroup = 4
-};
-} // anonymous namespace
-
-static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion) {
- RTCancelKind CancelKind = CancelNoreq;
- if (CancelRegion == OMPD_parallel)
- CancelKind = CancelParallel;
- else if (CancelRegion == OMPD_for)
- CancelKind = CancelLoop;
- else if (CancelRegion == OMPD_sections)
- CancelKind = CancelSections;
- else {
- assert(CancelRegion == OMPD_taskgroup);
- CancelKind = CancelTaskgroup;
- }
- return CancelKind;
-}
-
-void CGOpenMPRuntime::emitCancellationPointCall(
- CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind CancelRegion) {
- if (!CGF.HaveInsertPoint())
- return;
- // Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
- // global_tid, kmp_int32 cncl_kind);
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- // For 'cancellation point taskgroup', the task region info may not have a
- // cancel. This may instead happen in another adjacent task.
- if (CancelRegion == OMPD_taskgroup || OMPRegionInfo->hasCancel()) {
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
- // Ignore return result until untied tasks are supported.
- llvm::Value *Result = CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_cancellationpoint), Args);
- // if (__kmpc_cancellationpoint()) {
- // exit from construct;
- // }
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
- llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
- llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
- CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
- CGF.EmitBlock(ExitBB);
- // exit from construct;
- CodeGenFunction::JumpDest CancelDest =
- CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
- CGF.EmitBranchThroughCleanup(CancelDest);
- CGF.EmitBlock(ContBB, /*IsFinished=*/true);
- }
- }
-}
-
-void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
- const Expr *IfCond,
- OpenMPDirectiveKind CancelRegion) {
- if (!CGF.HaveInsertPoint())
- return;
- // Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
- // kmp_int32 cncl_kind);
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- auto &&ThenGen = [Loc, CancelRegion, OMPRegionInfo](CodeGenFunction &CGF,
- PrePostActionTy &) {
- CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
- llvm::Value *Args[] = {
- RT.emitUpdateLocation(CGF, Loc), RT.getThreadID(CGF, Loc),
- CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
- // Ignore return result until untied tasks are supported.
- llvm::Value *Result = CGF.EmitRuntimeCall(
- RT.createRuntimeFunction(OMPRTL__kmpc_cancel), Args);
- // if (__kmpc_cancel()) {
- // exit from construct;
- // }
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
- llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
- llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
- CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
- CGF.EmitBlock(ExitBB);
- // exit from construct;
- CodeGenFunction::JumpDest CancelDest =
- CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
- CGF.EmitBranchThroughCleanup(CancelDest);
- CGF.EmitBlock(ContBB, /*IsFinished=*/true);
- };
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, ThenGen,
- [](CodeGenFunction &, PrePostActionTy &) {});
- } else {
- RegionCodeGenTy ThenRCG(ThenGen);
- ThenRCG(CGF);
- }
- }
-}
-
-void CGOpenMPRuntime::emitTargetOutlinedFunction(
- const OMPExecutableDirective &D, StringRef ParentName,
- llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
- assert(!ParentName.empty() && "Invalid target region parent name!");
- emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
- IsOffloadEntry, CodeGen);
-}
-
-void CGOpenMPRuntime::emitTargetOutlinedFunctionHelper(
- const OMPExecutableDirective &D, StringRef ParentName,
- llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
- // Create a unique name for the entry function using the source location
- // information of the current target region. The name will be something like:
- //
- // __omp_offloading_DD_FFFF_PP_lBB
- //
- // where DD_FFFF is an ID unique to the file (device and file IDs), PP is the
- // mangled name of the function that encloses the target region and BB is the
- // line number of the target region.
-
- unsigned DeviceID;
- unsigned FileID;
- unsigned Line;
- getTargetEntryUniqueInfo(CGM.getContext(), D.getBeginLoc(), DeviceID, FileID,
- Line);
- SmallString<64> EntryFnName;
- {
- llvm::raw_svector_ostream OS(EntryFnName);
- OS << "__omp_offloading" << llvm::format("_%x", DeviceID)
- << llvm::format("_%x_", FileID) << ParentName << "_l" << Line;
- }
-
- const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
-
- CodeGenFunction CGF(CGM, true);
- CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName);
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
-
- OutlinedFn = CGF.GenerateOpenMPCapturedStmtFunction(CS);
-
- // If this target outline function is not an offload entry, we don't need to
- // register it.
- if (!IsOffloadEntry)
- return;
-
- // The target region ID is used by the runtime library to identify the current
- // target region, so it only has to be unique and not necessarily point to
- // anything. It could be the pointer to the outlined function that implements
- // the target region, but we aren't using that so that the compiler doesn't
- // need to keep that, and could therefore inline the host function if proven
- // worthwhile during optimization. In the other hand, if emitting code for the
- // device, the ID has to be the function address so that it can retrieved from
- // the offloading entry and launched by the runtime library. We also mark the
- // outlined function to have external linkage in case we are emitting code for
- // the device, because these functions will be entry points to the device.
-
- if (CGM.getLangOpts().OpenMPIsDevice) {
- OutlinedFnID = llvm::ConstantExpr::getBitCast(OutlinedFn, CGM.Int8PtrTy);
- OutlinedFn->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
- OutlinedFn->setDSOLocal(false);
- } else {
- std::string Name = getName({EntryFnName, "region_id"});
- OutlinedFnID = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::WeakAnyLinkage,
- llvm::Constant::getNullValue(CGM.Int8Ty), Name);
- }
-
- // Register the information for the entry associated with this target region.
- OffloadEntriesInfoManager.registerTargetRegionEntryInfo(
- DeviceID, FileID, ParentName, Line, OutlinedFn, OutlinedFnID,
- OffloadEntriesInfoManagerTy::OMPTargetRegionEntryTargetRegion);
-}
-
-/// discard all CompoundStmts intervening between two constructs
-static const Stmt *ignoreCompoundStmts(const Stmt *Body) {
- while (const auto *CS = dyn_cast_or_null<CompoundStmt>(Body))
- Body = CS->body_front();
-
- return Body;
-}
-
-/// Emit the number of teams for a target directive. Inspect the num_teams
-/// clause associated with a teams construct combined or closely nested
-/// with the target directive.
-///
-/// Emit a team of size one for directives such as 'target parallel' that
-/// have no associated teams construct.
-///
-/// Otherwise, return nullptr.
-static llvm::Value *
-emitNumTeamsForTargetDirective(CGOpenMPRuntime &OMPRuntime,
- CodeGenFunction &CGF,
- const OMPExecutableDirective &D) {
- assert(!CGF.getLangOpts().OpenMPIsDevice && "Clauses associated with the "
- "teams directive expected to be "
- "emitted only for the host!");
-
- CGBuilderTy &Bld = CGF.Builder;
-
- // If the target directive is combined with a teams directive:
- // Return the value in the num_teams clause, if any.
- // Otherwise, return 0 to denote the runtime default.
- if (isOpenMPTeamsDirective(D.getDirectiveKind())) {
- if (const auto *NumTeamsClause = D.getSingleClause<OMPNumTeamsClause>()) {
- CodeGenFunction::RunCleanupsScope NumTeamsScope(CGF);
- llvm::Value *NumTeams = CGF.EmitScalarExpr(NumTeamsClause->getNumTeams(),
- /*IgnoreResultAssign*/ true);
- return Bld.CreateIntCast(NumTeams, CGF.Int32Ty,
- /*IsSigned=*/true);
- }
-
- // The default value is 0.
- return Bld.getInt32(0);
- }
-
- // If the target directive is combined with a parallel directive but not a
- // teams directive, start one team.
- if (isOpenMPParallelDirective(D.getDirectiveKind()))
- return Bld.getInt32(1);
-
- // If the current target region has a teams region enclosed, we need to get
- // the number of teams to pass to the runtime function call. This is done
- // by generating the expression in a inlined region. This is required because
- // the expression is captured in the enclosing target environment when the
- // teams directive is not combined with target.
-
- const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
-
- if (const auto *TeamsDir = dyn_cast_or_null<OMPExecutableDirective>(
- ignoreCompoundStmts(CS.getCapturedStmt()))) {
- if (isOpenMPTeamsDirective(TeamsDir->getDirectiveKind())) {
- if (const auto *NTE = TeamsDir->getSingleClause<OMPNumTeamsClause>()) {
- CGOpenMPInnerExprInfo CGInfo(CGF, CS);
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
- llvm::Value *NumTeams = CGF.EmitScalarExpr(NTE->getNumTeams());
- return Bld.CreateIntCast(NumTeams, CGF.Int32Ty,
- /*IsSigned=*/true);
- }
-
- // If we have an enclosed teams directive but no num_teams clause we use
- // the default value 0.
- return Bld.getInt32(0);
- }
- }
-
- // No teams associated with the directive.
- return nullptr;
-}
-
-/// Emit the number of threads for a target directive. Inspect the
-/// thread_limit clause associated with a teams construct combined or closely
-/// nested with the target directive.
-///
-/// Emit the num_threads clause for directives such as 'target parallel' that
-/// have no associated teams construct.
-///
-/// Otherwise, return nullptr.
-static llvm::Value *
-emitNumThreadsForTargetDirective(CGOpenMPRuntime &OMPRuntime,
- CodeGenFunction &CGF,
- const OMPExecutableDirective &D) {
- assert(!CGF.getLangOpts().OpenMPIsDevice && "Clauses associated with the "
- "teams directive expected to be "
- "emitted only for the host!");
-
- CGBuilderTy &Bld = CGF.Builder;
-
- //
- // If the target directive is combined with a teams directive:
- // Return the value in the thread_limit clause, if any.
- //
- // If the target directive is combined with a parallel directive:
- // Return the value in the num_threads clause, if any.
- //
- // If both clauses are set, select the minimum of the two.
- //
- // If neither teams or parallel combined directives set the number of threads
- // in a team, return 0 to denote the runtime default.
- //
- // If this is not a teams directive return nullptr.
-
- if (isOpenMPTeamsDirective(D.getDirectiveKind()) ||
- isOpenMPParallelDirective(D.getDirectiveKind())) {
- llvm::Value *DefaultThreadLimitVal = Bld.getInt32(0);
- llvm::Value *NumThreadsVal = nullptr;
- llvm::Value *ThreadLimitVal = nullptr;
-
- if (const auto *ThreadLimitClause =
- D.getSingleClause<OMPThreadLimitClause>()) {
- CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
- llvm::Value *ThreadLimit =
- CGF.EmitScalarExpr(ThreadLimitClause->getThreadLimit(),
- /*IgnoreResultAssign*/ true);
- ThreadLimitVal = Bld.CreateIntCast(ThreadLimit, CGF.Int32Ty,
- /*IsSigned=*/true);
- }
-
- if (const auto *NumThreadsClause =
- D.getSingleClause<OMPNumThreadsClause>()) {
- CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
- llvm::Value *NumThreads =
- CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
- /*IgnoreResultAssign*/ true);
- NumThreadsVal =
- Bld.CreateIntCast(NumThreads, CGF.Int32Ty, /*IsSigned=*/true);
- }
-
- // Select the lesser of thread_limit and num_threads.
- if (NumThreadsVal)
- ThreadLimitVal = ThreadLimitVal
- ? Bld.CreateSelect(Bld.CreateICmpSLT(NumThreadsVal,
- ThreadLimitVal),
- NumThreadsVal, ThreadLimitVal)
- : NumThreadsVal;
-
- // Set default value passed to the runtime if either teams or a target
- // parallel type directive is found but no clause is specified.
- if (!ThreadLimitVal)
- ThreadLimitVal = DefaultThreadLimitVal;
-
- return ThreadLimitVal;
- }
-
- // If the current target region has a teams region enclosed, we need to get
- // the thread limit to pass to the runtime function call. This is done
- // by generating the expression in a inlined region. This is required because
- // the expression is captured in the enclosing target environment when the
- // teams directive is not combined with target.
-
- const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
-
- if (const auto *TeamsDir = dyn_cast_or_null<OMPExecutableDirective>(
- ignoreCompoundStmts(CS.getCapturedStmt()))) {
- if (isOpenMPTeamsDirective(TeamsDir->getDirectiveKind())) {
- if (const auto *TLE = TeamsDir->getSingleClause<OMPThreadLimitClause>()) {
- CGOpenMPInnerExprInfo CGInfo(CGF, CS);
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
- llvm::Value *ThreadLimit = CGF.EmitScalarExpr(TLE->getThreadLimit());
- return CGF.Builder.CreateIntCast(ThreadLimit, CGF.Int32Ty,
- /*IsSigned=*/true);
- }
-
- // If we have an enclosed teams directive but no thread_limit clause we
- // use the default value 0.
- return CGF.Builder.getInt32(0);
- }
- }
-
- // No teams associated with the directive.
- return nullptr;
-}
-
-namespace {
-LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
-
-// Utility to handle information from clauses associated with a given
-// construct that use mappable expressions (e.g. 'map' clause, 'to' clause).
-// It provides a convenient interface to obtain the information and generate
-// code for that information.
-class MappableExprsHandler {
-public:
- /// Values for bit flags used to specify the mapping type for
- /// offloading.
- enum OpenMPOffloadMappingFlags : uint64_t {
- /// No flags
- OMP_MAP_NONE = 0x0,
- /// Allocate memory on the device and move data from host to device.
- OMP_MAP_TO = 0x01,
- /// Allocate memory on the device and move data from device to host.
- OMP_MAP_FROM = 0x02,
- /// Always perform the requested mapping action on the element, even
- /// if it was already mapped before.
- OMP_MAP_ALWAYS = 0x04,
- /// Delete the element from the device environment, ignoring the
- /// current reference count associated with the element.
- OMP_MAP_DELETE = 0x08,
- /// The element being mapped is a pointer-pointee pair; both the
- /// pointer and the pointee should be mapped.
- OMP_MAP_PTR_AND_OBJ = 0x10,
- /// This flags signals that the base address of an entry should be
- /// passed to the target kernel as an argument.
- OMP_MAP_TARGET_PARAM = 0x20,
- /// Signal that the runtime library has to return the device pointer
- /// in the current position for the data being mapped. Used when we have the
- /// use_device_ptr clause.
- OMP_MAP_RETURN_PARAM = 0x40,
- /// This flag signals that the reference being passed is a pointer to
- /// private data.
- OMP_MAP_PRIVATE = 0x80,
- /// Pass the element to the device by value.
- OMP_MAP_LITERAL = 0x100,
- /// Implicit map
- OMP_MAP_IMPLICIT = 0x200,
- /// The 16 MSBs of the flags indicate whether the entry is member of some
- /// struct/class.
- OMP_MAP_MEMBER_OF = 0xffff000000000000,
- LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ OMP_MAP_MEMBER_OF),
- };
-
- /// Class that associates information with a base pointer to be passed to the
- /// runtime library.
- class BasePointerInfo {
- /// The base pointer.
- llvm::Value *Ptr = nullptr;
- /// The base declaration that refers to this device pointer, or null if
- /// there is none.
- const ValueDecl *DevPtrDecl = nullptr;
-
- public:
- BasePointerInfo(llvm::Value *Ptr, const ValueDecl *DevPtrDecl = nullptr)
- : Ptr(Ptr), DevPtrDecl(DevPtrDecl) {}
- llvm::Value *operator*() const { return Ptr; }
- const ValueDecl *getDevicePtrDecl() const { return DevPtrDecl; }
- void setDevicePtrDecl(const ValueDecl *D) { DevPtrDecl = D; }
- };
-
- using MapBaseValuesArrayTy = SmallVector<BasePointerInfo, 4>;
- using MapValuesArrayTy = SmallVector<llvm::Value *, 4>;
- using MapFlagsArrayTy = SmallVector<OpenMPOffloadMappingFlags, 4>;
-
- /// Map between a struct and the its lowest & highest elements which have been
- /// mapped.
- /// [ValueDecl *] --> {LE(FieldIndex, Pointer),
- /// HE(FieldIndex, Pointer)}
- struct StructRangeInfoTy {
- std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> LowestElem = {
- 0, Address::invalid()};
- std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> HighestElem = {
- 0, Address::invalid()};
- Address Base = Address::invalid();
- };
-
-private:
- /// Kind that defines how a device pointer has to be returned.
- struct MapInfo {
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components;
- OpenMPMapClauseKind MapType = OMPC_MAP_unknown;
- ArrayRef<OpenMPMapModifierKind> MapModifiers;
- bool ReturnDevicePointer = false;
- bool IsImplicit = false;
-
- MapInfo() = default;
- MapInfo(
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
- OpenMPMapClauseKind MapType,
- ArrayRef<OpenMPMapModifierKind> MapModifiers,
- bool ReturnDevicePointer, bool IsImplicit)
- : Components(Components), MapType(MapType), MapModifiers(MapModifiers),
- ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit) {}
- };
-
- /// If use_device_ptr is used on a pointer which is a struct member and there
- /// is no map information about it, then emission of that entry is deferred
- /// until the whole struct has been processed.
- struct DeferredDevicePtrEntryTy {
- const Expr *IE = nullptr;
- const ValueDecl *VD = nullptr;
-
- DeferredDevicePtrEntryTy(const Expr *IE, const ValueDecl *VD)
- : IE(IE), VD(VD) {}
- };
-
- /// Directive from where the map clauses were extracted.
- const OMPExecutableDirective &CurDir;
-
- /// Function the directive is being generated for.
- CodeGenFunction &CGF;
-
- /// Set of all first private variables in the current directive.
- llvm::SmallPtrSet<const VarDecl *, 8> FirstPrivateDecls;
-
- /// Map between device pointer declarations and their expression components.
- /// The key value for declarations in 'this' is null.
- llvm::DenseMap<
- const ValueDecl *,
- SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
- DevPointersMap;
-
- llvm::Value *getExprTypeSize(const Expr *E) const {
- QualType ExprTy = E->getType().getCanonicalType();
-
- // Reference types are ignored for mapping purposes.
- if (const auto *RefTy = ExprTy->getAs<ReferenceType>())
- ExprTy = RefTy->getPointeeType().getCanonicalType();
-
- // Given that an array section is considered a built-in type, we need to
- // do the calculation based on the length of the section instead of relying
- // on CGF.getTypeSize(E->getType()).
- if (const auto *OAE = dyn_cast<OMPArraySectionExpr>(E)) {
- QualType BaseTy = OMPArraySectionExpr::getBaseOriginalType(
- OAE->getBase()->IgnoreParenImpCasts())
- .getCanonicalType();
-
- // If there is no length associated with the expression, that means we
- // are using the whole length of the base.
- if (!OAE->getLength() && OAE->getColonLoc().isValid())
- return CGF.getTypeSize(BaseTy);
-
- llvm::Value *ElemSize;
- if (const auto *PTy = BaseTy->getAs<PointerType>()) {
- ElemSize = CGF.getTypeSize(PTy->getPointeeType().getCanonicalType());
- } else {
- const auto *ATy = cast<ArrayType>(BaseTy.getTypePtr());
- assert(ATy && "Expecting array type if not a pointer type.");
- ElemSize = CGF.getTypeSize(ATy->getElementType().getCanonicalType());
- }
-
- // If we don't have a length at this point, that is because we have an
- // array section with a single element.
- if (!OAE->getLength())
- return ElemSize;
-
- llvm::Value *LengthVal = CGF.EmitScalarExpr(OAE->getLength());
- LengthVal =
- CGF.Builder.CreateIntCast(LengthVal, CGF.SizeTy, /*isSigned=*/false);
- return CGF.Builder.CreateNUWMul(LengthVal, ElemSize);
- }
- return CGF.getTypeSize(ExprTy);
- }
-
- /// Return the corresponding bits for a given map clause modifier. Add
- /// a flag marking the map as a pointer if requested. Add a flag marking the
- /// map as the first one of a series of maps that relate to the same map
- /// expression.
- OpenMPOffloadMappingFlags getMapTypeBits(
- OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
- bool IsImplicit, bool AddPtrFlag, bool AddIsTargetParamFlag) const {
- OpenMPOffloadMappingFlags Bits =
- IsImplicit ? OMP_MAP_IMPLICIT : OMP_MAP_NONE;
- switch (MapType) {
- case OMPC_MAP_alloc:
- case OMPC_MAP_release:
- // alloc and release is the default behavior in the runtime library, i.e.
- // if we don't pass any bits alloc/release that is what the runtime is
- // going to do. Therefore, we don't need to signal anything for these two
- // type modifiers.
- break;
- case OMPC_MAP_to:
- Bits |= OMP_MAP_TO;
- break;
- case OMPC_MAP_from:
- Bits |= OMP_MAP_FROM;
- break;
- case OMPC_MAP_tofrom:
- Bits |= OMP_MAP_TO | OMP_MAP_FROM;
- break;
- case OMPC_MAP_delete:
- Bits |= OMP_MAP_DELETE;
- break;
- case OMPC_MAP_unknown:
- llvm_unreachable("Unexpected map type!");
- }
- if (AddPtrFlag)
- Bits |= OMP_MAP_PTR_AND_OBJ;
- if (AddIsTargetParamFlag)
- Bits |= OMP_MAP_TARGET_PARAM;
- if (llvm::find(MapModifiers, OMPC_MAP_MODIFIER_always)
- != MapModifiers.end())
- Bits |= OMP_MAP_ALWAYS;
- return Bits;
- }
-
- /// Return true if the provided expression is a final array section. A
- /// final array section, is one whose length can't be proved to be one.
- bool isFinalArraySectionExpression(const Expr *E) const {
- const auto *OASE = dyn_cast<OMPArraySectionExpr>(E);
-
- // It is not an array section and therefore not a unity-size one.
- if (!OASE)
- return false;
-
- // An array section with no colon always refer to a single element.
- if (OASE->getColonLoc().isInvalid())
- return false;
-
- const Expr *Length = OASE->getLength();
-
- // If we don't have a length we have to check if the array has size 1
- // for this dimension. Also, we should always expect a length if the
- // base type is pointer.
- if (!Length) {
- QualType BaseQTy = OMPArraySectionExpr::getBaseOriginalType(
- OASE->getBase()->IgnoreParenImpCasts())
- .getCanonicalType();
- if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
- return ATy->getSize().getSExtValue() != 1;
- // If we don't have a constant dimension length, we have to consider
- // the current section as having any size, so it is not necessarily
- // unitary. If it happen to be unity size, that's user fault.
- return true;
- }
-
- // Check if the length evaluates to 1.
- Expr::EvalResult Result;
- if (!Length->EvaluateAsInt(Result, CGF.getContext()))
- return true; // Can have more that size 1.
-
- llvm::APSInt ConstLength = Result.Val.getInt();
- return ConstLength.getSExtValue() != 1;
- }
-
- /// Generate the base pointers, section pointers, sizes and map type
- /// bits for the provided map type, map modifier, and expression components.
- /// \a IsFirstComponent should be set to true if the provided set of
- /// components is the first associated with a capture.
- void generateInfoForComponentList(
- OpenMPMapClauseKind MapType,
- ArrayRef<OpenMPMapModifierKind> MapModifiers,
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
- MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers,
- MapValuesArrayTy &Sizes, MapFlagsArrayTy &Types,
- StructRangeInfoTy &PartialStruct, bool IsFirstComponentList,
- bool IsImplicit,
- ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
- OverlappedElements = llvm::None) const {
- // The following summarizes what has to be generated for each map and the
- // types below. The generated information is expressed in this order:
- // base pointer, section pointer, size, flags
- // (to add to the ones that come from the map type and modifier).
- //
- // double d;
- // int i[100];
- // float *p;
- //
- // struct S1 {
- // int i;
- // float f[50];
- // }
- // struct S2 {
- // int i;
- // float f[50];
- // S1 s;
- // double *p;
- // struct S2 *ps;
- // }
- // S2 s;
- // S2 *ps;
- //
- // map(d)
- // &d, &d, sizeof(double), TARGET_PARAM | TO | FROM
- //
- // map(i)
- // &i, &i, 100*sizeof(int), TARGET_PARAM | TO | FROM
- //
- // map(i[1:23])
- // &i(=&i[0]), &i[1], 23*sizeof(int), TARGET_PARAM | TO | FROM
- //
- // map(p)
- // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
- //
- // map(p[1:24])
- // p, &p[1], 24*sizeof(float), TARGET_PARAM | TO | FROM
- //
- // map(s)
- // &s, &s, sizeof(S2), TARGET_PARAM | TO | FROM
- //
- // map(s.i)
- // &s, &(s.i), sizeof(int), TARGET_PARAM | TO | FROM
- //
- // map(s.s.f)
- // &s, &(s.s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
- //
- // map(s.p)
- // &s, &(s.p), sizeof(double*), TARGET_PARAM | TO | FROM
- //
- // map(to: s.p[:22])
- // &s, &(s.p), sizeof(double*), TARGET_PARAM (*)
- // &s, &(s.p), sizeof(double*), MEMBER_OF(1) (**)
- // &(s.p), &(s.p[0]), 22*sizeof(double),
- // MEMBER_OF(1) | PTR_AND_OBJ | TO (***)
- // (*) alloc space for struct members, only this is a target parameter
- // (**) map the pointer (nothing to be mapped in this example) (the compiler
- // optimizes this entry out, same in the examples below)
- // (***) map the pointee (map: to)
- //
- // map(s.ps)
- // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM
- //
- // map(from: s.ps->s.i)
- // &s, &(s.ps), sizeof(S2*), TARGET_PARAM
- // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1)
- // &(s.ps), &(s.ps->s.i), sizeof(int), MEMBER_OF(1) | PTR_AND_OBJ | FROM
- //
- // map(to: s.ps->ps)
- // &s, &(s.ps), sizeof(S2*), TARGET_PARAM
- // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1)
- // &(s.ps), &(s.ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ | TO
- //
- // map(s.ps->ps->ps)
- // &s, &(s.ps), sizeof(S2*), TARGET_PARAM
- // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1)
- // &(s.ps), &(s.ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ
- // &(s.ps->ps), &(s.ps->ps->ps), sizeof(S2*), PTR_AND_OBJ | TO | FROM
- //
- // map(to: s.ps->ps->s.f[:22])
- // &s, &(s.ps), sizeof(S2*), TARGET_PARAM
- // &s, &(s.ps), sizeof(S2*), MEMBER_OF(1)
- // &(s.ps), &(s.ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ
- // &(s.ps->ps), &(s.ps->ps->s.f[0]), 22*sizeof(float), PTR_AND_OBJ | TO
- //
- // map(ps)
- // &ps, &ps, sizeof(S2*), TARGET_PARAM | TO | FROM
- //
- // map(ps->i)
- // ps, &(ps->i), sizeof(int), TARGET_PARAM | TO | FROM
- //
- // map(ps->s.f)
- // ps, &(ps->s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
- //
- // map(from: ps->p)
- // ps, &(ps->p), sizeof(double*), TARGET_PARAM | FROM
- //
- // map(to: ps->p[:22])
- // ps, &(ps->p), sizeof(double*), TARGET_PARAM
- // ps, &(ps->p), sizeof(double*), MEMBER_OF(1)
- // &(ps->p), &(ps->p[0]), 22*sizeof(double), MEMBER_OF(1) | PTR_AND_OBJ | TO
- //
- // map(ps->ps)
- // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM | TO | FROM
- //
- // map(from: ps->ps->s.i)
- // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM
- // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1)
- // &(ps->ps), &(ps->ps->s.i), sizeof(int), MEMBER_OF(1) | PTR_AND_OBJ | FROM
- //
- // map(from: ps->ps->ps)
- // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM
- // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1)
- // &(ps->ps), &(ps->ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ | FROM
- //
- // map(ps->ps->ps->ps)
- // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM
- // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1)
- // &(ps->ps), &(ps->ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ
- // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(S2*), PTR_AND_OBJ | TO | FROM
- //
- // map(to: ps->ps->ps->s.f[:22])
- // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM
- // ps, &(ps->ps), sizeof(S2*), MEMBER_OF(1)
- // &(ps->ps), &(ps->ps->ps), sizeof(S2*), MEMBER_OF(1) | PTR_AND_OBJ
- // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), 22*sizeof(float), PTR_AND_OBJ | TO
- //
- // map(to: s.f[:22]) map(from: s.p[:33])
- // &s, &(s.f[0]), 50*sizeof(float) + sizeof(struct S1) +
- // sizeof(double*) (**), TARGET_PARAM
- // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | TO
- // &s, &(s.p), sizeof(double*), MEMBER_OF(1)
- // &(s.p), &(s.p[0]), 33*sizeof(double), MEMBER_OF(1) | PTR_AND_OBJ | FROM
- // (*) allocate contiguous space needed to fit all mapped members even if
- // we allocate space for members not mapped (in this example,
- // s.f[22..49] and s.s are not mapped, yet we must allocate space for
- // them as well because they fall between &s.f[0] and &s.p)
- //
- // map(from: s.f[:22]) map(to: ps->p[:33])
- // &s, &(s.f[0]), 22*sizeof(float), TARGET_PARAM | FROM
- // ps, &(ps->p), sizeof(S2*), TARGET_PARAM
- // ps, &(ps->p), sizeof(double*), MEMBER_OF(2) (*)
- // &(ps->p), &(ps->p[0]), 33*sizeof(double), MEMBER_OF(2) | PTR_AND_OBJ | TO
- // (*) the struct this entry pertains to is the 2nd element in the list of
- // arguments, hence MEMBER_OF(2)
- //
- // map(from: s.f[:22], s.s) map(to: ps->p[:33])
- // &s, &(s.f[0]), 50*sizeof(float) + sizeof(struct S1), TARGET_PARAM
- // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | FROM
- // &s, &(s.s), sizeof(struct S1), MEMBER_OF(1) | FROM
- // ps, &(ps->p), sizeof(S2*), TARGET_PARAM
- // ps, &(ps->p), sizeof(double*), MEMBER_OF(4) (*)
- // &(ps->p), &(ps->p[0]), 33*sizeof(double), MEMBER_OF(4) | PTR_AND_OBJ | TO
- // (*) the struct this entry pertains to is the 4th element in the list
- // of arguments, hence MEMBER_OF(4)
-
- // Track if the map information being generated is the first for a capture.
- bool IsCaptureFirstInfo = IsFirstComponentList;
- bool IsLink = false; // Is this variable a "declare target link"?
-
- // Scan the components from the base to the complete expression.
- auto CI = Components.rbegin();
- auto CE = Components.rend();
- auto I = CI;
-
- // Track if the map information being generated is the first for a list of
- // components.
- bool IsExpressionFirstInfo = true;
- Address BP = Address::invalid();
- const Expr *AssocExpr = I->getAssociatedExpression();
- const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr);
- const auto *OASE = dyn_cast<OMPArraySectionExpr>(AssocExpr);
-
- if (isa<MemberExpr>(AssocExpr)) {
- // The base is the 'this' pointer. The content of the pointer is going
- // to be the base of the field being mapped.
- BP = CGF.LoadCXXThisAddress();
- } else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) ||
- (OASE &&
- isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) {
- BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
- } else {
- // The base is the reference to the variable.
- // BP = &Var.
- BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
- if (const auto *VD =
- dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) {
- if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
- if (*Res == OMPDeclareTargetDeclAttr::MT_Link) {
- IsLink = true;
- BP = CGF.CGM.getOpenMPRuntime().getAddrOfDeclareTargetLink(VD);
- }
- }
-
- // If the variable is a pointer and is being dereferenced (i.e. is not
- // the last component), the base has to be the pointer itself, not its
- // reference. References are ignored for mapping purposes.
- QualType Ty =
- I->getAssociatedDeclaration()->getType().getNonReferenceType();
- if (Ty->isAnyPointerType() && std::next(I) != CE) {
- BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
-
- // We do not need to generate individual map information for the
- // pointer, it can be associated with the combined storage.
- ++I;
- }
- }
-
- // Track whether a component of the list should be marked as MEMBER_OF some
- // combined entry (for partial structs). Only the first PTR_AND_OBJ entry
- // in a component list should be marked as MEMBER_OF, all subsequent entries
- // do not belong to the base struct. E.g.
- // struct S2 s;
- // s.ps->ps->ps->f[:]
- // (1) (2) (3) (4)
- // ps(1) is a member pointer, ps(2) is a pointee of ps(1), so it is a
- // PTR_AND_OBJ entry; the PTR is ps(1), so MEMBER_OF the base struct. ps(3)
- // is the pointee of ps(2) which is not member of struct s, so it should not
- // be marked as such (it is still PTR_AND_OBJ).
- // The variable is initialized to false so that PTR_AND_OBJ entries which
- // are not struct members are not considered (e.g. array of pointers to
- // data).
- bool ShouldBeMemberOf = false;
-
- // Variable keeping track of whether or not we have encountered a component
- // in the component list which is a member expression. Useful when we have a
- // pointer or a final array section, in which case it is the previous
- // component in the list which tells us whether we have a member expression.
- // E.g. X.f[:]
- // While processing the final array section "[:]" it is "f" which tells us
- // whether we are dealing with a member of a declared struct.
- const MemberExpr *EncounteredME = nullptr;
-
- for (; I != CE; ++I) {
- // If the current component is member of a struct (parent struct) mark it.
- if (!EncounteredME) {
- EncounteredME = dyn_cast<MemberExpr>(I->getAssociatedExpression());
- // If we encounter a PTR_AND_OBJ entry from now on it should be marked
- // as MEMBER_OF the parent struct.
- if (EncounteredME)
- ShouldBeMemberOf = true;
- }
-
- auto Next = std::next(I);
-
- // We need to generate the addresses and sizes if this is the last
- // component, if the component is a pointer or if it is an array section
- // whose length can't be proved to be one. If this is a pointer, it
- // becomes the base address for the following components.
-
- // A final array section, is one whose length can't be proved to be one.
- bool IsFinalArraySection =
- isFinalArraySectionExpression(I->getAssociatedExpression());
-
- // Get information on whether the element is a pointer. Have to do a
- // special treatment for array sections given that they are built-in
- // types.
- const auto *OASE =
- dyn_cast<OMPArraySectionExpr>(I->getAssociatedExpression());
- bool IsPointer =
- (OASE && OMPArraySectionExpr::getBaseOriginalType(OASE)
- .getCanonicalType()
- ->isAnyPointerType()) ||
- I->getAssociatedExpression()->getType()->isAnyPointerType();
-
- if (Next == CE || IsPointer || IsFinalArraySection) {
- // If this is not the last component, we expect the pointer to be
- // associated with an array expression or member expression.
- assert((Next == CE ||
- isa<MemberExpr>(Next->getAssociatedExpression()) ||
- isa<ArraySubscriptExpr>(Next->getAssociatedExpression()) ||
- isa<OMPArraySectionExpr>(Next->getAssociatedExpression())) &&
- "Unexpected expression");
-
- Address LB =
- CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getAddress();
-
- // If this component is a pointer inside the base struct then we don't
- // need to create any entry for it - it will be combined with the object
- // it is pointing to into a single PTR_AND_OBJ entry.
- bool IsMemberPointer =
- IsPointer && EncounteredME &&
- (dyn_cast<MemberExpr>(I->getAssociatedExpression()) ==
- EncounteredME);
- if (!OverlappedElements.empty()) {
- // Handle base element with the info for overlapped elements.
- assert(!PartialStruct.Base.isValid() && "The base element is set.");
- assert(Next == CE &&
- "Expected last element for the overlapped elements.");
- assert(!IsPointer &&
- "Unexpected base element with the pointer type.");
- // Mark the whole struct as the struct that requires allocation on the
- // device.
- PartialStruct.LowestElem = {0, LB};
- CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(
- I->getAssociatedExpression()->getType());
- Address HB = CGF.Builder.CreateConstGEP(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(LB,
- CGF.VoidPtrTy),
- TypeSize.getQuantity() - 1, CharUnits::One());
- PartialStruct.HighestElem = {
- std::numeric_limits<decltype(
- PartialStruct.HighestElem.first)>::max(),
- HB};
- PartialStruct.Base = BP;
- // Emit data for non-overlapped data.
- OpenMPOffloadMappingFlags Flags =
- OMP_MAP_MEMBER_OF |
- getMapTypeBits(MapType, MapModifiers, IsImplicit,
- /*AddPtrFlag=*/false,
- /*AddIsTargetParamFlag=*/false);
- LB = BP;
- llvm::Value *Size = nullptr;
- // Do bitcopy of all non-overlapped structure elements.
- for (OMPClauseMappableExprCommon::MappableExprComponentListRef
- Component : OverlappedElements) {
- Address ComponentLB = Address::invalid();
- for (const OMPClauseMappableExprCommon::MappableComponent &MC :
- Component) {
- if (MC.getAssociatedDeclaration()) {
- ComponentLB =
- CGF.EmitOMPSharedLValue(MC.getAssociatedExpression())
- .getAddress();
- Size = CGF.Builder.CreatePtrDiff(
- CGF.EmitCastToVoidPtr(ComponentLB.getPointer()),
- CGF.EmitCastToVoidPtr(LB.getPointer()));
- break;
- }
- }
- BasePointers.push_back(BP.getPointer());
- Pointers.push_back(LB.getPointer());
- Sizes.push_back(Size);
- Types.push_back(Flags);
- LB = CGF.Builder.CreateConstGEP(ComponentLB, 1,
- CGF.getPointerSize());
- }
- BasePointers.push_back(BP.getPointer());
- Pointers.push_back(LB.getPointer());
- Size = CGF.Builder.CreatePtrDiff(
- CGF.EmitCastToVoidPtr(
- CGF.Builder.CreateConstGEP(HB, 1, CharUnits::One())
- .getPointer()),
- CGF.EmitCastToVoidPtr(LB.getPointer()));
- Sizes.push_back(Size);
- Types.push_back(Flags);
- break;
- }
- llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression());
- if (!IsMemberPointer) {
- BasePointers.push_back(BP.getPointer());
- Pointers.push_back(LB.getPointer());
- Sizes.push_back(Size);
-
- // We need to add a pointer flag for each map that comes from the
- // same expression except for the first one. We also need to signal
- // this map is the first one that relates with the current capture
- // (there is a set of entries for each capture).
- OpenMPOffloadMappingFlags Flags = getMapTypeBits(
- MapType, MapModifiers, IsImplicit,
- !IsExpressionFirstInfo || IsLink, IsCaptureFirstInfo && !IsLink);
-
- if (!IsExpressionFirstInfo) {
- // If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
- // then we reset the TO/FROM/ALWAYS/DELETE flags.
- if (IsPointer)
- Flags &= ~(OMP_MAP_TO | OMP_MAP_FROM | OMP_MAP_ALWAYS |
- OMP_MAP_DELETE);
-
- if (ShouldBeMemberOf) {
- // Set placeholder value MEMBER_OF=FFFF to indicate that the flag
- // should be later updated with the correct value of MEMBER_OF.
- Flags |= OMP_MAP_MEMBER_OF;
- // From now on, all subsequent PTR_AND_OBJ entries should not be
- // marked as MEMBER_OF.
- ShouldBeMemberOf = false;
- }
- }
-
- Types.push_back(Flags);
- }
-
- // If we have encountered a member expression so far, keep track of the
- // mapped member. If the parent is "*this", then the value declaration
- // is nullptr.
- if (EncounteredME) {
- const auto *FD = dyn_cast<FieldDecl>(EncounteredME->getMemberDecl());
- unsigned FieldIndex = FD->getFieldIndex();
-
- // Update info about the lowest and highest elements for this struct
- if (!PartialStruct.Base.isValid()) {
- PartialStruct.LowestElem = {FieldIndex, LB};
- PartialStruct.HighestElem = {FieldIndex, LB};
- PartialStruct.Base = BP;
- } else if (FieldIndex < PartialStruct.LowestElem.first) {
- PartialStruct.LowestElem = {FieldIndex, LB};
- } else if (FieldIndex > PartialStruct.HighestElem.first) {
- PartialStruct.HighestElem = {FieldIndex, LB};
- }
- }
-
- // If we have a final array section, we are done with this expression.
- if (IsFinalArraySection)
- break;
-
- // The pointer becomes the base for the next element.
- if (Next != CE)
- BP = LB;
-
- IsExpressionFirstInfo = false;
- IsCaptureFirstInfo = false;
- }
- }
- }
-
- /// Return the adjusted map modifiers if the declaration a capture refers to
- /// appears in a first-private clause. This is expected to be used only with
- /// directives that start with 'target'.
- MappableExprsHandler::OpenMPOffloadMappingFlags
- getMapModifiersForPrivateClauses(const CapturedStmt::Capture &Cap) const {
- assert(Cap.capturesVariable() && "Expected capture by reference only!");
-
- // A first private variable captured by reference will use only the
- // 'private ptr' and 'map to' flag. Return the right flags if the captured
- // declaration is known as first-private in this handler.
- if (FirstPrivateDecls.count(Cap.getCapturedVar()))
- return MappableExprsHandler::OMP_MAP_PRIVATE |
- MappableExprsHandler::OMP_MAP_TO;
- return MappableExprsHandler::OMP_MAP_TO |
- MappableExprsHandler::OMP_MAP_FROM;
- }
-
- static OpenMPOffloadMappingFlags getMemberOfFlag(unsigned Position) {
- // Member of is given by the 16 MSB of the flag, so rotate by 48 bits.
- return static_cast<OpenMPOffloadMappingFlags>(((uint64_t)Position + 1)
- << 48);
- }
-
- static void setCorrectMemberOfFlag(OpenMPOffloadMappingFlags &Flags,
- OpenMPOffloadMappingFlags MemberOfFlag) {
- // If the entry is PTR_AND_OBJ but has not been marked with the special
- // placeholder value 0xFFFF in the MEMBER_OF field, then it should not be
- // marked as MEMBER_OF.
- if ((Flags & OMP_MAP_PTR_AND_OBJ) &&
- ((Flags & OMP_MAP_MEMBER_OF) != OMP_MAP_MEMBER_OF))
- return;
-
- // Reset the placeholder value to prepare the flag for the assignment of the
- // proper MEMBER_OF value.
- Flags &= ~OMP_MAP_MEMBER_OF;
- Flags |= MemberOfFlag;
- }
-
- void getPlainLayout(const CXXRecordDecl *RD,
- llvm::SmallVectorImpl<const FieldDecl *> &Layout,
- bool AsBase) const {
- const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(RD);
-
- llvm::StructType *St =
- AsBase ? RL.getBaseSubobjectLLVMType() : RL.getLLVMType();
-
- unsigned NumElements = St->getNumElements();
- llvm::SmallVector<
- llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>, 4>
- RecordLayout(NumElements);
-
- // Fill bases.
- for (const auto &I : RD->bases()) {
- if (I.isVirtual())
- continue;
- const auto *Base = I.getType()->getAsCXXRecordDecl();
- // Ignore empty bases.
- if (Base->isEmpty() || CGF.getContext()
- .getASTRecordLayout(Base)
- .getNonVirtualSize()
- .isZero())
- continue;
-
- unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base);
- RecordLayout[FieldIndex] = Base;
- }
- // Fill in virtual bases.
- for (const auto &I : RD->vbases()) {
- const auto *Base = I.getType()->getAsCXXRecordDecl();
- // Ignore empty bases.
- if (Base->isEmpty())
- continue;
- unsigned FieldIndex = RL.getVirtualBaseIndex(Base);
- if (RecordLayout[FieldIndex])
- continue;
- RecordLayout[FieldIndex] = Base;
- }
- // Fill in all the fields.
- assert(!RD->isUnion() && "Unexpected union.");
- for (const auto *Field : RD->fields()) {
- // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
- // will fill in later.)
- if (!Field->isBitField()) {
- unsigned FieldIndex = RL.getLLVMFieldNo(Field);
- RecordLayout[FieldIndex] = Field;
- }
- }
- for (const llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>
- &Data : RecordLayout) {
- if (Data.isNull())
- continue;
- if (const auto *Base = Data.dyn_cast<const CXXRecordDecl *>())
- getPlainLayout(Base, Layout, /*AsBase=*/true);
- else
- Layout.push_back(Data.get<const FieldDecl *>());
- }
- }
-
-public:
- MappableExprsHandler(const OMPExecutableDirective &Dir, CodeGenFunction &CGF)
- : CurDir(Dir), CGF(CGF) {
- // Extract firstprivate clause information.
- for (const auto *C : Dir.getClausesOfKind<OMPFirstprivateClause>())
- for (const auto *D : C->varlists())
- FirstPrivateDecls.insert(
- cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl());
- // Extract device pointer clause information.
- for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
- for (auto L : C->component_lists())
- DevPointersMap[L.first].push_back(L.second);
- }
-
- /// Generate code for the combined entry if we have a partially mapped struct
- /// and take care of the mapping flags of the arguments corresponding to
- /// individual struct members.
- void emitCombinedEntry(MapBaseValuesArrayTy &BasePointers,
- MapValuesArrayTy &Pointers, MapValuesArrayTy &Sizes,
- MapFlagsArrayTy &Types, MapFlagsArrayTy &CurTypes,
- const StructRangeInfoTy &PartialStruct) const {
- // Base is the base of the struct
- BasePointers.push_back(PartialStruct.Base.getPointer());
- // Pointer is the address of the lowest element
- llvm::Value *LB = PartialStruct.LowestElem.second.getPointer();
- Pointers.push_back(LB);
- // Size is (addr of {highest+1} element) - (addr of lowest element)
- llvm::Value *HB = PartialStruct.HighestElem.second.getPointer();
- llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32(HB, /*Idx0=*/1);
- llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy);
- llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy);
- llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CHAddr, CLAddr);
- llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.SizeTy,
- /*isSinged=*/false);
- Sizes.push_back(Size);
- // Map type is always TARGET_PARAM
- Types.push_back(OMP_MAP_TARGET_PARAM);
- // Remove TARGET_PARAM flag from the first element
- (*CurTypes.begin()) &= ~OMP_MAP_TARGET_PARAM;
-
- // All other current entries will be MEMBER_OF the combined entry
- // (except for PTR_AND_OBJ entries which do not have a placeholder value
- // 0xFFFF in the MEMBER_OF field).
- OpenMPOffloadMappingFlags MemberOfFlag =
- getMemberOfFlag(BasePointers.size() - 1);
- for (auto &M : CurTypes)
- setCorrectMemberOfFlag(M, MemberOfFlag);
- }
-
- /// Generate all the base pointers, section pointers, sizes and map
- /// types for the extracted mappable expressions. Also, for each item that
- /// relates with a device pointer, a pair of the relevant declaration and
- /// index where it occurs is appended to the device pointers info array.
- void generateAllInfo(MapBaseValuesArrayTy &BasePointers,
- MapValuesArrayTy &Pointers, MapValuesArrayTy &Sizes,
- MapFlagsArrayTy &Types) const {
- // We have to process the component lists that relate with the same
- // declaration in a single chunk so that we can generate the map flags
- // correctly. Therefore, we organize all lists in a map.
- llvm::MapVector<const ValueDecl *, SmallVector<MapInfo, 8>> Info;
-
- // Helper function to fill the information map for the different supported
- // clauses.
- auto &&InfoGen = [&Info](
- const ValueDecl *D,
- OMPClauseMappableExprCommon::MappableExprComponentListRef L,
- OpenMPMapClauseKind MapType,
- ArrayRef<OpenMPMapModifierKind> MapModifiers,
- bool ReturnDevicePointer, bool IsImplicit) {
- const ValueDecl *VD =
- D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
- Info[VD].emplace_back(L, MapType, MapModifiers, ReturnDevicePointer,
- IsImplicit);
- };
-
- // FIXME: MSVC 2013 seems to require this-> to find member CurDir.
- for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>())
- for (const auto &L : C->component_lists()) {
- InfoGen(L.first, L.second, C->getMapType(), C->getMapTypeModifiers(),
- /*ReturnDevicePointer=*/false, C->isImplicit());
- }
- for (const auto *C : this->CurDir.getClausesOfKind<OMPToClause>())
- for (const auto &L : C->component_lists()) {
- InfoGen(L.first, L.second, OMPC_MAP_to, llvm::None,
- /*ReturnDevicePointer=*/false, C->isImplicit());
- }
- for (const auto *C : this->CurDir.getClausesOfKind<OMPFromClause>())
- for (const auto &L : C->component_lists()) {
- InfoGen(L.first, L.second, OMPC_MAP_from, llvm::None,
- /*ReturnDevicePointer=*/false, C->isImplicit());
- }
-
- // Look at the use_device_ptr clause information and mark the existing map
- // entries as such. If there is no map information for an entry in the
- // use_device_ptr list, we create one with map type 'alloc' and zero size
- // section. It is the user fault if that was not mapped before. If there is
- // no map information and the pointer is a struct member, then we defer the
- // emission of that entry until the whole struct has been processed.
- llvm::MapVector<const ValueDecl *, SmallVector<DeferredDevicePtrEntryTy, 4>>
- DeferredInfo;
-
- // FIXME: MSVC 2013 seems to require this-> to find member CurDir.
- for (const auto *C :
- this->CurDir.getClausesOfKind<OMPUseDevicePtrClause>()) {
- for (const auto &L : C->component_lists()) {
- assert(!L.second.empty() && "Not expecting empty list of components!");
- const ValueDecl *VD = L.second.back().getAssociatedDeclaration();
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- const Expr *IE = L.second.back().getAssociatedExpression();
- // If the first component is a member expression, we have to look into
- // 'this', which maps to null in the map of map information. Otherwise
- // look directly for the information.
- auto It = Info.find(isa<MemberExpr>(IE) ? nullptr : VD);
-
- // We potentially have map information for this declaration already.
- // Look for the first set of components that refer to it.
- if (It != Info.end()) {
- auto CI = std::find_if(
- It->second.begin(), It->second.end(), [VD](const MapInfo &MI) {
- return MI.Components.back().getAssociatedDeclaration() == VD;
- });
- // If we found a map entry, signal that the pointer has to be returned
- // and move on to the next declaration.
- if (CI != It->second.end()) {
- CI->ReturnDevicePointer = true;
- continue;
- }
- }
-
- // We didn't find any match in our map information - generate a zero
- // size array section - if the pointer is a struct member we defer this
- // action until the whole struct has been processed.
- // FIXME: MSVC 2013 seems to require this-> to find member CGF.
- if (isa<MemberExpr>(IE)) {
- // Insert the pointer into Info to be processed by
- // generateInfoForComponentList. Because it is a member pointer
- // without a pointee, no entry will be generated for it, therefore
- // we need to generate one after the whole struct has been processed.
- // Nonetheless, generateInfoForComponentList must be called to take
- // the pointer into account for the calculation of the range of the
- // partial struct.
- InfoGen(nullptr, L.second, OMPC_MAP_unknown, llvm::None,
- /*ReturnDevicePointer=*/false, C->isImplicit());
- DeferredInfo[nullptr].emplace_back(IE, VD);
- } else {
- llvm::Value *Ptr = this->CGF.EmitLoadOfScalar(
- this->CGF.EmitLValue(IE), IE->getExprLoc());
- BasePointers.emplace_back(Ptr, VD);
- Pointers.push_back(Ptr);
- Sizes.push_back(llvm::Constant::getNullValue(this->CGF.SizeTy));
- Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_TARGET_PARAM);
- }
- }
- }
-
- for (const auto &M : Info) {
- // We need to know when we generate information for the first component
- // associated with a capture, because the mapping flags depend on it.
- bool IsFirstComponentList = true;
-
- // Temporary versions of arrays
- MapBaseValuesArrayTy CurBasePointers;
- MapValuesArrayTy CurPointers;
- MapValuesArrayTy CurSizes;
- MapFlagsArrayTy CurTypes;
- StructRangeInfoTy PartialStruct;
-
- for (const MapInfo &L : M.second) {
- assert(!L.Components.empty() &&
- "Not expecting declaration with no component lists.");
-
- // Remember the current base pointer index.
- unsigned CurrentBasePointersIdx = CurBasePointers.size();
- // FIXME: MSVC 2013 seems to require this-> to find the member method.
- this->generateInfoForComponentList(
- L.MapType, L.MapModifiers, L.Components, CurBasePointers,
- CurPointers, CurSizes, CurTypes, PartialStruct,
- IsFirstComponentList, L.IsImplicit);
-
- // If this entry relates with a device pointer, set the relevant
- // declaration and add the 'return pointer' flag.
- if (L.ReturnDevicePointer) {
- assert(CurBasePointers.size() > CurrentBasePointersIdx &&
- "Unexpected number of mapped base pointers.");
-
- const ValueDecl *RelevantVD =
- L.Components.back().getAssociatedDeclaration();
- assert(RelevantVD &&
- "No relevant declaration related with device pointer??");
-
- CurBasePointers[CurrentBasePointersIdx].setDevicePtrDecl(RelevantVD);
- CurTypes[CurrentBasePointersIdx] |= OMP_MAP_RETURN_PARAM;
- }
- IsFirstComponentList = false;
- }
-
- // Append any pending zero-length pointers which are struct members and
- // used with use_device_ptr.
- auto CI = DeferredInfo.find(M.first);
- if (CI != DeferredInfo.end()) {
- for (const DeferredDevicePtrEntryTy &L : CI->second) {
- llvm::Value *BasePtr = this->CGF.EmitLValue(L.IE).getPointer();
- llvm::Value *Ptr = this->CGF.EmitLoadOfScalar(
- this->CGF.EmitLValue(L.IE), L.IE->getExprLoc());
- CurBasePointers.emplace_back(BasePtr, L.VD);
- CurPointers.push_back(Ptr);
- CurSizes.push_back(llvm::Constant::getNullValue(this->CGF.SizeTy));
- // Entry is PTR_AND_OBJ and RETURN_PARAM. Also, set the placeholder
- // value MEMBER_OF=FFFF so that the entry is later updated with the
- // correct value of MEMBER_OF.
- CurTypes.push_back(OMP_MAP_PTR_AND_OBJ | OMP_MAP_RETURN_PARAM |
- OMP_MAP_MEMBER_OF);
- }
- }
-
- // If there is an entry in PartialStruct it means we have a struct with
- // individual members mapped. Emit an extra combined entry.
- if (PartialStruct.Base.isValid())
- emitCombinedEntry(BasePointers, Pointers, Sizes, Types, CurTypes,
- PartialStruct);
-
- // We need to append the results of this capture to what we already have.
- BasePointers.append(CurBasePointers.begin(), CurBasePointers.end());
- Pointers.append(CurPointers.begin(), CurPointers.end());
- Sizes.append(CurSizes.begin(), CurSizes.end());
- Types.append(CurTypes.begin(), CurTypes.end());
- }
- }
-
- /// Emit capture info for lambdas for variables captured by reference.
- void generateInfoForLambdaCaptures(
- const ValueDecl *VD, llvm::Value *Arg, MapBaseValuesArrayTy &BasePointers,
- MapValuesArrayTy &Pointers, MapValuesArrayTy &Sizes,
- MapFlagsArrayTy &Types,
- llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers) const {
- const auto *RD = VD->getType()
- .getCanonicalType()
- .getNonReferenceType()
- ->getAsCXXRecordDecl();
- if (!RD || !RD->isLambda())
- return;
- Address VDAddr = Address(Arg, CGF.getContext().getDeclAlign(VD));
- LValue VDLVal = CGF.MakeAddrLValue(
- VDAddr, VD->getType().getCanonicalType().getNonReferenceType());
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
- FieldDecl *ThisCapture = nullptr;
- RD->getCaptureFields(Captures, ThisCapture);
- if (ThisCapture) {
- LValue ThisLVal =
- CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture);
- LValue ThisLValVal = CGF.EmitLValueForField(VDLVal, ThisCapture);
- LambdaPointers.try_emplace(ThisLVal.getPointer(), VDLVal.getPointer());
- BasePointers.push_back(ThisLVal.getPointer());
- Pointers.push_back(ThisLValVal.getPointer());
- Sizes.push_back(CGF.getTypeSize(CGF.getContext().VoidPtrTy));
- Types.push_back(OMP_MAP_PTR_AND_OBJ | OMP_MAP_LITERAL |
- OMP_MAP_MEMBER_OF | OMP_MAP_IMPLICIT);
- }
- for (const LambdaCapture &LC : RD->captures()) {
- if (LC.getCaptureKind() != LCK_ByRef)
- continue;
- const VarDecl *VD = LC.getCapturedVar();
- auto It = Captures.find(VD);
- assert(It != Captures.end() && "Found lambda capture without field.");
- LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
- LValue VarLValVal = CGF.EmitLValueForField(VDLVal, It->second);
- LambdaPointers.try_emplace(VarLVal.getPointer(), VDLVal.getPointer());
- BasePointers.push_back(VarLVal.getPointer());
- Pointers.push_back(VarLValVal.getPointer());
- Sizes.push_back(CGF.getTypeSize(
- VD->getType().getCanonicalType().getNonReferenceType()));
- Types.push_back(OMP_MAP_PTR_AND_OBJ | OMP_MAP_LITERAL |
- OMP_MAP_MEMBER_OF | OMP_MAP_IMPLICIT);
- }
- }
-
- /// Set correct indices for lambdas captures.
- void adjustMemberOfForLambdaCaptures(
- const llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers,
- MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers,
- MapFlagsArrayTy &Types) const {
- for (unsigned I = 0, E = Types.size(); I < E; ++I) {
- // Set correct member_of idx for all implicit lambda captures.
- if (Types[I] != (OMP_MAP_PTR_AND_OBJ | OMP_MAP_LITERAL |
- OMP_MAP_MEMBER_OF | OMP_MAP_IMPLICIT))
- continue;
- llvm::Value *BasePtr = LambdaPointers.lookup(*BasePointers[I]);
- assert(BasePtr && "Unable to find base lambda address.");
- int TgtIdx = -1;
- for (unsigned J = I; J > 0; --J) {
- unsigned Idx = J - 1;
- if (Pointers[Idx] != BasePtr)
- continue;
- TgtIdx = Idx;
- break;
- }
- assert(TgtIdx != -1 && "Unable to find parent lambda.");
- // All other current entries will be MEMBER_OF the combined entry
- // (except for PTR_AND_OBJ entries which do not have a placeholder value
- // 0xFFFF in the MEMBER_OF field).
- OpenMPOffloadMappingFlags MemberOfFlag = getMemberOfFlag(TgtIdx);
- setCorrectMemberOfFlag(Types[I], MemberOfFlag);
- }
- }
-
- /// Generate the base pointers, section pointers, sizes and map types
- /// associated to a given capture.
- void generateInfoForCapture(const CapturedStmt::Capture *Cap,
- llvm::Value *Arg,
- MapBaseValuesArrayTy &BasePointers,
- MapValuesArrayTy &Pointers,
- MapValuesArrayTy &Sizes, MapFlagsArrayTy &Types,
- StructRangeInfoTy &PartialStruct) const {
- assert(!Cap->capturesVariableArrayType() &&
- "Not expecting to generate map info for a variable array type!");
-
- // We need to know when we generating information for the first component
- const ValueDecl *VD = Cap->capturesThis()
- ? nullptr
- : Cap->getCapturedVar()->getCanonicalDecl();
-
- // If this declaration appears in a is_device_ptr clause we just have to
- // pass the pointer by value. If it is a reference to a declaration, we just
- // pass its value.
- if (DevPointersMap.count(VD)) {
- BasePointers.emplace_back(Arg, VD);
- Pointers.push_back(Arg);
- Sizes.push_back(CGF.getTypeSize(CGF.getContext().VoidPtrTy));
- Types.push_back(OMP_MAP_LITERAL | OMP_MAP_TARGET_PARAM);
- return;
- }
-
- using MapData =
- std::tuple<OMPClauseMappableExprCommon::MappableExprComponentListRef,
- OpenMPMapClauseKind, ArrayRef<OpenMPMapModifierKind>, bool>;
- SmallVector<MapData, 4> DeclComponentLists;
- // FIXME: MSVC 2013 seems to require this-> to find member CurDir.
- for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>()) {
- for (const auto &L : C->decl_component_lists(VD)) {
- assert(L.first == VD &&
- "We got information for the wrong declaration??");
- assert(!L.second.empty() &&
- "Not expecting declaration with no component lists.");
- DeclComponentLists.emplace_back(L.second, C->getMapType(),
- C->getMapTypeModifiers(),
- C->isImplicit());
- }
- }
-
- // Find overlapping elements (including the offset from the base element).
- llvm::SmallDenseMap<
- const MapData *,
- llvm::SmallVector<
- OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>,
- 4>
- OverlappedData;
- size_t Count = 0;
- for (const MapData &L : DeclComponentLists) {
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components;
- OpenMPMapClauseKind MapType;
- ArrayRef<OpenMPMapModifierKind> MapModifiers;
- bool IsImplicit;
- std::tie(Components, MapType, MapModifiers, IsImplicit) = L;
- ++Count;
- for (const MapData &L1 : makeArrayRef(DeclComponentLists).slice(Count)) {
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components1;
- std::tie(Components1, MapType, MapModifiers, IsImplicit) = L1;
- auto CI = Components.rbegin();
- auto CE = Components.rend();
- auto SI = Components1.rbegin();
- auto SE = Components1.rend();
- for (; CI != CE && SI != SE; ++CI, ++SI) {
- if (CI->getAssociatedExpression()->getStmtClass() !=
- SI->getAssociatedExpression()->getStmtClass())
- break;
- // Are we dealing with different variables/fields?
- if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration())
- break;
- }
- // Found overlapping if, at least for one component, reached the head of
- // the components list.
- if (CI == CE || SI == SE) {
- assert((CI != CE || SI != SE) &&
- "Unexpected full match of the mapping components.");
- const MapData &BaseData = CI == CE ? L : L1;
- OMPClauseMappableExprCommon::MappableExprComponentListRef SubData =
- SI == SE ? Components : Components1;
- auto &OverlappedElements = OverlappedData.FindAndConstruct(&BaseData);
- OverlappedElements.getSecond().push_back(SubData);
- }
- }
- }
- // Sort the overlapped elements for each item.
- llvm::SmallVector<const FieldDecl *, 4> Layout;
- if (!OverlappedData.empty()) {
- if (const auto *CRD =
- VD->getType().getCanonicalType()->getAsCXXRecordDecl())
- getPlainLayout(CRD, Layout, /*AsBase=*/false);
- else {
- const auto *RD = VD->getType().getCanonicalType()->getAsRecordDecl();
- Layout.append(RD->field_begin(), RD->field_end());
- }
- }
- for (auto &Pair : OverlappedData) {
- llvm::sort(
- Pair.getSecond(),
- [&Layout](
- OMPClauseMappableExprCommon::MappableExprComponentListRef First,
- OMPClauseMappableExprCommon::MappableExprComponentListRef
- Second) {
- auto CI = First.rbegin();
- auto CE = First.rend();
- auto SI = Second.rbegin();
- auto SE = Second.rend();
- for (; CI != CE && SI != SE; ++CI, ++SI) {
- if (CI->getAssociatedExpression()->getStmtClass() !=
- SI->getAssociatedExpression()->getStmtClass())
- break;
- // Are we dealing with different variables/fields?
- if (CI->getAssociatedDeclaration() !=
- SI->getAssociatedDeclaration())
- break;
- }
-
- // Lists contain the same elements.
- if (CI == CE && SI == SE)
- return false;
-
- // List with less elements is less than list with more elements.
- if (CI == CE || SI == SE)
- return CI == CE;
-
- const auto *FD1 = cast<FieldDecl>(CI->getAssociatedDeclaration());
- const auto *FD2 = cast<FieldDecl>(SI->getAssociatedDeclaration());
- if (FD1->getParent() == FD2->getParent())
- return FD1->getFieldIndex() < FD2->getFieldIndex();
- const auto It =
- llvm::find_if(Layout, [FD1, FD2](const FieldDecl *FD) {
- return FD == FD1 || FD == FD2;
- });
- return *It == FD1;
- });
- }
-
- // Associated with a capture, because the mapping flags depend on it.
- // Go through all of the elements with the overlapped elements.
- for (const auto &Pair : OverlappedData) {
- const MapData &L = *Pair.getFirst();
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components;
- OpenMPMapClauseKind MapType;
- ArrayRef<OpenMPMapModifierKind> MapModifiers;
- bool IsImplicit;
- std::tie(Components, MapType, MapModifiers, IsImplicit) = L;
- ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
- OverlappedComponents = Pair.getSecond();
- bool IsFirstComponentList = true;
- generateInfoForComponentList(MapType, MapModifiers, Components,
- BasePointers, Pointers, Sizes, Types,
- PartialStruct, IsFirstComponentList,
- IsImplicit, OverlappedComponents);
- }
- // Go through other elements without overlapped elements.
- bool IsFirstComponentList = OverlappedData.empty();
- for (const MapData &L : DeclComponentLists) {
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components;
- OpenMPMapClauseKind MapType;
- ArrayRef<OpenMPMapModifierKind> MapModifiers;
- bool IsImplicit;
- std::tie(Components, MapType, MapModifiers, IsImplicit) = L;
- auto It = OverlappedData.find(&L);
- if (It == OverlappedData.end())
- generateInfoForComponentList(MapType, MapModifiers, Components,
- BasePointers, Pointers, Sizes, Types,
- PartialStruct, IsFirstComponentList,
- IsImplicit);
- IsFirstComponentList = false;
- }
- }
-
- /// Generate the base pointers, section pointers, sizes and map types
- /// associated with the declare target link variables.
- void generateInfoForDeclareTargetLink(MapBaseValuesArrayTy &BasePointers,
- MapValuesArrayTy &Pointers,
- MapValuesArrayTy &Sizes,
- MapFlagsArrayTy &Types) const {
- // Map other list items in the map clause which are not captured variables
- // but "declare target link" global variables.,
- for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>()) {
- for (const auto &L : C->component_lists()) {
- if (!L.first)
- continue;
- const auto *VD = dyn_cast<VarDecl>(L.first);
- if (!VD)
- continue;
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)
- continue;
- StructRangeInfoTy PartialStruct;
- generateInfoForComponentList(
- C->getMapType(), C->getMapTypeModifiers(), L.second, BasePointers,
- Pointers, Sizes, Types, PartialStruct,
- /*IsFirstComponentList=*/true, C->isImplicit());
- assert(!PartialStruct.Base.isValid() &&
- "No partial structs for declare target link expected.");
- }
- }
- }
-
- /// Generate the default map information for a given capture \a CI,
- /// record field declaration \a RI and captured value \a CV.
- void generateDefaultMapInfo(const CapturedStmt::Capture &CI,
- const FieldDecl &RI, llvm::Value *CV,
- MapBaseValuesArrayTy &CurBasePointers,
- MapValuesArrayTy &CurPointers,
- MapValuesArrayTy &CurSizes,
- MapFlagsArrayTy &CurMapTypes) const {
- // Do the default mapping.
- if (CI.capturesThis()) {
- CurBasePointers.push_back(CV);
- CurPointers.push_back(CV);
- const auto *PtrTy = cast<PointerType>(RI.getType().getTypePtr());
- CurSizes.push_back(CGF.getTypeSize(PtrTy->getPointeeType()));
- // Default map type.
- CurMapTypes.push_back(OMP_MAP_TO | OMP_MAP_FROM);
- } else if (CI.capturesVariableByCopy()) {
- CurBasePointers.push_back(CV);
- CurPointers.push_back(CV);
- if (!RI.getType()->isAnyPointerType()) {
- // We have to signal to the runtime captures passed by value that are
- // not pointers.
- CurMapTypes.push_back(OMP_MAP_LITERAL);
- CurSizes.push_back(CGF.getTypeSize(RI.getType()));
- } else {
- // Pointers are implicitly mapped with a zero size and no flags
- // (other than first map that is added for all implicit maps).
- CurMapTypes.push_back(OMP_MAP_NONE);
- CurSizes.push_back(llvm::Constant::getNullValue(CGF.SizeTy));
- }
- } else {
- assert(CI.capturesVariable() && "Expected captured reference.");
- CurBasePointers.push_back(CV);
- CurPointers.push_back(CV);
-
- const auto *PtrTy = cast<ReferenceType>(RI.getType().getTypePtr());
- QualType ElementType = PtrTy->getPointeeType();
- CurSizes.push_back(CGF.getTypeSize(ElementType));
- // The default map type for a scalar/complex type is 'to' because by
- // default the value doesn't have to be retrieved. For an aggregate
- // type, the default is 'tofrom'.
- CurMapTypes.push_back(getMapModifiersForPrivateClauses(CI));
- }
- // Every default map produces a single argument which is a target parameter.
- CurMapTypes.back() |= OMP_MAP_TARGET_PARAM;
-
- // Add flag stating this is an implicit map.
- CurMapTypes.back() |= OMP_MAP_IMPLICIT;
- }
-};
-
-enum OpenMPOffloadingReservedDeviceIDs {
- /// Device ID if the device was not defined, runtime should get it
- /// from environment variables in the spec.
- OMP_DEVICEID_UNDEF = -1,
-};
-} // anonymous namespace
-
-/// Emit the arrays used to pass the captures and map information to the
-/// offloading runtime library. If there is no map or capture information,
-/// return nullptr by reference.
-static void
-emitOffloadingArrays(CodeGenFunction &CGF,
- MappableExprsHandler::MapBaseValuesArrayTy &BasePointers,
- MappableExprsHandler::MapValuesArrayTy &Pointers,
- MappableExprsHandler::MapValuesArrayTy &Sizes,
- MappableExprsHandler::MapFlagsArrayTy &MapTypes,
- CGOpenMPRuntime::TargetDataInfo &Info) {
- CodeGenModule &CGM = CGF.CGM;
- ASTContext &Ctx = CGF.getContext();
-
- // Reset the array information.
- Info.clearArrayInfo();
- Info.NumberOfPtrs = BasePointers.size();
-
- if (Info.NumberOfPtrs) {
- // Detect if we have any capture size requiring runtime evaluation of the
- // size so that a constant array could be eventually used.
- bool hasRuntimeEvaluationCaptureSize = false;
- for (llvm::Value *S : Sizes)
- if (!isa<llvm::Constant>(S)) {
- hasRuntimeEvaluationCaptureSize = true;
- break;
- }
-
- llvm::APInt PointerNumAP(32, Info.NumberOfPtrs, /*isSigned=*/true);
- QualType PointerArrayType =
- Ctx.getConstantArrayType(Ctx.VoidPtrTy, PointerNumAP, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
-
- Info.BasePointersArray =
- CGF.CreateMemTemp(PointerArrayType, ".offload_baseptrs").getPointer();
- Info.PointersArray =
- CGF.CreateMemTemp(PointerArrayType, ".offload_ptrs").getPointer();
-
- // If we don't have any VLA types or other types that require runtime
- // evaluation, we can use a constant array for the map sizes, otherwise we
- // need to fill up the arrays as we do for the pointers.
- if (hasRuntimeEvaluationCaptureSize) {
- QualType SizeArrayType = Ctx.getConstantArrayType(
- Ctx.getSizeType(), PointerNumAP, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- Info.SizesArray =
- CGF.CreateMemTemp(SizeArrayType, ".offload_sizes").getPointer();
- } else {
- // We expect all the sizes to be constant, so we collect them to create
- // a constant array.
- SmallVector<llvm::Constant *, 16> ConstSizes;
- for (llvm::Value *S : Sizes)
- ConstSizes.push_back(cast<llvm::Constant>(S));
-
- auto *SizesArrayInit = llvm::ConstantArray::get(
- llvm::ArrayType::get(CGM.SizeTy, ConstSizes.size()), ConstSizes);
- std::string Name = CGM.getOpenMPRuntime().getName({"offload_sizes"});
- auto *SizesArrayGbl = new llvm::GlobalVariable(
- CGM.getModule(), SizesArrayInit->getType(),
- /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
- SizesArrayInit, Name);
- SizesArrayGbl->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- Info.SizesArray = SizesArrayGbl;
- }
-
- // The map types are always constant so we don't need to generate code to
- // fill arrays. Instead, we create an array constant.
- SmallVector<uint64_t, 4> Mapping(MapTypes.size(), 0);
- llvm::copy(MapTypes, Mapping.begin());
- llvm::Constant *MapTypesArrayInit =
- llvm::ConstantDataArray::get(CGF.Builder.getContext(), Mapping);
- std::string MaptypesName =
- CGM.getOpenMPRuntime().getName({"offload_maptypes"});
- auto *MapTypesArrayGbl = new llvm::GlobalVariable(
- CGM.getModule(), MapTypesArrayInit->getType(),
- /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
- MapTypesArrayInit, MaptypesName);
- MapTypesArrayGbl->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- Info.MapTypesArray = MapTypesArrayGbl;
-
- for (unsigned I = 0; I < Info.NumberOfPtrs; ++I) {
- llvm::Value *BPVal = *BasePointers[I];
- llvm::Value *BP = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.BasePointersArray, 0, I);
- BP = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- BP, BPVal->getType()->getPointerTo(/*AddrSpace=*/0));
- Address BPAddr(BP, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
- CGF.Builder.CreateStore(BPVal, BPAddr);
-
- if (Info.requiresDevicePointerInfo())
- if (const ValueDecl *DevVD = BasePointers[I].getDevicePtrDecl())
- Info.CaptureDeviceAddrMap.try_emplace(DevVD, BPAddr);
-
- llvm::Value *PVal = Pointers[I];
- llvm::Value *P = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.PointersArray, 0, I);
- P = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- P, PVal->getType()->getPointerTo(/*AddrSpace=*/0));
- Address PAddr(P, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
- CGF.Builder.CreateStore(PVal, PAddr);
-
- if (hasRuntimeEvaluationCaptureSize) {
- llvm::Value *S = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.SizeTy, Info.NumberOfPtrs),
- Info.SizesArray,
- /*Idx0=*/0,
- /*Idx1=*/I);
- Address SAddr(S, Ctx.getTypeAlignInChars(Ctx.getSizeType()));
- CGF.Builder.CreateStore(
- CGF.Builder.CreateIntCast(Sizes[I], CGM.SizeTy, /*isSigned=*/true),
- SAddr);
- }
- }
- }
-}
-/// Emit the arguments to be passed to the runtime library based on the
-/// arrays of pointers, sizes and map types.
-static void emitOffloadingArraysArgument(
- CodeGenFunction &CGF, llvm::Value *&BasePointersArrayArg,
- llvm::Value *&PointersArrayArg, llvm::Value *&SizesArrayArg,
- llvm::Value *&MapTypesArrayArg, CGOpenMPRuntime::TargetDataInfo &Info) {
- CodeGenModule &CGM = CGF.CGM;
- if (Info.NumberOfPtrs) {
- BasePointersArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.BasePointersArray,
- /*Idx0=*/0, /*Idx1=*/0);
- PointersArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.PointersArray,
- /*Idx0=*/0,
- /*Idx1=*/0);
- SizesArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.SizeTy, Info.NumberOfPtrs), Info.SizesArray,
- /*Idx0=*/0, /*Idx1=*/0);
- MapTypesArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.Int64Ty, Info.NumberOfPtrs),
- Info.MapTypesArray,
- /*Idx0=*/0,
- /*Idx1=*/0);
- } else {
- BasePointersArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- PointersArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- SizesArrayArg = llvm::ConstantPointerNull::get(CGM.SizeTy->getPointerTo());
- MapTypesArrayArg =
- llvm::ConstantPointerNull::get(CGM.Int64Ty->getPointerTo());
- }
-}
-
-/// Checks if the expression is constant or does not have non-trivial function
-/// calls.
-static bool isTrivial(ASTContext &Ctx, const Expr * E) {
- // We can skip constant expressions.
- // We can skip expressions with trivial calls or simple expressions.
- return (E->isEvaluatable(Ctx, Expr::SE_AllowUndefinedBehavior) ||
- !E->hasNonTrivialCall(Ctx)) &&
- !E->HasSideEffects(Ctx, /*IncludePossibleEffects=*/true);
-}
-
-/// Checks if the \p Body is the \a CompoundStmt and returns its child statement
-/// iff there is only one that is not evaluatable at the compile time.
-static const Stmt *getSingleCompoundChild(ASTContext &Ctx, const Stmt *Body) {
- if (const auto *C = dyn_cast<CompoundStmt>(Body)) {
- const Stmt *Child = nullptr;
- for (const Stmt *S : C->body()) {
- if (const auto *E = dyn_cast<Expr>(S)) {
- if (isTrivial(Ctx, E))
- continue;
- }
- // Some of the statements can be ignored.
- if (isa<AsmStmt>(S) || isa<NullStmt>(S) || isa<OMPFlushDirective>(S) ||
- isa<OMPBarrierDirective>(S) || isa<OMPTaskyieldDirective>(S))
- continue;
- // Analyze declarations.
- if (const auto *DS = dyn_cast<DeclStmt>(S)) {
- if (llvm::all_of(DS->decls(), [&Ctx](const Decl *D) {
- if (isa<EmptyDecl>(D) || isa<DeclContext>(D) ||
- isa<TypeDecl>(D) || isa<PragmaCommentDecl>(D) ||
- isa<PragmaDetectMismatchDecl>(D) || isa<UsingDecl>(D) ||
- isa<UsingDirectiveDecl>(D) ||
- isa<OMPDeclareReductionDecl>(D) ||
- isa<OMPThreadPrivateDecl>(D))
- return true;
- const auto *VD = dyn_cast<VarDecl>(D);
- if (!VD)
- return false;
- return VD->isConstexpr() ||
- ((VD->getType().isTrivialType(Ctx) ||
- VD->getType()->isReferenceType()) &&
- (!VD->hasInit() || isTrivial(Ctx, VD->getInit())));
- }))
- continue;
- }
- // Found multiple children - cannot get the one child only.
- if (Child)
- return Body;
- Child = S;
- }
- if (Child)
- return Child;
- }
- return Body;
-}
-
-/// Check for inner distribute directive.
-static const OMPExecutableDirective *
-getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
- const auto *CS = D.getInnermostCapturedStmt();
- const auto *Body =
- CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
- const Stmt *ChildStmt = getSingleCompoundChild(Ctx, Body);
-
- if (const auto *NestedDir = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
- switch (D.getDirectiveKind()) {
- case OMPD_target:
- if (isOpenMPDistributeDirective(DKind))
- return NestedDir;
- if (DKind == OMPD_teams) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return nullptr;
- ChildStmt = getSingleCompoundChild(Ctx, Body);
- if (const auto *NND = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPDistributeDirective(DKind))
- return NND;
- }
- }
- return nullptr;
- case OMPD_target_teams:
- if (isOpenMPDistributeDirective(DKind))
- return NestedDir;
- return nullptr;
- case OMPD_target_parallel:
- case OMPD_target_simd:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
- return nullptr;
- case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_target:
- case OMPD_end_declare_target:
- case OMPD_declare_reduction:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- llvm_unreachable("Unexpected directive.");
- }
- }
-
- return nullptr;
-}
-
-void CGOpenMPRuntime::emitTargetNumIterationsCall(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *Device,
- const llvm::function_ref<llvm::Value *(
- CodeGenFunction &CGF, const OMPLoopDirective &D)> &SizeEmitter) {
- OpenMPDirectiveKind Kind = D.getDirectiveKind();
- const OMPExecutableDirective *TD = &D;
- // Get nested teams distribute kind directive, if any.
- if (!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind))
- TD = getNestedDistributeDirective(CGM.getContext(), D);
- if (!TD)
- return;
- const auto *LD = cast<OMPLoopDirective>(TD);
- auto &&CodeGen = [LD, &Device, &SizeEmitter, this](CodeGenFunction &CGF,
- PrePostActionTy &) {
- llvm::Value *NumIterations = SizeEmitter(CGF, *LD);
-
- // Emit device ID if any.
- llvm::Value *DeviceID;
- if (Device)
- DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
- CGF.Int64Ty, /*isSigned=*/true);
- else
- DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
-
- llvm::Value *Args[] = {DeviceID, NumIterations};
- CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_push_target_tripcount), Args);
- };
- emitInlinedDirective(CGF, OMPD_unknown, CodeGen);
-}
-
-void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- llvm::Value *OutlinedFn,
- llvm::Value *OutlinedFnID,
- const Expr *IfCond, const Expr *Device) {
- if (!CGF.HaveInsertPoint())
- return;
-
- assert(OutlinedFn && "Invalid outlined function!");
-
- const bool RequiresOuterTask = D.hasClausesOfKind<OMPDependClause>();
- llvm::SmallVector<llvm::Value *, 16> CapturedVars;
- const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
- auto &&ArgsCodegen = [&CS, &CapturedVars](CodeGenFunction &CGF,
- PrePostActionTy &) {
- CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
- };
- emitInlinedDirective(CGF, OMPD_unknown, ArgsCodegen);
-
- CodeGenFunction::OMPTargetDataInfo InputInfo;
- llvm::Value *MapTypesArray = nullptr;
- // Fill up the pointer arrays and transfer execution to the device.
- auto &&ThenGen = [this, Device, OutlinedFn, OutlinedFnID, &D, &InputInfo,
- &MapTypesArray, &CS, RequiresOuterTask,
- &CapturedVars](CodeGenFunction &CGF, PrePostActionTy &) {
- // On top of the arrays that were filled up, the target offloading call
- // takes as arguments the device id as well as the host pointer. The host
- // pointer is used by the runtime library to identify the current target
- // region, so it only has to be unique and not necessarily point to
- // anything. It could be the pointer to the outlined function that
- // implements the target region, but we aren't using that so that the
- // compiler doesn't need to keep that, and could therefore inline the host
- // function if proven worthwhile during optimization.
-
- // From this point on, we need to have an ID of the target region defined.
- assert(OutlinedFnID && "Invalid outlined function ID!");
-
- // Emit device ID if any.
- llvm::Value *DeviceID;
- if (Device) {
- DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
- CGF.Int64Ty, /*isSigned=*/true);
- } else {
- DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
- }
-
- // Emit the number of elements in the offloading arrays.
- llvm::Value *PointerNum =
- CGF.Builder.getInt32(InputInfo.NumberOfTargetItems);
-
- // Return value of the runtime offloading call.
- llvm::Value *Return;
-
- llvm::Value *NumTeams = emitNumTeamsForTargetDirective(*this, CGF, D);
- llvm::Value *NumThreads = emitNumThreadsForTargetDirective(*this, CGF, D);
-
- bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
- // The target region is an outlined function launched by the runtime
- // via calls __tgt_target() or __tgt_target_teams().
- //
- // __tgt_target() launches a target region with one team and one thread,
- // executing a serial region. This master thread may in turn launch
- // more threads within its team upon encountering a parallel region,
- // however, no additional teams can be launched on the device.
- //
- // __tgt_target_teams() launches a target region with one or more teams,
- // each with one or more threads. This call is required for target
- // constructs such as:
- // 'target teams'
- // 'target' / 'teams'
- // 'target teams distribute parallel for'
- // 'target parallel'
- // and so on.
- //
- // Note that on the host and CPU targets, the runtime implementation of
- // these calls simply call the outlined function without forking threads.
- // The outlined functions themselves have runtime calls to
- // __kmpc_fork_teams() and __kmpc_fork() for this purpose, codegen'd by
- // the compiler in emitTeamsCall() and emitParallelCall().
- //
- // In contrast, on the NVPTX target, the implementation of
- // __tgt_target_teams() launches a GPU kernel with the requested number
- // of teams and threads so no additional calls to the runtime are required.
- if (NumTeams) {
- // If we have NumTeams defined this means that we have an enclosed teams
- // region. Therefore we also expect to have NumThreads defined. These two
- // values should be defined in the presence of a teams directive,
- // regardless of having any clauses associated. If the user is using teams
- // but no clauses, these two values will be the default that should be
- // passed to the runtime library - a 32-bit integer with the value zero.
- assert(NumThreads && "Thread limit expression should be available along "
- "with number of teams.");
- llvm::Value *OffloadingArgs[] = {DeviceID,
- OutlinedFnID,
- PointerNum,
- InputInfo.BasePointersArray.getPointer(),
- InputInfo.PointersArray.getPointer(),
- InputInfo.SizesArray.getPointer(),
- MapTypesArray,
- NumTeams,
- NumThreads};
- Return = CGF.EmitRuntimeCall(
- createRuntimeFunction(HasNowait ? OMPRTL__tgt_target_teams_nowait
- : OMPRTL__tgt_target_teams),
- OffloadingArgs);
- } else {
- llvm::Value *OffloadingArgs[] = {DeviceID,
- OutlinedFnID,
- PointerNum,
- InputInfo.BasePointersArray.getPointer(),
- InputInfo.PointersArray.getPointer(),
- InputInfo.SizesArray.getPointer(),
- MapTypesArray};
- Return = CGF.EmitRuntimeCall(
- createRuntimeFunction(HasNowait ? OMPRTL__tgt_target_nowait
- : OMPRTL__tgt_target),
- OffloadingArgs);
- }
-
- // Check the error code and execute the host version if required.
- llvm::BasicBlock *OffloadFailedBlock =
- CGF.createBasicBlock("omp_offload.failed");
- llvm::BasicBlock *OffloadContBlock =
- CGF.createBasicBlock("omp_offload.cont");
- llvm::Value *Failed = CGF.Builder.CreateIsNotNull(Return);
- CGF.Builder.CreateCondBr(Failed, OffloadFailedBlock, OffloadContBlock);
-
- CGF.EmitBlock(OffloadFailedBlock);
- if (RequiresOuterTask) {
- CapturedVars.clear();
- CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
- }
- emitOutlinedFunctionCall(CGF, D.getBeginLoc(), OutlinedFn, CapturedVars);
- CGF.EmitBranch(OffloadContBlock);
-
- CGF.EmitBlock(OffloadContBlock, /*IsFinished=*/true);
- };
-
- // Notify that the host version must be executed.
- auto &&ElseGen = [this, &D, OutlinedFn, &CS, &CapturedVars,
- RequiresOuterTask](CodeGenFunction &CGF,
- PrePostActionTy &) {
- if (RequiresOuterTask) {
- CapturedVars.clear();
- CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
- }
- emitOutlinedFunctionCall(CGF, D.getBeginLoc(), OutlinedFn, CapturedVars);
- };
-
- auto &&TargetThenGen = [this, &ThenGen, &D, &InputInfo, &MapTypesArray,
- &CapturedVars, RequiresOuterTask,
- &CS](CodeGenFunction &CGF, PrePostActionTy &) {
- // Fill up the arrays with all the captured variables.
- MappableExprsHandler::MapBaseValuesArrayTy BasePointers;
- MappableExprsHandler::MapValuesArrayTy Pointers;
- MappableExprsHandler::MapValuesArrayTy Sizes;
- MappableExprsHandler::MapFlagsArrayTy MapTypes;
-
- // Get mappable expression information.
- MappableExprsHandler MEHandler(D, CGF);
- llvm::DenseMap<llvm::Value *, llvm::Value *> LambdaPointers;
-
- auto RI = CS.getCapturedRecordDecl()->field_begin();
- auto CV = CapturedVars.begin();
- for (CapturedStmt::const_capture_iterator CI = CS.capture_begin(),
- CE = CS.capture_end();
- CI != CE; ++CI, ++RI, ++CV) {
- MappableExprsHandler::MapBaseValuesArrayTy CurBasePointers;
- MappableExprsHandler::MapValuesArrayTy CurPointers;
- MappableExprsHandler::MapValuesArrayTy CurSizes;
- MappableExprsHandler::MapFlagsArrayTy CurMapTypes;
- MappableExprsHandler::StructRangeInfoTy PartialStruct;
-
- // VLA sizes are passed to the outlined region by copy and do not have map
- // information associated.
- if (CI->capturesVariableArrayType()) {
- CurBasePointers.push_back(*CV);
- CurPointers.push_back(*CV);
- CurSizes.push_back(CGF.getTypeSize(RI->getType()));
- // Copy to the device as an argument. No need to retrieve it.
- CurMapTypes.push_back(MappableExprsHandler::OMP_MAP_LITERAL |
- MappableExprsHandler::OMP_MAP_TARGET_PARAM);
- } else {
- // If we have any information in the map clause, we use it, otherwise we
- // just do a default mapping.
- MEHandler.generateInfoForCapture(CI, *CV, CurBasePointers, CurPointers,
- CurSizes, CurMapTypes, PartialStruct);
- if (CurBasePointers.empty())
- MEHandler.generateDefaultMapInfo(*CI, **RI, *CV, CurBasePointers,
- CurPointers, CurSizes, CurMapTypes);
- // Generate correct mapping for variables captured by reference in
- // lambdas.
- if (CI->capturesVariable())
- MEHandler.generateInfoForLambdaCaptures(
- CI->getCapturedVar(), *CV, CurBasePointers, CurPointers, CurSizes,
- CurMapTypes, LambdaPointers);
- }
- // We expect to have at least an element of information for this capture.
- assert(!CurBasePointers.empty() &&
- "Non-existing map pointer for capture!");
- assert(CurBasePointers.size() == CurPointers.size() &&
- CurBasePointers.size() == CurSizes.size() &&
- CurBasePointers.size() == CurMapTypes.size() &&
- "Inconsistent map information sizes!");
-
- // If there is an entry in PartialStruct it means we have a struct with
- // individual members mapped. Emit an extra combined entry.
- if (PartialStruct.Base.isValid())
- MEHandler.emitCombinedEntry(BasePointers, Pointers, Sizes, MapTypes,
- CurMapTypes, PartialStruct);
-
- // We need to append the results of this capture to what we already have.
- BasePointers.append(CurBasePointers.begin(), CurBasePointers.end());
- Pointers.append(CurPointers.begin(), CurPointers.end());
- Sizes.append(CurSizes.begin(), CurSizes.end());
- MapTypes.append(CurMapTypes.begin(), CurMapTypes.end());
- }
- // Adjust MEMBER_OF flags for the lambdas captures.
- MEHandler.adjustMemberOfForLambdaCaptures(LambdaPointers, BasePointers,
- Pointers, MapTypes);
- // Map other list items in the map clause which are not captured variables
- // but "declare target link" global variables.
- MEHandler.generateInfoForDeclareTargetLink(BasePointers, Pointers, Sizes,
- MapTypes);
-
- TargetDataInfo Info;
- // Fill up the arrays and create the arguments.
- emitOffloadingArrays(CGF, BasePointers, Pointers, Sizes, MapTypes, Info);
- emitOffloadingArraysArgument(CGF, Info.BasePointersArray,
- Info.PointersArray, Info.SizesArray,
- Info.MapTypesArray, Info);
- InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
- InputInfo.BasePointersArray =
- Address(Info.BasePointersArray, CGM.getPointerAlign());
- InputInfo.PointersArray =
- Address(Info.PointersArray, CGM.getPointerAlign());
- InputInfo.SizesArray = Address(Info.SizesArray, CGM.getPointerAlign());
- MapTypesArray = Info.MapTypesArray;
- if (RequiresOuterTask)
- CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
- else
- emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
- };
-
- auto &&TargetElseGen = [this, &ElseGen, &D, RequiresOuterTask](
- CodeGenFunction &CGF, PrePostActionTy &) {
- if (RequiresOuterTask) {
- CodeGenFunction::OMPTargetDataInfo InputInfo;
- CGF.EmitOMPTargetTaskBasedDirective(D, ElseGen, InputInfo);
- } else {
- emitInlinedDirective(CGF, D.getDirectiveKind(), ElseGen);
- }
- };
-
- // If we have a target function ID it means that we need to support
- // offloading, otherwise, just execute on the host. We need to execute on host
- // regardless of the conditional in the if clause if, e.g., the user do not
- // specify target triples.
- if (OutlinedFnID) {
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, TargetThenGen, TargetElseGen);
- } else {
- RegionCodeGenTy ThenRCG(TargetThenGen);
- ThenRCG(CGF);
- }
- } else {
- RegionCodeGenTy ElseRCG(TargetElseGen);
- ElseRCG(CGF);
- }
-}
-
-void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
- StringRef ParentName) {
- if (!S)
- return;
-
- // Codegen OMP target directives that offload compute to the device.
- bool RequiresDeviceCodegen =
- isa<OMPExecutableDirective>(S) &&
- isOpenMPTargetExecutionDirective(
- cast<OMPExecutableDirective>(S)->getDirectiveKind());
-
- if (RequiresDeviceCodegen) {
- const auto &E = *cast<OMPExecutableDirective>(S);
- unsigned DeviceID;
- unsigned FileID;
- unsigned Line;
- getTargetEntryUniqueInfo(CGM.getContext(), E.getBeginLoc(), DeviceID,
- FileID, Line);
-
- // Is this a target region that should not be emitted as an entry point? If
- // so just signal we are done with this target region.
- if (!OffloadEntriesInfoManager.hasTargetRegionEntryInfo(DeviceID, FileID,
- ParentName, Line))
- return;
-
- switch (E.getDirectiveKind()) {
- case OMPD_target:
- CodeGenFunction::EmitOMPTargetDeviceFunction(CGM, ParentName,
- cast<OMPTargetDirective>(E));
- break;
- case OMPD_target_parallel:
- CodeGenFunction::EmitOMPTargetParallelDeviceFunction(
- CGM, ParentName, cast<OMPTargetParallelDirective>(E));
- break;
- case OMPD_target_teams:
- CodeGenFunction::EmitOMPTargetTeamsDeviceFunction(
- CGM, ParentName, cast<OMPTargetTeamsDirective>(E));
- break;
- case OMPD_target_teams_distribute:
- CodeGenFunction::EmitOMPTargetTeamsDistributeDeviceFunction(
- CGM, ParentName, cast<OMPTargetTeamsDistributeDirective>(E));
- break;
- case OMPD_target_teams_distribute_simd:
- CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDeviceFunction(
- CGM, ParentName, cast<OMPTargetTeamsDistributeSimdDirective>(E));
- break;
- case OMPD_target_parallel_for:
- CodeGenFunction::EmitOMPTargetParallelForDeviceFunction(
- CGM, ParentName, cast<OMPTargetParallelForDirective>(E));
- break;
- case OMPD_target_parallel_for_simd:
- CodeGenFunction::EmitOMPTargetParallelForSimdDeviceFunction(
- CGM, ParentName, cast<OMPTargetParallelForSimdDirective>(E));
- break;
- case OMPD_target_simd:
- CodeGenFunction::EmitOMPTargetSimdDeviceFunction(
- CGM, ParentName, cast<OMPTargetSimdDirective>(E));
- break;
- case OMPD_target_teams_distribute_parallel_for:
- CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDeviceFunction(
- CGM, ParentName,
- cast<OMPTargetTeamsDistributeParallelForDirective>(E));
- break;
- case OMPD_target_teams_distribute_parallel_for_simd:
- CodeGenFunction::
- EmitOMPTargetTeamsDistributeParallelForSimdDeviceFunction(
- CGM, ParentName,
- cast<OMPTargetTeamsDistributeParallelForSimdDirective>(E));
- break;
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_target:
- case OMPD_end_declare_target:
- case OMPD_declare_reduction:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- llvm_unreachable("Unknown target directive for OpenMP device codegen.");
- }
- return;
- }
-
- if (const auto *E = dyn_cast<OMPExecutableDirective>(S)) {
- if (!E->hasAssociatedStmt() || !E->getAssociatedStmt())
- return;
-
- scanForTargetRegionsFunctions(
- E->getInnermostCapturedStmt()->getCapturedStmt(), ParentName);
- return;
- }
-
- // If this is a lambda function, look into its body.
- if (const auto *L = dyn_cast<LambdaExpr>(S))
- S = L->getBody();
-
- // Keep looking for target regions recursively.
- for (const Stmt *II : S->children())
- scanForTargetRegionsFunctions(II, ParentName);
-}
-
-bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) {
- // If emitting code for the host, we do not process FD here. Instead we do
- // the normal code generation.
- if (!CGM.getLangOpts().OpenMPIsDevice)
- return false;
-
- const ValueDecl *VD = cast<ValueDecl>(GD.getDecl());
- StringRef Name = CGM.getMangledName(GD);
- // Try to detect target regions in the function.
- if (const auto *FD = dyn_cast<FunctionDecl>(VD))
- scanForTargetRegionsFunctions(FD->getBody(), Name);
-
- // Do not to emit function if it is not marked as declare target.
- return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
- AlreadyEmittedTargetFunctions.count(Name) == 0;
-}
-
-bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
- if (!CGM.getLangOpts().OpenMPIsDevice)
- return false;
-
- // Check if there are Ctors/Dtors in this declaration and look for target
- // regions in it. We use the complete variant to produce the kernel name
- // mangling.
- QualType RDTy = cast<VarDecl>(GD.getDecl())->getType();
- if (const auto *RD = RDTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
- for (const CXXConstructorDecl *Ctor : RD->ctors()) {
- StringRef ParentName =
- CGM.getMangledName(GlobalDecl(Ctor, Ctor_Complete));
- scanForTargetRegionsFunctions(Ctor->getBody(), ParentName);
- }
- if (const CXXDestructorDecl *Dtor = RD->getDestructor()) {
- StringRef ParentName =
- CGM.getMangledName(GlobalDecl(Dtor, Dtor_Complete));
- scanForTargetRegionsFunctions(Dtor->getBody(), ParentName);
- }
- }
-
- // Do not to emit variable if it is not marked as declare target.
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
- cast<VarDecl>(GD.getDecl()));
- if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link) {
- DeferredGlobalVariables.insert(cast<VarDecl>(GD.getDecl()));
- return true;
- }
- return false;
-}
-
-void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
- llvm::Constant *Addr) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (!Res) {
- if (CGM.getLangOpts().OpenMPIsDevice) {
- // Register non-target variables being emitted in device code (debug info
- // may cause this).
- StringRef VarName = CGM.getMangledName(VD);
- EmittedNonTargetVariables.try_emplace(VarName, Addr);
- }
- return;
- }
- // Register declare target variables.
- OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind Flags;
- StringRef VarName;
- CharUnits VarSize;
- llvm::GlobalValue::LinkageTypes Linkage;
- switch (*Res) {
- case OMPDeclareTargetDeclAttr::MT_To:
- Flags = OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryTo;
- VarName = CGM.getMangledName(VD);
- if (VD->hasDefinition(CGM.getContext()) != VarDecl::DeclarationOnly) {
- VarSize = CGM.getContext().getTypeSizeInChars(VD->getType());
- assert(!VarSize.isZero() && "Expected non-zero size of the variable");
- } else {
- VarSize = CharUnits::Zero();
- }
- Linkage = CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false);
- // Temp solution to prevent optimizations of the internal variables.
- if (CGM.getLangOpts().OpenMPIsDevice && !VD->isExternallyVisible()) {
- std::string RefName = getName({VarName, "ref"});
- if (!CGM.GetGlobalValue(RefName)) {
- llvm::Constant *AddrRef =
- getOrCreateInternalVariable(Addr->getType(), RefName);
- auto *GVAddrRef = cast<llvm::GlobalVariable>(AddrRef);
- GVAddrRef->setConstant(/*Val=*/true);
- GVAddrRef->setLinkage(llvm::GlobalValue::InternalLinkage);
- GVAddrRef->setInitializer(Addr);
- CGM.addCompilerUsedGlobal(GVAddrRef);
- }
- }
- break;
- case OMPDeclareTargetDeclAttr::MT_Link:
- Flags = OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryLink;
- if (CGM.getLangOpts().OpenMPIsDevice) {
- VarName = Addr->getName();
- Addr = nullptr;
- } else {
- VarName = getAddrOfDeclareTargetLink(VD).getName();
- Addr = cast<llvm::Constant>(getAddrOfDeclareTargetLink(VD).getPointer());
- }
- VarSize = CGM.getPointerSize();
- Linkage = llvm::GlobalValue::WeakAnyLinkage;
- break;
- }
- OffloadEntriesInfoManager.registerDeviceGlobalVarEntryInfo(
- VarName, Addr, VarSize, Flags, Linkage);
-}
-
-bool CGOpenMPRuntime::emitTargetGlobal(GlobalDecl GD) {
- if (isa<FunctionDecl>(GD.getDecl()) ||
- isa<OMPDeclareReductionDecl>(GD.getDecl()))
- return emitTargetFunctions(GD);
-
- return emitTargetGlobalVariable(GD);
-}
-
-void CGOpenMPRuntime::emitDeferredTargetDecls() const {
- for (const VarDecl *VD : DeferredGlobalVariables) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (!Res)
- continue;
- if (*Res == OMPDeclareTargetDeclAttr::MT_To) {
- CGM.EmitGlobal(VD);
- } else {
- assert(*Res == OMPDeclareTargetDeclAttr::MT_Link &&
- "Expected to or link clauses.");
- (void)CGM.getOpenMPRuntime().getAddrOfDeclareTargetLink(VD);
- }
- }
-}
-
-void CGOpenMPRuntime::adjustTargetSpecificDataForLambdas(
- CodeGenFunction &CGF, const OMPExecutableDirective &D) const {
- assert(isOpenMPTargetExecutionDirective(D.getDirectiveKind()) &&
- " Expected target-based directive.");
-}
-
-CGOpenMPRuntime::DisableAutoDeclareTargetRAII::DisableAutoDeclareTargetRAII(
- CodeGenModule &CGM)
- : CGM(CGM) {
- if (CGM.getLangOpts().OpenMPIsDevice) {
- SavedShouldMarkAsGlobal = CGM.getOpenMPRuntime().ShouldMarkAsGlobal;
- CGM.getOpenMPRuntime().ShouldMarkAsGlobal = false;
- }
-}
-
-CGOpenMPRuntime::DisableAutoDeclareTargetRAII::~DisableAutoDeclareTargetRAII() {
- if (CGM.getLangOpts().OpenMPIsDevice)
- CGM.getOpenMPRuntime().ShouldMarkAsGlobal = SavedShouldMarkAsGlobal;
-}
-
-bool CGOpenMPRuntime::markAsGlobalTarget(GlobalDecl GD) {
- if (!CGM.getLangOpts().OpenMPIsDevice || !ShouldMarkAsGlobal)
- return true;
-
- StringRef Name = CGM.getMangledName(GD);
- const auto *D = cast<FunctionDecl>(GD.getDecl());
- // Do not to emit function if it is marked as declare target as it was already
- // emitted.
- if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(D)) {
- if (D->hasBody() && AlreadyEmittedTargetFunctions.count(Name) == 0) {
- if (auto *F = dyn_cast_or_null<llvm::Function>(CGM.GetGlobalValue(Name)))
- return !F->isDeclaration();
- return false;
- }
- return true;
- }
-
- return !AlreadyEmittedTargetFunctions.insert(Name).second;
-}
-
-llvm::Function *CGOpenMPRuntime::emitRegistrationFunction() {
- // If we have offloading in the current module, we need to emit the entries
- // now and register the offloading descriptor.
- createOffloadEntriesAndInfoMetadata();
-
- // Create and register the offloading binary descriptors. This is the main
- // entity that captures all the information about offloading in the current
- // compilation unit.
- return createOffloadingBinaryDescriptorRegistration();
-}
-
-void CGOpenMPRuntime::emitTeamsCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars) {
- if (!CGF.HaveInsertPoint())
- return;
-
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- CodeGenFunction::RunCleanupsScope Scope(CGF);
-
- // Build call __kmpc_fork_teams(loc, n, microtask, var1, .., varn);
- llvm::Value *Args[] = {
- RTLoc,
- CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
- CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy())};
- llvm::SmallVector<llvm::Value *, 16> RealArgs;
- RealArgs.append(std::begin(Args), std::end(Args));
- RealArgs.append(CapturedVars.begin(), CapturedVars.end());
-
- llvm::Value *RTLFn = createRuntimeFunction(OMPRTL__kmpc_fork_teams);
- CGF.EmitRuntimeCall(RTLFn, RealArgs);
-}
-
-void CGOpenMPRuntime::emitNumTeamsClause(CodeGenFunction &CGF,
- const Expr *NumTeams,
- const Expr *ThreadLimit,
- SourceLocation Loc) {
- if (!CGF.HaveInsertPoint())
- return;
-
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
-
- llvm::Value *NumTeamsVal =
- NumTeams
- ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(NumTeams),
- CGF.CGM.Int32Ty, /* isSigned = */ true)
- : CGF.Builder.getInt32(0);
-
- llvm::Value *ThreadLimitVal =
- ThreadLimit
- ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(ThreadLimit),
- CGF.CGM.Int32Ty, /* isSigned = */ true)
- : CGF.Builder.getInt32(0);
-
- // Build call __kmpc_push_num_teamss(&loc, global_tid, num_teams, thread_limit)
- llvm::Value *PushNumTeamsArgs[] = {RTLoc, getThreadID(CGF, Loc), NumTeamsVal,
- ThreadLimitVal};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_push_num_teams),
- PushNumTeamsArgs);
-}
-
-void CGOpenMPRuntime::emitTargetDataCalls(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
- const Expr *Device, const RegionCodeGenTy &CodeGen, TargetDataInfo &Info) {
- if (!CGF.HaveInsertPoint())
- return;
-
- // Action used to replace the default codegen action and turn privatization
- // off.
- PrePostActionTy NoPrivAction;
-
- // Generate the code for the opening of the data environment. Capture all the
- // arguments of the runtime call by reference because they are used in the
- // closing of the region.
- auto &&BeginThenGen = [this, &D, Device, &Info,
- &CodeGen](CodeGenFunction &CGF, PrePostActionTy &) {
- // Fill up the arrays with all the mapped variables.
- MappableExprsHandler::MapBaseValuesArrayTy BasePointers;
- MappableExprsHandler::MapValuesArrayTy Pointers;
- MappableExprsHandler::MapValuesArrayTy Sizes;
- MappableExprsHandler::MapFlagsArrayTy MapTypes;
-
- // Get map clause information.
- MappableExprsHandler MCHandler(D, CGF);
- MCHandler.generateAllInfo(BasePointers, Pointers, Sizes, MapTypes);
-
- // Fill up the arrays and create the arguments.
- emitOffloadingArrays(CGF, BasePointers, Pointers, Sizes, MapTypes, Info);
-
- llvm::Value *BasePointersArrayArg = nullptr;
- llvm::Value *PointersArrayArg = nullptr;
- llvm::Value *SizesArrayArg = nullptr;
- llvm::Value *MapTypesArrayArg = nullptr;
- emitOffloadingArraysArgument(CGF, BasePointersArrayArg, PointersArrayArg,
- SizesArrayArg, MapTypesArrayArg, Info);
-
- // Emit device ID if any.
- llvm::Value *DeviceID = nullptr;
- if (Device) {
- DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
- CGF.Int64Ty, /*isSigned=*/true);
- } else {
- DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
- }
-
- // Emit the number of elements in the offloading arrays.
- llvm::Value *PointerNum = CGF.Builder.getInt32(Info.NumberOfPtrs);
-
- llvm::Value *OffloadingArgs[] = {
- DeviceID, PointerNum, BasePointersArrayArg,
- PointersArrayArg, SizesArrayArg, MapTypesArrayArg};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_target_data_begin),
- OffloadingArgs);
-
- // If device pointer privatization is required, emit the body of the region
- // here. It will have to be duplicated: with and without privatization.
- if (!Info.CaptureDeviceAddrMap.empty())
- CodeGen(CGF);
- };
-
- // Generate code for the closing of the data region.
- auto &&EndThenGen = [this, Device, &Info](CodeGenFunction &CGF,
- PrePostActionTy &) {
- assert(Info.isValid() && "Invalid data environment closing arguments.");
-
- llvm::Value *BasePointersArrayArg = nullptr;
- llvm::Value *PointersArrayArg = nullptr;
- llvm::Value *SizesArrayArg = nullptr;
- llvm::Value *MapTypesArrayArg = nullptr;
- emitOffloadingArraysArgument(CGF, BasePointersArrayArg, PointersArrayArg,
- SizesArrayArg, MapTypesArrayArg, Info);
-
- // Emit device ID if any.
- llvm::Value *DeviceID = nullptr;
- if (Device) {
- DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
- CGF.Int64Ty, /*isSigned=*/true);
- } else {
- DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
- }
-
- // Emit the number of elements in the offloading arrays.
- llvm::Value *PointerNum = CGF.Builder.getInt32(Info.NumberOfPtrs);
-
- llvm::Value *OffloadingArgs[] = {
- DeviceID, PointerNum, BasePointersArrayArg,
- PointersArrayArg, SizesArrayArg, MapTypesArrayArg};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_target_data_end),
- OffloadingArgs);
- };
-
- // If we need device pointer privatization, we need to emit the body of the
- // region with no privatization in the 'else' branch of the conditional.
- // Otherwise, we don't have to do anything.
- auto &&BeginElseGen = [&Info, &CodeGen, &NoPrivAction](CodeGenFunction &CGF,
- PrePostActionTy &) {
- if (!Info.CaptureDeviceAddrMap.empty()) {
- CodeGen.setAction(NoPrivAction);
- CodeGen(CGF);
- }
- };
-
- // We don't have to do anything to close the region if the if clause evaluates
- // to false.
- auto &&EndElseGen = [](CodeGenFunction &CGF, PrePostActionTy &) {};
-
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, BeginThenGen, BeginElseGen);
- } else {
- RegionCodeGenTy RCG(BeginThenGen);
- RCG(CGF);
- }
-
- // If we don't require privatization of device pointers, we emit the body in
- // between the runtime calls. This avoids duplicating the body code.
- if (Info.CaptureDeviceAddrMap.empty()) {
- CodeGen.setAction(NoPrivAction);
- CodeGen(CGF);
- }
-
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, EndThenGen, EndElseGen);
- } else {
- RegionCodeGenTy RCG(EndThenGen);
- RCG(CGF);
- }
-}
-
-void CGOpenMPRuntime::emitTargetDataStandAloneCall(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
- const Expr *Device) {
- if (!CGF.HaveInsertPoint())
- return;
-
- assert((isa<OMPTargetEnterDataDirective>(D) ||
- isa<OMPTargetExitDataDirective>(D) ||
- isa<OMPTargetUpdateDirective>(D)) &&
- "Expecting either target enter, exit data, or update directives.");
-
- CodeGenFunction::OMPTargetDataInfo InputInfo;
- llvm::Value *MapTypesArray = nullptr;
- // Generate the code for the opening of the data environment.
- auto &&ThenGen = [this, &D, Device, &InputInfo,
- &MapTypesArray](CodeGenFunction &CGF, PrePostActionTy &) {
- // Emit device ID if any.
- llvm::Value *DeviceID = nullptr;
- if (Device) {
- DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
- CGF.Int64Ty, /*isSigned=*/true);
- } else {
- DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
- }
-
- // Emit the number of elements in the offloading arrays.
- llvm::Constant *PointerNum =
- CGF.Builder.getInt32(InputInfo.NumberOfTargetItems);
-
- llvm::Value *OffloadingArgs[] = {DeviceID,
- PointerNum,
- InputInfo.BasePointersArray.getPointer(),
- InputInfo.PointersArray.getPointer(),
- InputInfo.SizesArray.getPointer(),
- MapTypesArray};
-
- // Select the right runtime function call for each expected standalone
- // directive.
- const bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
- OpenMPRTLFunction RTLFn;
- switch (D.getDirectiveKind()) {
- case OMPD_target_enter_data:
- RTLFn = HasNowait ? OMPRTL__tgt_target_data_begin_nowait
- : OMPRTL__tgt_target_data_begin;
- break;
- case OMPD_target_exit_data:
- RTLFn = HasNowait ? OMPRTL__tgt_target_data_end_nowait
- : OMPRTL__tgt_target_data_end;
- break;
- case OMPD_target_update:
- RTLFn = HasNowait ? OMPRTL__tgt_target_data_update_nowait
- : OMPRTL__tgt_target_data_update;
- break;
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_declare_simd:
- case OMPD_declare_target:
- case OMPD_end_declare_target:
- case OMPD_declare_reduction:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
- case OMPD_target:
- case OMPD_target_simd:
- case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_target_teams:
- case OMPD_target_parallel:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
- case OMPD_requires:
- case OMPD_unknown:
- llvm_unreachable("Unexpected standalone target data directive.");
- break;
- }
- CGF.EmitRuntimeCall(createRuntimeFunction(RTLFn), OffloadingArgs);
- };
-
- auto &&TargetThenGen = [this, &ThenGen, &D, &InputInfo, &MapTypesArray](
- CodeGenFunction &CGF, PrePostActionTy &) {
- // Fill up the arrays with all the mapped variables.
- MappableExprsHandler::MapBaseValuesArrayTy BasePointers;
- MappableExprsHandler::MapValuesArrayTy Pointers;
- MappableExprsHandler::MapValuesArrayTy Sizes;
- MappableExprsHandler::MapFlagsArrayTy MapTypes;
-
- // Get map clause information.
- MappableExprsHandler MEHandler(D, CGF);
- MEHandler.generateAllInfo(BasePointers, Pointers, Sizes, MapTypes);
-
- TargetDataInfo Info;
- // Fill up the arrays and create the arguments.
- emitOffloadingArrays(CGF, BasePointers, Pointers, Sizes, MapTypes, Info);
- emitOffloadingArraysArgument(CGF, Info.BasePointersArray,
- Info.PointersArray, Info.SizesArray,
- Info.MapTypesArray, Info);
- InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
- InputInfo.BasePointersArray =
- Address(Info.BasePointersArray, CGM.getPointerAlign());
- InputInfo.PointersArray =
- Address(Info.PointersArray, CGM.getPointerAlign());
- InputInfo.SizesArray =
- Address(Info.SizesArray, CGM.getPointerAlign());
- MapTypesArray = Info.MapTypesArray;
- if (D.hasClausesOfKind<OMPDependClause>())
- CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
- else
- emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
- };
-
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, TargetThenGen,
- [](CodeGenFunction &CGF, PrePostActionTy &) {});
- } else {
- RegionCodeGenTy ThenRCG(TargetThenGen);
- ThenRCG(CGF);
- }
-}
-
-namespace {
- /// Kind of parameter in a function with 'declare simd' directive.
- enum ParamKindTy { LinearWithVarStride, Linear, Uniform, Vector };
- /// Attribute set of the parameter.
- struct ParamAttrTy {
- ParamKindTy Kind = Vector;
- llvm::APSInt StrideOrArg;
- llvm::APSInt Alignment;
- };
-} // namespace
-
-static unsigned evaluateCDTSize(const FunctionDecl *FD,
- ArrayRef<ParamAttrTy> ParamAttrs) {
- // Every vector variant of a SIMD-enabled function has a vector length (VLEN).
- // If OpenMP clause "simdlen" is used, the VLEN is the value of the argument
- // of that clause. The VLEN value must be power of 2.
- // In other case the notion of the function`s "characteristic data type" (CDT)
- // is used to compute the vector length.
- // CDT is defined in the following order:
- // a) For non-void function, the CDT is the return type.
- // b) If the function has any non-uniform, non-linear parameters, then the
- // CDT is the type of the first such parameter.
- // c) If the CDT determined by a) or b) above is struct, union, or class
- // type which is pass-by-value (except for the type that maps to the
- // built-in complex data type), the characteristic data type is int.
- // d) If none of the above three cases is applicable, the CDT is int.
- // The VLEN is then determined based on the CDT and the size of vector
- // register of that ISA for which current vector version is generated. The
- // VLEN is computed using the formula below:
- // VLEN = sizeof(vector_register) / sizeof(CDT),
- // where vector register size specified in section 3.2.1 Registers and the
- // Stack Frame of original AMD64 ABI document.
- QualType RetType = FD->getReturnType();
- if (RetType.isNull())
- return 0;
- ASTContext &C = FD->getASTContext();
- QualType CDT;
- if (!RetType.isNull() && !RetType->isVoidType()) {
- CDT = RetType;
- } else {
- unsigned Offset = 0;
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
- if (ParamAttrs[Offset].Kind == Vector)
- CDT = C.getPointerType(C.getRecordType(MD->getParent()));
- ++Offset;
- }
- if (CDT.isNull()) {
- for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
- if (ParamAttrs[I + Offset].Kind == Vector) {
- CDT = FD->getParamDecl(I)->getType();
- break;
- }
- }
- }
- }
- if (CDT.isNull())
- CDT = C.IntTy;
- CDT = CDT->getCanonicalTypeUnqualified();
- if (CDT->isRecordType() || CDT->isUnionType())
- CDT = C.IntTy;
- return C.getTypeSize(CDT);
-}
-
-static void
-emitX86DeclareSimdFunction(const FunctionDecl *FD, llvm::Function *Fn,
- const llvm::APSInt &VLENVal,
- ArrayRef<ParamAttrTy> ParamAttrs,
- OMPDeclareSimdDeclAttr::BranchStateTy State) {
- struct ISADataTy {
- char ISA;
- unsigned VecRegSize;
- };
- ISADataTy ISAData[] = {
- {
- 'b', 128
- }, // SSE
- {
- 'c', 256
- }, // AVX
- {
- 'd', 256
- }, // AVX2
- {
- 'e', 512
- }, // AVX512
- };
- llvm::SmallVector<char, 2> Masked;
- switch (State) {
- case OMPDeclareSimdDeclAttr::BS_Undefined:
- Masked.push_back('N');
- Masked.push_back('M');
- break;
- case OMPDeclareSimdDeclAttr::BS_Notinbranch:
- Masked.push_back('N');
- break;
- case OMPDeclareSimdDeclAttr::BS_Inbranch:
- Masked.push_back('M');
- break;
- }
- for (char Mask : Masked) {
- for (const ISADataTy &Data : ISAData) {
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- Out << "_ZGV" << Data.ISA << Mask;
- if (!VLENVal) {
- Out << llvm::APSInt::getUnsigned(Data.VecRegSize /
- evaluateCDTSize(FD, ParamAttrs));
- } else {
- Out << VLENVal;
- }
- for (const ParamAttrTy &ParamAttr : ParamAttrs) {
- switch (ParamAttr.Kind){
- case LinearWithVarStride:
- Out << 's' << ParamAttr.StrideOrArg;
- break;
- case Linear:
- Out << 'l';
- if (!!ParamAttr.StrideOrArg)
- Out << ParamAttr.StrideOrArg;
- break;
- case Uniform:
- Out << 'u';
- break;
- case Vector:
- Out << 'v';
- break;
- }
- if (!!ParamAttr.Alignment)
- Out << 'a' << ParamAttr.Alignment;
- }
- Out << '_' << Fn->getName();
- Fn->addFnAttr(Out.str());
- }
- }
-}
-
-void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD,
- llvm::Function *Fn) {
- ASTContext &C = CGM.getContext();
- FD = FD->getMostRecentDecl();
- // Map params to their positions in function decl.
- llvm::DenseMap<const Decl *, unsigned> ParamPositions;
- if (isa<CXXMethodDecl>(FD))
- ParamPositions.try_emplace(FD, 0);
- unsigned ParamPos = ParamPositions.size();
- for (const ParmVarDecl *P : FD->parameters()) {
- ParamPositions.try_emplace(P->getCanonicalDecl(), ParamPos);
- ++ParamPos;
- }
- while (FD) {
- for (const auto *Attr : FD->specific_attrs<OMPDeclareSimdDeclAttr>()) {
- llvm::SmallVector<ParamAttrTy, 8> ParamAttrs(ParamPositions.size());
- // Mark uniform parameters.
- for (const Expr *E : Attr->uniforms()) {
- E = E->IgnoreParenImpCasts();
- unsigned Pos;
- if (isa<CXXThisExpr>(E)) {
- Pos = ParamPositions[FD];
- } else {
- const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
- ->getCanonicalDecl();
- Pos = ParamPositions[PVD];
- }
- ParamAttrs[Pos].Kind = Uniform;
- }
- // Get alignment info.
- auto NI = Attr->alignments_begin();
- for (const Expr *E : Attr->aligneds()) {
- E = E->IgnoreParenImpCasts();
- unsigned Pos;
- QualType ParmTy;
- if (isa<CXXThisExpr>(E)) {
- Pos = ParamPositions[FD];
- ParmTy = E->getType();
- } else {
- const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
- ->getCanonicalDecl();
- Pos = ParamPositions[PVD];
- ParmTy = PVD->getType();
- }
- ParamAttrs[Pos].Alignment =
- (*NI)
- ? (*NI)->EvaluateKnownConstInt(C)
- : llvm::APSInt::getUnsigned(
- C.toCharUnitsFromBits(C.getOpenMPDefaultSimdAlign(ParmTy))
- .getQuantity());
- ++NI;
- }
- // Mark linear parameters.
- auto SI = Attr->steps_begin();
- auto MI = Attr->modifiers_begin();
- for (const Expr *E : Attr->linears()) {
- E = E->IgnoreParenImpCasts();
- unsigned Pos;
- if (isa<CXXThisExpr>(E)) {
- Pos = ParamPositions[FD];
- } else {
- const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
- ->getCanonicalDecl();
- Pos = ParamPositions[PVD];
- }
- ParamAttrTy &ParamAttr = ParamAttrs[Pos];
- ParamAttr.Kind = Linear;
- if (*SI) {
- Expr::EvalResult Result;
- if (!(*SI)->EvaluateAsInt(Result, C, Expr::SE_AllowSideEffects)) {
- if (const auto *DRE =
- cast<DeclRefExpr>((*SI)->IgnoreParenImpCasts())) {
- if (const auto *StridePVD = cast<ParmVarDecl>(DRE->getDecl())) {
- ParamAttr.Kind = LinearWithVarStride;
- ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(
- ParamPositions[StridePVD->getCanonicalDecl()]);
- }
- }
- } else {
- ParamAttr.StrideOrArg = Result.Val.getInt();
- }
- }
- ++SI;
- ++MI;
- }
- llvm::APSInt VLENVal;
- if (const Expr *VLEN = Attr->getSimdlen())
- VLENVal = VLEN->EvaluateKnownConstInt(C);
- OMPDeclareSimdDeclAttr::BranchStateTy State = Attr->getBranchState();
- if (CGM.getTriple().getArch() == llvm::Triple::x86 ||
- CGM.getTriple().getArch() == llvm::Triple::x86_64)
- emitX86DeclareSimdFunction(FD, Fn, VLENVal, ParamAttrs, State);
- }
- FD = FD->getPreviousDecl();
- }
-}
-
-namespace {
-/// Cleanup action for doacross support.
-class DoacrossCleanupTy final : public EHScopeStack::Cleanup {
-public:
- static const int DoacrossFinArgs = 2;
-
-private:
- llvm::Value *RTLFn;
- llvm::Value *Args[DoacrossFinArgs];
-
-public:
- DoacrossCleanupTy(llvm::Value *RTLFn, ArrayRef<llvm::Value *> CallArgs)
- : RTLFn(RTLFn) {
- assert(CallArgs.size() == DoacrossFinArgs);
- std::copy(CallArgs.begin(), CallArgs.end(), std::begin(Args));
- }
- void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
- if (!CGF.HaveInsertPoint())
- return;
- CGF.EmitRuntimeCall(RTLFn, Args);
- }
-};
-} // namespace
-
-void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF,
- const OMPLoopDirective &D,
- ArrayRef<Expr *> NumIterations) {
- if (!CGF.HaveInsertPoint())
- return;
-
- ASTContext &C = CGM.getContext();
- QualType Int64Ty = C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/true);
- RecordDecl *RD;
- if (KmpDimTy.isNull()) {
- // Build struct kmp_dim { // loop bounds info casted to kmp_int64
- // kmp_int64 lo; // lower
- // kmp_int64 up; // upper
- // kmp_int64 st; // stride
- // };
- RD = C.buildImplicitRecord("kmp_dim");
- RD->startDefinition();
- addFieldToRecordDecl(C, RD, Int64Ty);
- addFieldToRecordDecl(C, RD, Int64Ty);
- addFieldToRecordDecl(C, RD, Int64Ty);
- RD->completeDefinition();
- KmpDimTy = C.getRecordType(RD);
- } else {
- RD = cast<RecordDecl>(KmpDimTy->getAsTagDecl());
- }
- llvm::APInt Size(/*numBits=*/32, NumIterations.size());
- QualType ArrayTy =
- C.getConstantArrayType(KmpDimTy, Size, ArrayType::Normal, 0);
-
- Address DimsAddr = CGF.CreateMemTemp(ArrayTy, "dims");
- CGF.EmitNullInitialization(DimsAddr, ArrayTy);
- enum { LowerFD = 0, UpperFD, StrideFD };
- // Fill dims with data.
- for (unsigned I = 0, E = NumIterations.size(); I < E; ++I) {
- LValue DimsLVal =
- CGF.MakeAddrLValue(CGF.Builder.CreateConstArrayGEP(
- DimsAddr, I, C.getTypeSizeInChars(KmpDimTy)),
- KmpDimTy);
- // dims.upper = num_iterations;
- LValue UpperLVal = CGF.EmitLValueForField(
- DimsLVal, *std::next(RD->field_begin(), UpperFD));
- llvm::Value *NumIterVal =
- CGF.EmitScalarConversion(CGF.EmitScalarExpr(NumIterations[I]),
- D.getNumIterations()->getType(), Int64Ty,
- D.getNumIterations()->getExprLoc());
- CGF.EmitStoreOfScalar(NumIterVal, UpperLVal);
- // dims.stride = 1;
- LValue StrideLVal = CGF.EmitLValueForField(
- DimsLVal, *std::next(RD->field_begin(), StrideFD));
- CGF.EmitStoreOfScalar(llvm::ConstantInt::getSigned(CGM.Int64Ty, /*V=*/1),
- StrideLVal);
- }
-
- // Build call void __kmpc_doacross_init(ident_t *loc, kmp_int32 gtid,
- // kmp_int32 num_dims, struct kmp_dim * dims);
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, D.getBeginLoc()),
- getThreadID(CGF, D.getBeginLoc()),
- llvm::ConstantInt::getSigned(CGM.Int32Ty, NumIterations.size()),
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder
- .CreateConstArrayGEP(DimsAddr, 0, C.getTypeSizeInChars(KmpDimTy))
- .getPointer(),
- CGM.VoidPtrTy)};
-
- llvm::Value *RTLFn = createRuntimeFunction(OMPRTL__kmpc_doacross_init);
- CGF.EmitRuntimeCall(RTLFn, Args);
- llvm::Value *FiniArgs[DoacrossCleanupTy::DoacrossFinArgs] = {
- emitUpdateLocation(CGF, D.getEndLoc()), getThreadID(CGF, D.getEndLoc())};
- llvm::Value *FiniRTLFn = createRuntimeFunction(OMPRTL__kmpc_doacross_fini);
- CGF.EHStack.pushCleanup<DoacrossCleanupTy>(NormalAndEHCleanup, FiniRTLFn,
- llvm::makeArrayRef(FiniArgs));
-}
-
-void CGOpenMPRuntime::emitDoacrossOrdered(CodeGenFunction &CGF,
- const OMPDependClause *C) {
- QualType Int64Ty =
- CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
- llvm::APInt Size(/*numBits=*/32, C->getNumLoops());
- QualType ArrayTy = CGM.getContext().getConstantArrayType(
- Int64Ty, Size, ArrayType::Normal, 0);
- Address CntAddr = CGF.CreateMemTemp(ArrayTy, ".cnt.addr");
- for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) {
- const Expr *CounterVal = C->getLoopData(I);
- assert(CounterVal);
- llvm::Value *CntVal = CGF.EmitScalarConversion(
- CGF.EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty,
- CounterVal->getExprLoc());
- CGF.EmitStoreOfScalar(
- CntVal,
- CGF.Builder.CreateConstArrayGEP(
- CntAddr, I, CGM.getContext().getTypeSizeInChars(Int64Ty)),
- /*Volatile=*/false, Int64Ty);
- }
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, C->getBeginLoc()),
- getThreadID(CGF, C->getBeginLoc()),
- CGF.Builder
- .CreateConstArrayGEP(CntAddr, 0,
- CGM.getContext().getTypeSizeInChars(Int64Ty))
- .getPointer()};
- llvm::Value *RTLFn;
- if (C->getDependencyKind() == OMPC_DEPEND_source) {
- RTLFn = createRuntimeFunction(OMPRTL__kmpc_doacross_post);
- } else {
- assert(C->getDependencyKind() == OMPC_DEPEND_sink);
- RTLFn = createRuntimeFunction(OMPRTL__kmpc_doacross_wait);
- }
- CGF.EmitRuntimeCall(RTLFn, Args);
-}
-
-void CGOpenMPRuntime::emitCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *Callee,
- ArrayRef<llvm::Value *> Args) const {
- assert(Loc.isValid() && "Outlined function call location must be valid.");
- auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc);
-
- if (auto *Fn = dyn_cast<llvm::Function>(Callee)) {
- if (Fn->doesNotThrow()) {
- CGF.EmitNounwindRuntimeCall(Fn, Args);
- return;
- }
- }
- CGF.EmitRuntimeCall(Callee, Args);
-}
-
-void CGOpenMPRuntime::emitOutlinedFunctionCall(
- CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> Args) const {
- emitCall(CGF, Loc, OutlinedFn, Args);
-}
-
-Address CGOpenMPRuntime::getParameterAddress(CodeGenFunction &CGF,
- const VarDecl *NativeParam,
- const VarDecl *TargetParam) const {
- return CGF.GetAddrOfLocalVar(NativeParam);
-}
-
-Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
- const VarDecl *VD) {
- return Address::invalid();
-}
-
-llvm::Value *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-llvm::Value *CGOpenMPSIMDRuntime::emitTeamsOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-llvm::Value *CGOpenMPSIMDRuntime::emitTaskOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- const VarDecl *PartIDVar, const VarDecl *TaskTVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
- bool Tied, unsigned &NumberOfParts) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitParallelCall(CodeGenFunction &CGF,
- SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars,
- const Expr *IfCond) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitCriticalRegion(
- CodeGenFunction &CGF, StringRef CriticalName,
- const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc,
- const Expr *Hint) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitMasterRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &MasterOpGen,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTaskyieldCall(CodeGenFunction &CGF,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTaskgroupRegion(
- CodeGenFunction &CGF, const RegionCodeGenTy &TaskgroupOpGen,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitSingleRegion(
- CodeGenFunction &CGF, const RegionCodeGenTy &SingleOpGen,
- SourceLocation Loc, ArrayRef<const Expr *> CopyprivateVars,
- ArrayRef<const Expr *> DestExprs, ArrayRef<const Expr *> SrcExprs,
- ArrayRef<const Expr *> AssignmentOps) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitOrderedRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &OrderedOpGen,
- SourceLocation Loc,
- bool IsThreads) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitBarrierCall(CodeGenFunction &CGF,
- SourceLocation Loc,
- OpenMPDirectiveKind Kind,
- bool EmitChecks,
- bool ForceSimpleCall) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitForDispatchInit(
- CodeGenFunction &CGF, SourceLocation Loc,
- const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
- bool Ordered, const DispatchRTInput &DispatchValues) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitForStaticInit(
- CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind DKind,
- const OpenMPScheduleTy &ScheduleKind, const StaticRTInput &Values) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitDistributeStaticInit(
- CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDistScheduleClauseKind SchedKind, const StaticRTInput &Values) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitForOrderedIterationEnd(CodeGenFunction &CGF,
- SourceLocation Loc,
- unsigned IVSize,
- bool IVSigned) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitForStaticFinish(CodeGenFunction &CGF,
- SourceLocation Loc,
- OpenMPDirectiveKind DKind) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-llvm::Value *CGOpenMPSIMDRuntime::emitForNext(CodeGenFunction &CGF,
- SourceLocation Loc,
- unsigned IVSize, bool IVSigned,
- Address IL, Address LB,
- Address UB, Address ST) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitNumThreadsClause(CodeGenFunction &CGF,
- llvm::Value *NumThreads,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-Address CGOpenMPSIMDRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF,
- const VarDecl *VD,
- Address VDAddr,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-llvm::Function *CGOpenMPSIMDRuntime::emitThreadPrivateVarDefinition(
- const VarDecl *VD, Address VDAddr, SourceLocation Loc, bool PerformInit,
- CodeGenFunction *CGF) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-Address CGOpenMPSIMDRuntime::getAddrOfArtificialThreadPrivate(
- CodeGenFunction &CGF, QualType VarType, StringRef Name) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitFlush(CodeGenFunction &CGF,
- ArrayRef<const Expr *> Vars,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPExecutableDirective &D,
- llvm::Value *TaskFunction,
- QualType SharedsTy, Address Shareds,
- const Expr *IfCond,
- const OMPTaskDataTy &Data) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTaskLoopCall(
- CodeGenFunction &CGF, SourceLocation Loc, const OMPLoopDirective &D,
- llvm::Value *TaskFunction, QualType SharedsTy, Address Shareds,
- const Expr *IfCond, const OMPTaskDataTy &Data) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitReduction(
- CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs, ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps, ReductionOptionsTy Options) {
- assert(Options.SimpleReduction && "Only simple reduction is expected.");
- CGOpenMPRuntime::emitReduction(CGF, Loc, Privates, LHSExprs, RHSExprs,
- ReductionOps, Options);
-}
-
-llvm::Value *CGOpenMPSIMDRuntime::emitTaskReductionInit(
- CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTaskReductionFixups(CodeGenFunction &CGF,
- SourceLocation Loc,
- ReductionCodeGen &RCG,
- unsigned N) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-Address CGOpenMPSIMDRuntime::getTaskReductionItem(CodeGenFunction &CGF,
- SourceLocation Loc,
- llvm::Value *ReductionsPtr,
- LValue SharedLVal) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTaskwaitCall(CodeGenFunction &CGF,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitCancellationPointCall(
- CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind CancelRegion) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitCancelCall(CodeGenFunction &CGF,
- SourceLocation Loc, const Expr *IfCond,
- OpenMPDirectiveKind CancelRegion) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTargetOutlinedFunction(
- const OMPExecutableDirective &D, StringRef ParentName,
- llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTargetCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- llvm::Value *OutlinedFn,
- llvm::Value *OutlinedFnID,
- const Expr *IfCond, const Expr *Device) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-bool CGOpenMPSIMDRuntime::emitTargetFunctions(GlobalDecl GD) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-bool CGOpenMPSIMDRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-bool CGOpenMPSIMDRuntime::emitTargetGlobal(GlobalDecl GD) {
- return false;
-}
-
-llvm::Function *CGOpenMPSIMDRuntime::emitRegistrationFunction() {
- return nullptr;
-}
-
-void CGOpenMPSIMDRuntime::emitTeamsCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitNumTeamsClause(CodeGenFunction &CGF,
- const Expr *NumTeams,
- const Expr *ThreadLimit,
- SourceLocation Loc) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTargetDataCalls(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
- const Expr *Device, const RegionCodeGenTy &CodeGen, TargetDataInfo &Info) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitTargetDataStandAloneCall(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
- const Expr *Device) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitDoacrossInit(CodeGenFunction &CGF,
- const OMPLoopDirective &D,
- ArrayRef<Expr *> NumIterations) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-void CGOpenMPSIMDRuntime::emitDoacrossOrdered(CodeGenFunction &CGF,
- const OMPDependClause *C) {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-const VarDecl *
-CGOpenMPSIMDRuntime::translateParameter(const FieldDecl *FD,
- const VarDecl *NativeParam) const {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
-Address
-CGOpenMPSIMDRuntime::getParameterAddress(CodeGenFunction &CGF,
- const VarDecl *NativeParam,
- const VarDecl *TargetParam) const {
- llvm_unreachable("Not supported in SIMD-only mode");
-}
-
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h b/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h
deleted file mode 100644
index 1822a6fd197..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ /dev/null
@@ -1,2155 +0,0 @@
-//===----- CGOpenMPRuntime.h - Interface to OpenMP Runtimes -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides a class for OpenMP runtime code generation.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
-#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
-
-#include "CGValue.h"
-#include "clang/AST/DeclOpenMP.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/OpenMPKinds.h"
-#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/ValueHandle.h"
-
-namespace llvm {
-class ArrayType;
-class Constant;
-class FunctionType;
-class GlobalVariable;
-class StructType;
-class Type;
-class Value;
-} // namespace llvm
-
-namespace clang {
-class Expr;
-class GlobalDecl;
-class OMPDependClause;
-class OMPExecutableDirective;
-class OMPLoopDirective;
-class VarDecl;
-class OMPDeclareReductionDecl;
-class IdentifierInfo;
-
-namespace CodeGen {
-class Address;
-class CodeGenFunction;
-class CodeGenModule;
-
-/// A basic class for pre|post-action for advanced codegen sequence for OpenMP
-/// region.
-class PrePostActionTy {
-public:
- explicit PrePostActionTy() {}
- virtual void Enter(CodeGenFunction &CGF) {}
- virtual void Exit(CodeGenFunction &CGF) {}
- virtual ~PrePostActionTy() {}
-};
-
-/// Class provides a way to call simple version of codegen for OpenMP region, or
-/// an advanced with possible pre|post-actions in codegen.
-class RegionCodeGenTy final {
- intptr_t CodeGen;
- typedef void (*CodeGenTy)(intptr_t, CodeGenFunction &, PrePostActionTy &);
- CodeGenTy Callback;
- mutable PrePostActionTy *PrePostAction;
- RegionCodeGenTy() = delete;
- RegionCodeGenTy &operator=(const RegionCodeGenTy &) = delete;
- template <typename Callable>
- static void CallbackFn(intptr_t CodeGen, CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- return (*reinterpret_cast<Callable *>(CodeGen))(CGF, Action);
- }
-
-public:
- template <typename Callable>
- RegionCodeGenTy(
- Callable &&CodeGen,
- typename std::enable_if<
- !std::is_same<typename std::remove_reference<Callable>::type,
- RegionCodeGenTy>::value>::type * = nullptr)
- : CodeGen(reinterpret_cast<intptr_t>(&CodeGen)),
- Callback(CallbackFn<typename std::remove_reference<Callable>::type>),
- PrePostAction(nullptr) {}
- void setAction(PrePostActionTy &Action) const { PrePostAction = &Action; }
- void operator()(CodeGenFunction &CGF) const;
-};
-
-struct OMPTaskDataTy final {
- SmallVector<const Expr *, 4> PrivateVars;
- SmallVector<const Expr *, 4> PrivateCopies;
- SmallVector<const Expr *, 4> FirstprivateVars;
- SmallVector<const Expr *, 4> FirstprivateCopies;
- SmallVector<const Expr *, 4> FirstprivateInits;
- SmallVector<const Expr *, 4> LastprivateVars;
- SmallVector<const Expr *, 4> LastprivateCopies;
- SmallVector<const Expr *, 4> ReductionVars;
- SmallVector<const Expr *, 4> ReductionCopies;
- SmallVector<const Expr *, 4> ReductionOps;
- SmallVector<std::pair<OpenMPDependClauseKind, const Expr *>, 4> Dependences;
- llvm::PointerIntPair<llvm::Value *, 1, bool> Final;
- llvm::PointerIntPair<llvm::Value *, 1, bool> Schedule;
- llvm::PointerIntPair<llvm::Value *, 1, bool> Priority;
- llvm::Value *Reductions = nullptr;
- unsigned NumberOfParts = 0;
- bool Tied = true;
- bool Nogroup = false;
-};
-
-/// Class intended to support codegen of all kind of the reduction clauses.
-class ReductionCodeGen {
-private:
- /// Data required for codegen of reduction clauses.
- struct ReductionData {
- /// Reference to the original shared item.
- const Expr *Ref = nullptr;
- /// Helper expression for generation of private copy.
- const Expr *Private = nullptr;
- /// Helper expression for generation reduction operation.
- const Expr *ReductionOp = nullptr;
- ReductionData(const Expr *Ref, const Expr *Private, const Expr *ReductionOp)
- : Ref(Ref), Private(Private), ReductionOp(ReductionOp) {}
- };
- /// List of reduction-based clauses.
- SmallVector<ReductionData, 4> ClausesData;
-
- /// List of addresses of original shared variables/expressions.
- SmallVector<std::pair<LValue, LValue>, 4> SharedAddresses;
- /// Sizes of the reduction items in chars.
- SmallVector<std::pair<llvm::Value *, llvm::Value *>, 4> Sizes;
- /// Base declarations for the reduction items.
- SmallVector<const VarDecl *, 4> BaseDecls;
-
- /// Emits lvalue for shared expression.
- LValue emitSharedLValue(CodeGenFunction &CGF, const Expr *E);
- /// Emits upper bound for shared expression (if array section).
- LValue emitSharedLValueUB(CodeGenFunction &CGF, const Expr *E);
- /// Performs aggregate initialization.
- /// \param N Number of reduction item in the common list.
- /// \param PrivateAddr Address of the corresponding private item.
- /// \param SharedLVal Address of the original shared variable.
- /// \param DRD Declare reduction construct used for reduction item.
- void emitAggregateInitialization(CodeGenFunction &CGF, unsigned N,
- Address PrivateAddr, LValue SharedLVal,
- const OMPDeclareReductionDecl *DRD);
-
-public:
- ReductionCodeGen(ArrayRef<const Expr *> Shareds,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> ReductionOps);
- /// Emits lvalue for a reduction item.
- /// \param N Number of the reduction item.
- void emitSharedLValue(CodeGenFunction &CGF, unsigned N);
- /// Emits the code for the variable-modified type, if required.
- /// \param N Number of the reduction item.
- void emitAggregateType(CodeGenFunction &CGF, unsigned N);
- /// Emits the code for the variable-modified type, if required.
- /// \param N Number of the reduction item.
- /// \param Size Size of the type in chars.
- void emitAggregateType(CodeGenFunction &CGF, unsigned N, llvm::Value *Size);
- /// Performs initialization of the private copy for the reduction item.
- /// \param N Number of the reduction item.
- /// \param PrivateAddr Address of the corresponding private item.
- /// \param DefaultInit Default initialization sequence that should be
- /// performed if no reduction specific initialization is found.
- /// \param SharedLVal Address of the original shared variable.
- void
- emitInitialization(CodeGenFunction &CGF, unsigned N, Address PrivateAddr,
- LValue SharedLVal,
- llvm::function_ref<bool(CodeGenFunction &)> DefaultInit);
- /// Returns true if the private copy requires cleanups.
- bool needCleanups(unsigned N);
- /// Emits cleanup code for the reduction item.
- /// \param N Number of the reduction item.
- /// \param PrivateAddr Address of the corresponding private item.
- void emitCleanups(CodeGenFunction &CGF, unsigned N, Address PrivateAddr);
- /// Adjusts \p PrivatedAddr for using instead of the original variable
- /// address in normal operations.
- /// \param N Number of the reduction item.
- /// \param PrivateAddr Address of the corresponding private item.
- Address adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
- Address PrivateAddr);
- /// Returns LValue for the reduction item.
- LValue getSharedLValue(unsigned N) const { return SharedAddresses[N].first; }
- /// Returns the size of the reduction item (in chars and total number of
- /// elements in the item), or nullptr, if the size is a constant.
- std::pair<llvm::Value *, llvm::Value *> getSizes(unsigned N) const {
- return Sizes[N];
- }
- /// Returns the base declaration of the reduction item.
- const VarDecl *getBaseDecl(unsigned N) const { return BaseDecls[N]; }
- /// Returns the base declaration of the reduction item.
- const Expr *getRefExpr(unsigned N) const { return ClausesData[N].Ref; }
- /// Returns true if the initialization of the reduction item uses initializer
- /// from declare reduction construct.
- bool usesReductionInitializer(unsigned N) const;
-};
-
-class CGOpenMPRuntime {
-public:
- /// Allows to disable automatic handling of functions used in target regions
- /// as those marked as `omp declare target`.
- class DisableAutoDeclareTargetRAII {
- CodeGenModule &CGM;
- bool SavedShouldMarkAsGlobal;
-
- public:
- DisableAutoDeclareTargetRAII(CodeGenModule &CGM);
- ~DisableAutoDeclareTargetRAII();
- };
-
-protected:
- CodeGenModule &CGM;
- StringRef FirstSeparator, Separator;
-
- /// Constructor allowing to redefine the name separator for the variables.
- explicit CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
- StringRef Separator);
-
- /// Creates offloading entry for the provided entry ID \a ID,
- /// address \a Addr, size \a Size, and flags \a Flags.
- virtual void createOffloadEntry(llvm::Constant *ID, llvm::Constant *Addr,
- uint64_t Size, int32_t Flags,
- llvm::GlobalValue::LinkageTypes Linkage);
-
- /// Helper to emit outlined function for 'target' directive.
- /// \param D Directive to emit.
- /// \param ParentName Name of the function that encloses the target region.
- /// \param OutlinedFn Outlined function value to be defined by this call.
- /// \param OutlinedFnID Outlined function ID value to be defined by this call.
- /// \param IsOffloadEntry True if the outlined function is an offload entry.
- /// \param CodeGen Lambda codegen specific to an accelerator device.
- /// An outlined function may not be an entry if, e.g. the if clause always
- /// evaluates to false.
- virtual void emitTargetOutlinedFunctionHelper(const OMPExecutableDirective &D,
- StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen);
-
- /// Emits code for OpenMP 'if' clause using specified \a CodeGen
- /// function. Here is the logic:
- /// if (Cond) {
- /// ThenGen();
- /// } else {
- /// ElseGen();
- /// }
- void emitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond,
- const RegionCodeGenTy &ThenGen,
- const RegionCodeGenTy &ElseGen);
-
- /// Emits object of ident_t type with info for source location.
- /// \param Flags Flags for OpenMP location.
- ///
- llvm::Value *emitUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
- unsigned Flags = 0);
-
- /// Returns pointer to ident_t type.
- llvm::Type *getIdentTyPointerTy();
-
- /// Gets thread id value for the current thread.
- ///
- llvm::Value *getThreadID(CodeGenFunction &CGF, SourceLocation Loc);
-
- /// Get the function name of an outlined region.
- // The name can be customized depending on the target.
- //
- virtual StringRef getOutlinedHelperName() const { return ".omp_outlined."; }
-
- /// Emits \p Callee function call with arguments \p Args with location \p Loc.
- void emitCall(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *Callee,
- ArrayRef<llvm::Value *> Args = llvm::None) const;
-
- /// Emits address of the word in a memory where current thread id is
- /// stored.
- virtual Address emitThreadIDAddress(CodeGenFunction &CGF, SourceLocation Loc);
-
- void setLocThreadIdInsertPt(CodeGenFunction &CGF,
- bool AtCurrentPoint = false);
- void clearLocThreadIdInsertPt(CodeGenFunction &CGF);
-
- /// Check if the default location must be constant.
- /// Default is false to support OMPT/OMPD.
- virtual bool isDefaultLocationConstant() const { return false; }
-
- /// Returns additional flags that can be stored in reserved_2 field of the
- /// default location.
- virtual unsigned getDefaultLocationReserved2Flags() const { return 0; }
-
- /// Returns default flags for the barriers depending on the directive, for
- /// which this barier is going to be emitted.
- static unsigned getDefaultFlagsForBarriers(OpenMPDirectiveKind Kind);
-
- /// Get the LLVM type for the critical name.
- llvm::ArrayType *getKmpCriticalNameTy() const {return KmpCriticalNameTy;}
-
- /// Returns corresponding lock object for the specified critical region
- /// name. If the lock object does not exist it is created, otherwise the
- /// reference to the existing copy is returned.
- /// \param CriticalName Name of the critical region.
- ///
- llvm::Value *getCriticalRegionLock(StringRef CriticalName);
-
-private:
- /// Default const ident_t object used for initialization of all other
- /// ident_t objects.
- llvm::Constant *DefaultOpenMPPSource = nullptr;
- using FlagsTy = std::pair<unsigned, unsigned>;
- /// Map of flags and corresponding default locations.
- using OpenMPDefaultLocMapTy = llvm::DenseMap<FlagsTy, llvm::Value *>;
- OpenMPDefaultLocMapTy OpenMPDefaultLocMap;
- Address getOrCreateDefaultLocation(unsigned Flags);
-
- QualType IdentQTy;
- llvm::StructType *IdentTy = nullptr;
- /// Map for SourceLocation and OpenMP runtime library debug locations.
- typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDebugLocMapTy;
- OpenMPDebugLocMapTy OpenMPDebugLocMap;
- /// The type for a microtask which gets passed to __kmpc_fork_call().
- /// Original representation is:
- /// typedef void (kmpc_micro)(kmp_int32 global_tid, kmp_int32 bound_tid,...);
- llvm::FunctionType *Kmpc_MicroTy = nullptr;
- /// Stores debug location and ThreadID for the function.
- struct DebugLocThreadIdTy {
- llvm::Value *DebugLoc;
- llvm::Value *ThreadID;
- /// Insert point for the service instructions.
- llvm::AssertingVH<llvm::Instruction> ServiceInsertPt = nullptr;
- };
- /// Map of local debug location, ThreadId and functions.
- typedef llvm::DenseMap<llvm::Function *, DebugLocThreadIdTy>
- OpenMPLocThreadIDMapTy;
- OpenMPLocThreadIDMapTy OpenMPLocThreadIDMap;
- /// Map of UDRs and corresponding combiner/initializer.
- typedef llvm::DenseMap<const OMPDeclareReductionDecl *,
- std::pair<llvm::Function *, llvm::Function *>>
- UDRMapTy;
- UDRMapTy UDRMap;
- /// Map of functions and locally defined UDRs.
- typedef llvm::DenseMap<llvm::Function *,
- SmallVector<const OMPDeclareReductionDecl *, 4>>
- FunctionUDRMapTy;
- FunctionUDRMapTy FunctionUDRMap;
- /// Type kmp_critical_name, originally defined as typedef kmp_int32
- /// kmp_critical_name[8];
- llvm::ArrayType *KmpCriticalNameTy;
- /// An ordered map of auto-generated variables to their unique names.
- /// It stores variables with the following names: 1) ".gomp_critical_user_" +
- /// <critical_section_name> + ".var" for "omp critical" directives; 2)
- /// <mangled_name_for_global_var> + ".cache." for cache for threadprivate
- /// variables.
- llvm::StringMap<llvm::AssertingVH<llvm::Constant>, llvm::BumpPtrAllocator>
- InternalVars;
- /// Type typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *);
- llvm::Type *KmpRoutineEntryPtrTy = nullptr;
- QualType KmpRoutineEntryPtrQTy;
- /// Type typedef struct kmp_task {
- /// void * shareds; /**< pointer to block of pointers to
- /// shared vars */
- /// kmp_routine_entry_t routine; /**< pointer to routine to call for
- /// executing task */
- /// kmp_int32 part_id; /**< part id for the task */
- /// kmp_routine_entry_t destructors; /* pointer to function to invoke
- /// deconstructors of firstprivate C++ objects */
- /// } kmp_task_t;
- QualType KmpTaskTQTy;
- /// Saved kmp_task_t for task directive.
- QualType SavedKmpTaskTQTy;
- /// Saved kmp_task_t for taskloop-based directive.
- QualType SavedKmpTaskloopTQTy;
- /// Type typedef struct kmp_depend_info {
- /// kmp_intptr_t base_addr;
- /// size_t len;
- /// struct {
- /// bool in:1;
- /// bool out:1;
- /// } flags;
- /// } kmp_depend_info_t;
- QualType KmpDependInfoTy;
- /// struct kmp_dim { // loop bounds info casted to kmp_int64
- /// kmp_int64 lo; // lower
- /// kmp_int64 up; // upper
- /// kmp_int64 st; // stride
- /// };
- QualType KmpDimTy;
- /// Type struct __tgt_offload_entry{
- /// void *addr; // Pointer to the offload entry info.
- /// // (function or global)
- /// char *name; // Name of the function or global.
- /// size_t size; // Size of the entry info (0 if it a function).
- /// };
- QualType TgtOffloadEntryQTy;
- /// struct __tgt_device_image{
- /// void *ImageStart; // Pointer to the target code start.
- /// void *ImageEnd; // Pointer to the target code end.
- /// // We also add the host entries to the device image, as it may be useful
- /// // for the target runtime to have access to that information.
- /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all
- /// // the entries.
- /// __tgt_offload_entry *EntriesEnd; // End of the table with all the
- /// // entries (non inclusive).
- /// };
- QualType TgtDeviceImageQTy;
- /// struct __tgt_bin_desc{
- /// int32_t NumDevices; // Number of devices supported.
- /// __tgt_device_image *DeviceImages; // Arrays of device images
- /// // (one per device).
- /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all the
- /// // entries.
- /// __tgt_offload_entry *EntriesEnd; // End of the table with all the
- /// // entries (non inclusive).
- /// };
- QualType TgtBinaryDescriptorQTy;
- /// Entity that registers the offloading constants that were emitted so
- /// far.
- class OffloadEntriesInfoManagerTy {
- CodeGenModule &CGM;
-
- /// Number of entries registered so far.
- unsigned OffloadingEntriesNum = 0;
-
- public:
- /// Base class of the entries info.
- class OffloadEntryInfo {
- public:
- /// Kind of a given entry.
- enum OffloadingEntryInfoKinds : unsigned {
- /// Entry is a target region.
- OffloadingEntryInfoTargetRegion = 0,
- /// Entry is a declare target variable.
- OffloadingEntryInfoDeviceGlobalVar = 1,
- /// Invalid entry info.
- OffloadingEntryInfoInvalid = ~0u
- };
-
- protected:
- OffloadEntryInfo() = delete;
- explicit OffloadEntryInfo(OffloadingEntryInfoKinds Kind) : Kind(Kind) {}
- explicit OffloadEntryInfo(OffloadingEntryInfoKinds Kind, unsigned Order,
- uint32_t Flags)
- : Flags(Flags), Order(Order), Kind(Kind) {}
- ~OffloadEntryInfo() = default;
-
- public:
- bool isValid() const { return Order != ~0u; }
- unsigned getOrder() const { return Order; }
- OffloadingEntryInfoKinds getKind() const { return Kind; }
- uint32_t getFlags() const { return Flags; }
- void setFlags(uint32_t NewFlags) { Flags = NewFlags; }
- llvm::Constant *getAddress() const {
- return cast_or_null<llvm::Constant>(Addr);
- }
- void setAddress(llvm::Constant *V) {
- assert(!Addr.pointsToAliveValue() && "Address has been set before!");
- Addr = V;
- }
- static bool classof(const OffloadEntryInfo *Info) { return true; }
-
- private:
- /// Address of the entity that has to be mapped for offloading.
- llvm::WeakTrackingVH Addr;
-
- /// Flags associated with the device global.
- uint32_t Flags = 0u;
-
- /// Order this entry was emitted.
- unsigned Order = ~0u;
-
- OffloadingEntryInfoKinds Kind = OffloadingEntryInfoInvalid;
- };
-
- /// Return true if a there are no entries defined.
- bool empty() const;
- /// Return number of entries defined so far.
- unsigned size() const { return OffloadingEntriesNum; }
- OffloadEntriesInfoManagerTy(CodeGenModule &CGM) : CGM(CGM) {}
-
- //
- // Target region entries related.
- //
-
- /// Kind of the target registry entry.
- enum OMPTargetRegionEntryKind : uint32_t {
- /// Mark the entry as target region.
- OMPTargetRegionEntryTargetRegion = 0x0,
- /// Mark the entry as a global constructor.
- OMPTargetRegionEntryCtor = 0x02,
- /// Mark the entry as a global destructor.
- OMPTargetRegionEntryDtor = 0x04,
- };
-
- /// Target region entries info.
- class OffloadEntryInfoTargetRegion final : public OffloadEntryInfo {
- /// Address that can be used as the ID of the entry.
- llvm::Constant *ID = nullptr;
-
- public:
- OffloadEntryInfoTargetRegion()
- : OffloadEntryInfo(OffloadingEntryInfoTargetRegion) {}
- explicit OffloadEntryInfoTargetRegion(unsigned Order,
- llvm::Constant *Addr,
- llvm::Constant *ID,
- OMPTargetRegionEntryKind Flags)
- : OffloadEntryInfo(OffloadingEntryInfoTargetRegion, Order, Flags),
- ID(ID) {
- setAddress(Addr);
- }
-
- llvm::Constant *getID() const { return ID; }
- void setID(llvm::Constant *V) {
- assert(!ID && "ID has been set before!");
- ID = V;
- }
- static bool classof(const OffloadEntryInfo *Info) {
- return Info->getKind() == OffloadingEntryInfoTargetRegion;
- }
- };
-
- /// Initialize target region entry.
- void initializeTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- unsigned Order);
- /// Register target region entry.
- void registerTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- llvm::Constant *Addr, llvm::Constant *ID,
- OMPTargetRegionEntryKind Flags);
- /// Return true if a target region entry with the provided information
- /// exists.
- bool hasTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum) const;
- /// brief Applies action \a Action on all registered entries.
- typedef llvm::function_ref<void(unsigned, unsigned, StringRef, unsigned,
- const OffloadEntryInfoTargetRegion &)>
- OffloadTargetRegionEntryInfoActTy;
- void actOnTargetRegionEntriesInfo(
- const OffloadTargetRegionEntryInfoActTy &Action);
-
- //
- // Device global variable entries related.
- //
-
- /// Kind of the global variable entry..
- enum OMPTargetGlobalVarEntryKind : uint32_t {
- /// Mark the entry as a to declare target.
- OMPTargetGlobalVarEntryTo = 0x0,
- /// Mark the entry as a to declare target link.
- OMPTargetGlobalVarEntryLink = 0x1,
- };
-
- /// Device global variable entries info.
- class OffloadEntryInfoDeviceGlobalVar final : public OffloadEntryInfo {
- /// Type of the global variable.
- CharUnits VarSize;
- llvm::GlobalValue::LinkageTypes Linkage;
-
- public:
- OffloadEntryInfoDeviceGlobalVar()
- : OffloadEntryInfo(OffloadingEntryInfoDeviceGlobalVar) {}
- explicit OffloadEntryInfoDeviceGlobalVar(unsigned Order,
- OMPTargetGlobalVarEntryKind Flags)
- : OffloadEntryInfo(OffloadingEntryInfoDeviceGlobalVar, Order, Flags) {}
- explicit OffloadEntryInfoDeviceGlobalVar(
- unsigned Order, llvm::Constant *Addr, CharUnits VarSize,
- OMPTargetGlobalVarEntryKind Flags,
- llvm::GlobalValue::LinkageTypes Linkage)
- : OffloadEntryInfo(OffloadingEntryInfoDeviceGlobalVar, Order, Flags),
- VarSize(VarSize), Linkage(Linkage) {
- setAddress(Addr);
- }
-
- CharUnits getVarSize() const { return VarSize; }
- void setVarSize(CharUnits Size) { VarSize = Size; }
- llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; }
- void setLinkage(llvm::GlobalValue::LinkageTypes LT) { Linkage = LT; }
- static bool classof(const OffloadEntryInfo *Info) {
- return Info->getKind() == OffloadingEntryInfoDeviceGlobalVar;
- }
- };
-
- /// Initialize device global variable entry.
- void initializeDeviceGlobalVarEntryInfo(StringRef Name,
- OMPTargetGlobalVarEntryKind Flags,
- unsigned Order);
-
- /// Register device global variable entry.
- void
- registerDeviceGlobalVarEntryInfo(StringRef VarName, llvm::Constant *Addr,
- CharUnits VarSize,
- OMPTargetGlobalVarEntryKind Flags,
- llvm::GlobalValue::LinkageTypes Linkage);
- /// Checks if the variable with the given name has been registered already.
- bool hasDeviceGlobalVarEntryInfo(StringRef VarName) const {
- return OffloadEntriesDeviceGlobalVar.count(VarName) > 0;
- }
- /// Applies action \a Action on all registered entries.
- typedef llvm::function_ref<void(StringRef,
- const OffloadEntryInfoDeviceGlobalVar &)>
- OffloadDeviceGlobalVarEntryInfoActTy;
- void actOnDeviceGlobalVarEntriesInfo(
- const OffloadDeviceGlobalVarEntryInfoActTy &Action);
-
- private:
- // Storage for target region entries kind. The storage is to be indexed by
- // file ID, device ID, parent function name and line number.
- typedef llvm::DenseMap<unsigned, OffloadEntryInfoTargetRegion>
- OffloadEntriesTargetRegionPerLine;
- typedef llvm::StringMap<OffloadEntriesTargetRegionPerLine>
- OffloadEntriesTargetRegionPerParentName;
- typedef llvm::DenseMap<unsigned, OffloadEntriesTargetRegionPerParentName>
- OffloadEntriesTargetRegionPerFile;
- typedef llvm::DenseMap<unsigned, OffloadEntriesTargetRegionPerFile>
- OffloadEntriesTargetRegionPerDevice;
- typedef OffloadEntriesTargetRegionPerDevice OffloadEntriesTargetRegionTy;
- OffloadEntriesTargetRegionTy OffloadEntriesTargetRegion;
- /// Storage for device global variable entries kind. The storage is to be
- /// indexed by mangled name.
- typedef llvm::StringMap<OffloadEntryInfoDeviceGlobalVar>
- OffloadEntriesDeviceGlobalVarTy;
- OffloadEntriesDeviceGlobalVarTy OffloadEntriesDeviceGlobalVar;
- };
- OffloadEntriesInfoManagerTy OffloadEntriesInfoManager;
-
- bool ShouldMarkAsGlobal = true;
- /// List of the emitted functions.
- llvm::StringSet<> AlreadyEmittedTargetFunctions;
- /// List of the global variables with their addresses that should not be
- /// emitted for the target.
- llvm::StringMap<llvm::WeakTrackingVH> EmittedNonTargetVariables;
-
- /// List of variables that can become declare target implicitly and, thus,
- /// must be emitted.
- llvm::SmallDenseSet<const VarDecl *> DeferredGlobalVariables;
-
- /// Creates and registers offloading binary descriptor for the current
- /// compilation unit. The function that does the registration is returned.
- llvm::Function *createOffloadingBinaryDescriptorRegistration();
-
- /// Creates all the offload entries in the current compilation unit
- /// along with the associated metadata.
- void createOffloadEntriesAndInfoMetadata();
-
- /// Loads all the offload entries information from the host IR
- /// metadata.
- void loadOffloadInfoMetadata();
-
- /// Returns __tgt_offload_entry type.
- QualType getTgtOffloadEntryQTy();
-
- /// Returns __tgt_device_image type.
- QualType getTgtDeviceImageQTy();
-
- /// Returns __tgt_bin_desc type.
- QualType getTgtBinaryDescriptorQTy();
-
- /// Start scanning from statement \a S and and emit all target regions
- /// found along the way.
- /// \param S Starting statement.
- /// \param ParentName Name of the function declaration that is being scanned.
- void scanForTargetRegionsFunctions(const Stmt *S, StringRef ParentName);
-
- /// Build type kmp_routine_entry_t (if not built yet).
- void emitKmpRoutineEntryT(QualType KmpInt32Ty);
-
- /// Returns pointer to kmpc_micro type.
- llvm::Type *getKmpc_MicroPointerTy();
-
- /// Returns specified OpenMP runtime function.
- /// \param Function OpenMP runtime function.
- /// \return Specified function.
- llvm::Constant *createRuntimeFunction(unsigned Function);
-
- /// Returns __kmpc_for_static_init_* runtime function for the specified
- /// size \a IVSize and sign \a IVSigned.
- llvm::Constant *createForStaticInitFunction(unsigned IVSize, bool IVSigned);
-
- /// Returns __kmpc_dispatch_init_* runtime function for the specified
- /// size \a IVSize and sign \a IVSigned.
- llvm::Constant *createDispatchInitFunction(unsigned IVSize, bool IVSigned);
-
- /// Returns __kmpc_dispatch_next_* runtime function for the specified
- /// size \a IVSize and sign \a IVSigned.
- llvm::Constant *createDispatchNextFunction(unsigned IVSize, bool IVSigned);
-
- /// Returns __kmpc_dispatch_fini_* runtime function for the specified
- /// size \a IVSize and sign \a IVSigned.
- llvm::Constant *createDispatchFiniFunction(unsigned IVSize, bool IVSigned);
-
- /// If the specified mangled name is not in the module, create and
- /// return threadprivate cache object. This object is a pointer's worth of
- /// storage that's reserved for use by the OpenMP runtime.
- /// \param VD Threadprivate variable.
- /// \return Cache variable for the specified threadprivate.
- llvm::Constant *getOrCreateThreadPrivateCache(const VarDecl *VD);
-
- /// Gets (if variable with the given name already exist) or creates
- /// internal global variable with the specified Name. The created variable has
- /// linkage CommonLinkage by default and is initialized by null value.
- /// \param Ty Type of the global variable. If it is exist already the type
- /// must be the same.
- /// \param Name Name of the variable.
- llvm::Constant *getOrCreateInternalVariable(llvm::Type *Ty,
- const llvm::Twine &Name);
-
- /// Set of threadprivate variables with the generated initializer.
- llvm::StringSet<> ThreadPrivateWithDefinition;
-
- /// Set of declare target variables with the generated initializer.
- llvm::StringSet<> DeclareTargetWithDefinition;
-
- /// Emits initialization code for the threadprivate variables.
- /// \param VDAddr Address of the global variable \a VD.
- /// \param Ctor Pointer to a global init function for \a VD.
- /// \param CopyCtor Pointer to a global copy function for \a VD.
- /// \param Dtor Pointer to a global destructor function for \a VD.
- /// \param Loc Location of threadprivate declaration.
- void emitThreadPrivateVarInit(CodeGenFunction &CGF, Address VDAddr,
- llvm::Value *Ctor, llvm::Value *CopyCtor,
- llvm::Value *Dtor, SourceLocation Loc);
-
- struct TaskResultTy {
- llvm::Value *NewTask = nullptr;
- llvm::Value *TaskEntry = nullptr;
- llvm::Value *NewTaskNewTaskTTy = nullptr;
- LValue TDBase;
- const RecordDecl *KmpTaskTQTyRD = nullptr;
- llvm::Value *TaskDupFn = nullptr;
- };
- /// Emit task region for the task directive. The task region is emitted in
- /// several steps:
- /// 1. Emit a call to kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32
- /// gtid, kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- /// kmp_routine_entry_t *task_entry). Here task_entry is a pointer to the
- /// function:
- /// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
- /// TaskFunction(gtid, tt->part_id, tt->shareds);
- /// return 0;
- /// }
- /// 2. Copy a list of shared variables to field shareds of the resulting
- /// structure kmp_task_t returned by the previous call (if any).
- /// 3. Copy a pointer to destructions function to field destructions of the
- /// resulting structure kmp_task_t.
- /// \param D Current task directive.
- /// \param TaskFunction An LLVM function with type void (*)(i32 /*gtid*/, i32
- /// /*part_id*/, captured_struct */*__context*/);
- /// \param SharedsTy A type which contains references the shared variables.
- /// \param Shareds Context with the list of shared variables from the \p
- /// TaskFunction.
- /// \param Data Additional data for task generation like tiednsee, final
- /// state, list of privates etc.
- TaskResultTy emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPExecutableDirective &D,
- llvm::Value *TaskFunction, QualType SharedsTy,
- Address Shareds, const OMPTaskDataTy &Data);
-
-public:
- explicit CGOpenMPRuntime(CodeGenModule &CGM)
- : CGOpenMPRuntime(CGM, ".", ".") {}
- virtual ~CGOpenMPRuntime() {}
- virtual void clear();
-
- /// Get the platform-specific name separator.
- std::string getName(ArrayRef<StringRef> Parts) const;
-
- /// Emit code for the specified user defined reduction construct.
- virtual void emitUserDefinedReduction(CodeGenFunction *CGF,
- const OMPDeclareReductionDecl *D);
- /// Get combiner/initializer for the specified user-defined reduction, if any.
- virtual std::pair<llvm::Function *, llvm::Function *>
- getUserDefinedReduction(const OMPDeclareReductionDecl *D);
-
- /// Emits outlined function for the specified OpenMP parallel directive
- /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
- /// kmp_int32 BoundID, struct context_vars*).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- virtual llvm::Value *emitParallelOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen);
-
- /// Emits outlined function for the specified OpenMP teams directive
- /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
- /// kmp_int32 BoundID, struct context_vars*).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- virtual llvm::Value *emitTeamsOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen);
-
- /// Emits outlined function for the OpenMP task directive \a D. This
- /// outlined function has type void(*)(kmp_int32 ThreadID, struct task_t*
- /// TaskT).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param PartIDVar Variable for partition id in the current OpenMP untied
- /// task region.
- /// \param TaskTVar Variable for task_t argument.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- /// \param Tied true if task is generated for tied task, false otherwise.
- /// \param NumberOfParts Number of parts in untied task. Ignored for tied
- /// tasks.
- ///
- virtual llvm::Value *emitTaskOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- const VarDecl *PartIDVar, const VarDecl *TaskTVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
- bool Tied, unsigned &NumberOfParts);
-
- /// Cleans up references to the objects in finished function.
- ///
- virtual void functionFinished(CodeGenFunction &CGF);
-
- /// Emits code for parallel or serial call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- /// \param IfCond Condition in the associated 'if' clause, if it was
- /// specified, nullptr otherwise.
- ///
- virtual void emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars,
- const Expr *IfCond);
-
- /// Emits a critical region.
- /// \param CriticalName Name of the critical region.
- /// \param CriticalOpGen Generator for the statement associated with the given
- /// critical region.
- /// \param Hint Value of the 'hint' clause (optional).
- virtual void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName,
- const RegionCodeGenTy &CriticalOpGen,
- SourceLocation Loc,
- const Expr *Hint = nullptr);
-
- /// Emits a master region.
- /// \param MasterOpGen Generator for the statement associated with the given
- /// master region.
- virtual void emitMasterRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &MasterOpGen,
- SourceLocation Loc);
-
- /// Emits code for a taskyield directive.
- virtual void emitTaskyieldCall(CodeGenFunction &CGF, SourceLocation Loc);
-
- /// Emit a taskgroup region.
- /// \param TaskgroupOpGen Generator for the statement associated with the
- /// given taskgroup region.
- virtual void emitTaskgroupRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &TaskgroupOpGen,
- SourceLocation Loc);
-
- /// Emits a single region.
- /// \param SingleOpGen Generator for the statement associated with the given
- /// single region.
- virtual void emitSingleRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &SingleOpGen,
- SourceLocation Loc,
- ArrayRef<const Expr *> CopyprivateVars,
- ArrayRef<const Expr *> DestExprs,
- ArrayRef<const Expr *> SrcExprs,
- ArrayRef<const Expr *> AssignmentOps);
-
- /// Emit an ordered region.
- /// \param OrderedOpGen Generator for the statement associated with the given
- /// ordered region.
- virtual void emitOrderedRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &OrderedOpGen,
- SourceLocation Loc, bool IsThreads);
-
- /// Emit an implicit/explicit barrier for OpenMP threads.
- /// \param Kind Directive for which this implicit barrier call must be
- /// generated. Must be OMPD_barrier for explicit barrier generation.
- /// \param EmitChecks true if need to emit checks for cancellation barriers.
- /// \param ForceSimpleCall true simple barrier call must be emitted, false if
- /// runtime class decides which one to emit (simple or with cancellation
- /// checks).
- ///
- virtual void emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind Kind,
- bool EmitChecks = true,
- bool ForceSimpleCall = false);
-
- /// Check if the specified \a ScheduleKind is static non-chunked.
- /// This kind of worksharing directive is emitted without outer loop.
- /// \param ScheduleKind Schedule kind specified in the 'schedule' clause.
- /// \param Chunked True if chunk is specified in the clause.
- ///
- virtual bool isStaticNonchunked(OpenMPScheduleClauseKind ScheduleKind,
- bool Chunked) const;
-
- /// Check if the specified \a ScheduleKind is static non-chunked.
- /// This kind of distribute directive is emitted without outer loop.
- /// \param ScheduleKind Schedule kind specified in the 'dist_schedule' clause.
- /// \param Chunked True if chunk is specified in the clause.
- ///
- virtual bool isStaticNonchunked(OpenMPDistScheduleClauseKind ScheduleKind,
- bool Chunked) const;
-
- /// Check if the specified \a ScheduleKind is static chunked.
- /// \param ScheduleKind Schedule kind specified in the 'schedule' clause.
- /// \param Chunked True if chunk is specified in the clause.
- ///
- virtual bool isStaticChunked(OpenMPScheduleClauseKind ScheduleKind,
- bool Chunked) const;
-
- /// Check if the specified \a ScheduleKind is static non-chunked.
- /// \param ScheduleKind Schedule kind specified in the 'dist_schedule' clause.
- /// \param Chunked True if chunk is specified in the clause.
- ///
- virtual bool isStaticChunked(OpenMPDistScheduleClauseKind ScheduleKind,
- bool Chunked) const;
-
- /// Check if the specified \a ScheduleKind is dynamic.
- /// This kind of worksharing directive is emitted without outer loop.
- /// \param ScheduleKind Schedule Kind specified in the 'schedule' clause.
- ///
- virtual bool isDynamic(OpenMPScheduleClauseKind ScheduleKind) const;
-
- /// struct with the values to be passed to the dispatch runtime function
- struct DispatchRTInput {
- /// Loop lower bound
- llvm::Value *LB = nullptr;
- /// Loop upper bound
- llvm::Value *UB = nullptr;
- /// Chunk size specified using 'schedule' clause (nullptr if chunk
- /// was not specified)
- llvm::Value *Chunk = nullptr;
- DispatchRTInput() = default;
- DispatchRTInput(llvm::Value *LB, llvm::Value *UB, llvm::Value *Chunk)
- : LB(LB), UB(UB), Chunk(Chunk) {}
- };
-
- /// Call the appropriate runtime routine to initialize it before start
- /// of loop.
-
- /// This is used for non static scheduled types and when the ordered
- /// clause is present on the loop construct.
- /// Depending on the loop schedule, it is necessary to call some runtime
- /// routine before start of the OpenMP loop to get the loop upper / lower
- /// bounds \a LB and \a UB and stride \a ST.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
- /// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the iteration variable.
- /// \param Ordered true if loop is ordered, false otherwise.
- /// \param DispatchValues struct containing llvm values for lower bound, upper
- /// bound, and chunk expression.
- /// For the default (nullptr) value, the chunk 1 will be used.
- ///
- virtual void emitForDispatchInit(CodeGenFunction &CGF, SourceLocation Loc,
- const OpenMPScheduleTy &ScheduleKind,
- unsigned IVSize, bool IVSigned, bool Ordered,
- const DispatchRTInput &DispatchValues);
-
- /// Struct with the values to be passed to the static runtime function
- struct StaticRTInput {
- /// Size of the iteration variable in bits.
- unsigned IVSize = 0;
- /// Sign of the iteration variable.
- bool IVSigned = false;
- /// true if loop is ordered, false otherwise.
- bool Ordered = false;
- /// Address of the output variable in which the flag of the last iteration
- /// is returned.
- Address IL = Address::invalid();
- /// Address of the output variable in which the lower iteration number is
- /// returned.
- Address LB = Address::invalid();
- /// Address of the output variable in which the upper iteration number is
- /// returned.
- Address UB = Address::invalid();
- /// Address of the output variable in which the stride value is returned
- /// necessary to generated the static_chunked scheduled loop.
- Address ST = Address::invalid();
- /// Value of the chunk for the static_chunked scheduled loop. For the
- /// default (nullptr) value, the chunk 1 will be used.
- llvm::Value *Chunk = nullptr;
- StaticRTInput(unsigned IVSize, bool IVSigned, bool Ordered, Address IL,
- Address LB, Address UB, Address ST,
- llvm::Value *Chunk = nullptr)
- : IVSize(IVSize), IVSigned(IVSigned), Ordered(Ordered), IL(IL), LB(LB),
- UB(UB), ST(ST), Chunk(Chunk) {}
- };
- /// Call the appropriate runtime routine to initialize it before start
- /// of loop.
- ///
- /// This is used only in case of static schedule, when the user did not
- /// specify a ordered clause on the loop construct.
- /// Depending on the loop schedule, it is necessary to call some runtime
- /// routine before start of the OpenMP loop to get the loop upper / lower
- /// bounds LB and UB and stride ST.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param DKind Kind of the directive.
- /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
- /// \param Values Input arguments for the construct.
- ///
- virtual void emitForStaticInit(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind DKind,
- const OpenMPScheduleTy &ScheduleKind,
- const StaticRTInput &Values);
-
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param SchedKind Schedule kind, specified by the 'dist_schedule' clause.
- /// \param Values Input arguments for the construct.
- ///
- virtual void emitDistributeStaticInit(CodeGenFunction &CGF,
- SourceLocation Loc,
- OpenMPDistScheduleClauseKind SchedKind,
- const StaticRTInput &Values);
-
- /// Call the appropriate runtime routine to notify that we finished
- /// iteration of the ordered loop with the dynamic scheduling.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the iteration variable.
- ///
- virtual void emitForOrderedIterationEnd(CodeGenFunction &CGF,
- SourceLocation Loc, unsigned IVSize,
- bool IVSigned);
-
- /// Call the appropriate runtime routine to notify that we finished
- /// all the work with current loop.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param DKind Kind of the directive for which the static finish is emitted.
- ///
- virtual void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind DKind);
-
- /// Call __kmpc_dispatch_next(
- /// ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
- /// kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
- /// kmp_int[32|64] *p_stride);
- /// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the iteration variable.
- /// \param IL Address of the output variable in which the flag of the
- /// last iteration is returned.
- /// \param LB Address of the output variable in which the lower iteration
- /// number is returned.
- /// \param UB Address of the output variable in which the upper iteration
- /// number is returned.
- /// \param ST Address of the output variable in which the stride value is
- /// returned.
- virtual llvm::Value *emitForNext(CodeGenFunction &CGF, SourceLocation Loc,
- unsigned IVSize, bool IVSigned,
- Address IL, Address LB,
- Address UB, Address ST);
-
- /// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
- /// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
- /// clause.
- /// \param NumThreads An integer value of threads.
- virtual void emitNumThreadsClause(CodeGenFunction &CGF,
- llvm::Value *NumThreads,
- SourceLocation Loc);
-
- /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
- /// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
- virtual void emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
- SourceLocation Loc);
-
- /// Returns address of the threadprivate variable for the current
- /// thread.
- /// \param VD Threadprivate variable.
- /// \param VDAddr Address of the global variable \a VD.
- /// \param Loc Location of the reference to threadprivate var.
- /// \return Address of the threadprivate variable for the current thread.
- virtual Address getAddrOfThreadPrivate(CodeGenFunction &CGF,
- const VarDecl *VD,
- Address VDAddr,
- SourceLocation Loc);
-
- /// Returns the address of the variable marked as declare target with link
- /// clause.
- virtual Address getAddrOfDeclareTargetLink(const VarDecl *VD);
-
- /// Emit a code for initialization of threadprivate variable. It emits
- /// a call to runtime library which adds initial value to the newly created
- /// threadprivate variable (if it is not constant) and registers destructor
- /// for the variable (if any).
- /// \param VD Threadprivate variable.
- /// \param VDAddr Address of the global variable \a VD.
- /// \param Loc Location of threadprivate declaration.
- /// \param PerformInit true if initialization expression is not constant.
- virtual llvm::Function *
- emitThreadPrivateVarDefinition(const VarDecl *VD, Address VDAddr,
- SourceLocation Loc, bool PerformInit,
- CodeGenFunction *CGF = nullptr);
-
- /// Emit a code for initialization of declare target variable.
- /// \param VD Declare target variable.
- /// \param Addr Address of the global variable \a VD.
- /// \param PerformInit true if initialization expression is not constant.
- virtual bool emitDeclareTargetVarDefinition(const VarDecl *VD,
- llvm::GlobalVariable *Addr,
- bool PerformInit);
-
- /// Creates artificial threadprivate variable with name \p Name and type \p
- /// VarType.
- /// \param VarType Type of the artificial threadprivate variable.
- /// \param Name Name of the artificial threadprivate variable.
- virtual Address getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
- QualType VarType,
- StringRef Name);
-
- /// Emit flush of the variables specified in 'omp flush' directive.
- /// \param Vars List of variables to flush.
- virtual void emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *> Vars,
- SourceLocation Loc);
-
- /// Emit task region for the task directive. The task region is
- /// emitted in several steps:
- /// 1. Emit a call to kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32
- /// gtid, kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- /// kmp_routine_entry_t *task_entry). Here task_entry is a pointer to the
- /// function:
- /// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
- /// TaskFunction(gtid, tt->part_id, tt->shareds);
- /// return 0;
- /// }
- /// 2. Copy a list of shared variables to field shareds of the resulting
- /// structure kmp_task_t returned by the previous call (if any).
- /// 3. Copy a pointer to destructions function to field destructions of the
- /// resulting structure kmp_task_t.
- /// 4. Emit a call to kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid,
- /// kmp_task_t *new_task), where new_task is a resulting structure from
- /// previous items.
- /// \param D Current task directive.
- /// \param TaskFunction An LLVM function with type void (*)(i32 /*gtid*/, i32
- /// /*part_id*/, captured_struct */*__context*/);
- /// \param SharedsTy A type which contains references the shared variables.
- /// \param Shareds Context with the list of shared variables from the \p
- /// TaskFunction.
- /// \param IfCond Not a nullptr if 'if' clause was specified, nullptr
- /// otherwise.
- /// \param Data Additional data for task generation like tiednsee, final
- /// state, list of privates etc.
- virtual void emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPExecutableDirective &D,
- llvm::Value *TaskFunction, QualType SharedsTy,
- Address Shareds, const Expr *IfCond,
- const OMPTaskDataTy &Data);
-
- /// Emit task region for the taskloop directive. The taskloop region is
- /// emitted in several steps:
- /// 1. Emit a call to kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32
- /// gtid, kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- /// kmp_routine_entry_t *task_entry). Here task_entry is a pointer to the
- /// function:
- /// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
- /// TaskFunction(gtid, tt->part_id, tt->shareds);
- /// return 0;
- /// }
- /// 2. Copy a list of shared variables to field shareds of the resulting
- /// structure kmp_task_t returned by the previous call (if any).
- /// 3. Copy a pointer to destructions function to field destructions of the
- /// resulting structure kmp_task_t.
- /// 4. Emit a call to void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t
- /// *task, int if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int
- /// nogroup, int sched, kmp_uint64 grainsize, void *task_dup ), where new_task
- /// is a resulting structure from
- /// previous items.
- /// \param D Current task directive.
- /// \param TaskFunction An LLVM function with type void (*)(i32 /*gtid*/, i32
- /// /*part_id*/, captured_struct */*__context*/);
- /// \param SharedsTy A type which contains references the shared variables.
- /// \param Shareds Context with the list of shared variables from the \p
- /// TaskFunction.
- /// \param IfCond Not a nullptr if 'if' clause was specified, nullptr
- /// otherwise.
- /// \param Data Additional data for task generation like tiednsee, final
- /// state, list of privates etc.
- virtual void emitTaskLoopCall(
- CodeGenFunction &CGF, SourceLocation Loc, const OMPLoopDirective &D,
- llvm::Value *TaskFunction, QualType SharedsTy, Address Shareds,
- const Expr *IfCond, const OMPTaskDataTy &Data);
-
- /// Emit code for the directive that does not require outlining.
- ///
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- /// \param HasCancel true if region has inner cancel directive, false
- /// otherwise.
- virtual void emitInlinedDirective(CodeGenFunction &CGF,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen,
- bool HasCancel = false);
-
- /// Emits reduction function.
- /// \param ArgsType Array type containing pointers to reduction variables.
- /// \param Privates List of private copies for original reduction arguments.
- /// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
- /// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
- /// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
- /// or 'operator binop(LHS, RHS)'.
- llvm::Value *emitReductionFunction(CodeGenModule &CGM, SourceLocation Loc,
- llvm::Type *ArgsType,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps);
-
- /// Emits single reduction combiner
- void emitSingleReductionCombiner(CodeGenFunction &CGF,
- const Expr *ReductionOp,
- const Expr *PrivateRef,
- const DeclRefExpr *LHS,
- const DeclRefExpr *RHS);
-
- struct ReductionOptionsTy {
- bool WithNowait;
- bool SimpleReduction;
- OpenMPDirectiveKind ReductionKind;
- };
- /// Emit a code for reduction clause. Next code should be emitted for
- /// reduction:
- /// \code
- ///
- /// static kmp_critical_name lock = { 0 };
- ///
- /// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
- /// ...
- /// *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
- /// ...
- /// }
- ///
- /// ...
- /// void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
- /// switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
- /// RedList, reduce_func, &<lock>)) {
- /// case 1:
- /// ...
- /// <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
- /// ...
- /// __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
- /// break;
- /// case 2:
- /// ...
- /// Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
- /// ...
- /// break;
- /// default:;
- /// }
- /// \endcode
- ///
- /// \param Privates List of private copies for original reduction arguments.
- /// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
- /// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
- /// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
- /// or 'operator binop(LHS, RHS)'.
- /// \param Options List of options for reduction codegen:
- /// WithNowait true if parent directive has also nowait clause, false
- /// otherwise.
- /// SimpleReduction Emit reduction operation only. Used for omp simd
- /// directive on the host.
- /// ReductionKind The kind of reduction to perform.
- virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps,
- ReductionOptionsTy Options);
-
- /// Emit a code for initialization of task reduction clause. Next code
- /// should be emitted for reduction:
- /// \code
- ///
- /// _task_red_item_t red_data[n];
- /// ...
- /// red_data[i].shar = &origs[i];
- /// red_data[i].size = sizeof(origs[i]);
- /// red_data[i].f_init = (void*)RedInit<i>;
- /// red_data[i].f_fini = (void*)RedDest<i>;
- /// red_data[i].f_comb = (void*)RedOp<i>;
- /// red_data[i].flags = <Flag_i>;
- /// ...
- /// void* tg1 = __kmpc_task_reduction_init(gtid, n, red_data);
- /// \endcode
- ///
- /// \param LHSExprs List of LHS in \a Data.ReductionOps reduction operations.
- /// \param RHSExprs List of RHS in \a Data.ReductionOps reduction operations.
- /// \param Data Additional data for task generation like tiedness, final
- /// state, list of privates, reductions etc.
- virtual llvm::Value *emitTaskReductionInit(CodeGenFunction &CGF,
- SourceLocation Loc,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- const OMPTaskDataTy &Data);
-
- /// Required to resolve existing problems in the runtime. Emits threadprivate
- /// variables to store the size of the VLAs/array sections for
- /// initializer/combiner/finalizer functions + emits threadprivate variable to
- /// store the pointer to the original reduction item for the custom
- /// initializer defined by declare reduction construct.
- /// \param RCG Allows to reuse an existing data for the reductions.
- /// \param N Reduction item for which fixups must be emitted.
- virtual void emitTaskReductionFixups(CodeGenFunction &CGF, SourceLocation Loc,
- ReductionCodeGen &RCG, unsigned N);
-
- /// Get the address of `void *` type of the privatue copy of the reduction
- /// item specified by the \p SharedLVal.
- /// \param ReductionsPtr Pointer to the reduction data returned by the
- /// emitTaskReductionInit function.
- /// \param SharedLVal Address of the original reduction item.
- virtual Address getTaskReductionItem(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *ReductionsPtr,
- LValue SharedLVal);
-
- /// Emit code for 'taskwait' directive.
- virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc);
-
- /// Emit code for 'cancellation point' construct.
- /// \param CancelRegion Region kind for which the cancellation point must be
- /// emitted.
- ///
- virtual void emitCancellationPointCall(CodeGenFunction &CGF,
- SourceLocation Loc,
- OpenMPDirectiveKind CancelRegion);
-
- /// Emit code for 'cancel' construct.
- /// \param IfCond Condition in the associated 'if' clause, if it was
- /// specified, nullptr otherwise.
- /// \param CancelRegion Region kind for which the cancel must be emitted.
- ///
- virtual void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
- const Expr *IfCond,
- OpenMPDirectiveKind CancelRegion);
-
- /// Emit outilined function for 'target' directive.
- /// \param D Directive to emit.
- /// \param ParentName Name of the function that encloses the target region.
- /// \param OutlinedFn Outlined function value to be defined by this call.
- /// \param OutlinedFnID Outlined function ID value to be defined by this call.
- /// \param IsOffloadEntry True if the outlined function is an offload entry.
- /// \param CodeGen Code generation sequence for the \a D directive.
- /// An outlined function may not be an entry if, e.g. the if clause always
- /// evaluates to false.
- virtual void emitTargetOutlinedFunction(const OMPExecutableDirective &D,
- StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen);
-
- /// Emit code that pushes the trip count of loops associated with constructs
- /// 'target teams distribute' and 'teams distribute parallel for'.
- /// \param SizeEmitter Emits the int64 value for the number of iterations of
- /// the associated loop.
- virtual void emitTargetNumIterationsCall(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *Device,
- const llvm::function_ref<llvm::Value *(
- CodeGenFunction &CGF, const OMPLoopDirective &D)> &SizeEmitter);
-
- /// Emit the target offloading code associated with \a D. The emitted
- /// code attempts offloading the execution to the device, an the event of
- /// a failure it executes the host version outlined in \a OutlinedFn.
- /// \param D Directive to emit.
- /// \param OutlinedFn Host version of the code to be offloaded.
- /// \param OutlinedFnID ID of host version of the code to be offloaded.
- /// \param IfCond Expression evaluated in if clause associated with the target
- /// directive, or null if no if clause is used.
- /// \param Device Expression evaluated in device clause associated with the
- /// target directive, or null if no device clause is used.
- virtual void emitTargetCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- llvm::Value *OutlinedFn,
- llvm::Value *OutlinedFnID, const Expr *IfCond,
- const Expr *Device);
-
- /// Emit the target regions enclosed in \a GD function definition or
- /// the function itself in case it is a valid device function. Returns true if
- /// \a GD was dealt with successfully.
- /// \param GD Function to scan.
- virtual bool emitTargetFunctions(GlobalDecl GD);
-
- /// Emit the global variable if it is a valid device global variable.
- /// Returns true if \a GD was dealt with successfully.
- /// \param GD Variable declaration to emit.
- virtual bool emitTargetGlobalVariable(GlobalDecl GD);
-
- /// Checks if the provided global decl \a GD is a declare target variable and
- /// registers it when emitting code for the host.
- virtual void registerTargetGlobalVariable(const VarDecl *VD,
- llvm::Constant *Addr);
-
- /// Emit the global \a GD if it is meaningful for the target. Returns
- /// if it was emitted successfully.
- /// \param GD Global to scan.
- virtual bool emitTargetGlobal(GlobalDecl GD);
-
- /// Creates the offloading descriptor in the event any target region
- /// was emitted in the current module and return the function that registers
- /// it.
- virtual llvm::Function *emitRegistrationFunction();
-
- /// Emits code for teams call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// \param OutlinedFn Outlined function to be run by team masters. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- ///
- virtual void emitTeamsCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars);
-
- /// Emits call to void __kmpc_push_num_teams(ident_t *loc, kmp_int32
- /// global_tid, kmp_int32 num_teams, kmp_int32 thread_limit) to generate code
- /// for num_teams clause.
- /// \param NumTeams An integer expression of teams.
- /// \param ThreadLimit An integer expression of threads.
- virtual void emitNumTeamsClause(CodeGenFunction &CGF, const Expr *NumTeams,
- const Expr *ThreadLimit, SourceLocation Loc);
-
- /// Struct that keeps all the relevant information that should be kept
- /// throughout a 'target data' region.
- class TargetDataInfo {
- /// Set to true if device pointer information have to be obtained.
- bool RequiresDevicePointerInfo = false;
-
- public:
- /// The array of base pointer passed to the runtime library.
- llvm::Value *BasePointersArray = nullptr;
- /// The array of section pointers passed to the runtime library.
- llvm::Value *PointersArray = nullptr;
- /// The array of sizes passed to the runtime library.
- llvm::Value *SizesArray = nullptr;
- /// The array of map types passed to the runtime library.
- llvm::Value *MapTypesArray = nullptr;
- /// The total number of pointers passed to the runtime library.
- unsigned NumberOfPtrs = 0u;
- /// Map between the a declaration of a capture and the corresponding base
- /// pointer address where the runtime returns the device pointers.
- llvm::DenseMap<const ValueDecl *, Address> CaptureDeviceAddrMap;
-
- explicit TargetDataInfo() {}
- explicit TargetDataInfo(bool RequiresDevicePointerInfo)
- : RequiresDevicePointerInfo(RequiresDevicePointerInfo) {}
- /// Clear information about the data arrays.
- void clearArrayInfo() {
- BasePointersArray = nullptr;
- PointersArray = nullptr;
- SizesArray = nullptr;
- MapTypesArray = nullptr;
- NumberOfPtrs = 0u;
- }
- /// Return true if the current target data information has valid arrays.
- bool isValid() {
- return BasePointersArray && PointersArray && SizesArray &&
- MapTypesArray && NumberOfPtrs;
- }
- bool requiresDevicePointerInfo() { return RequiresDevicePointerInfo; }
- };
-
- /// Emit the target data mapping code associated with \a D.
- /// \param D Directive to emit.
- /// \param IfCond Expression evaluated in if clause associated with the
- /// target directive, or null if no device clause is used.
- /// \param Device Expression evaluated in device clause associated with the
- /// target directive, or null if no device clause is used.
- /// \param Info A record used to store information that needs to be preserved
- /// until the region is closed.
- virtual void emitTargetDataCalls(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- const Expr *IfCond, const Expr *Device,
- const RegionCodeGenTy &CodeGen,
- TargetDataInfo &Info);
-
- /// Emit the data mapping/movement code associated with the directive
- /// \a D that should be of the form 'target [{enter|exit} data | update]'.
- /// \param D Directive to emit.
- /// \param IfCond Expression evaluated in if clause associated with the target
- /// directive, or null if no if clause is used.
- /// \param Device Expression evaluated in device clause associated with the
- /// target directive, or null if no device clause is used.
- virtual void emitTargetDataStandAloneCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- const Expr *IfCond,
- const Expr *Device);
-
- /// Marks function \a Fn with properly mangled versions of vector functions.
- /// \param FD Function marked as 'declare simd'.
- /// \param Fn LLVM function that must be marked with 'declare simd'
- /// attributes.
- virtual void emitDeclareSimdFunction(const FunctionDecl *FD,
- llvm::Function *Fn);
-
- /// Emit initialization for doacross loop nesting support.
- /// \param D Loop-based construct used in doacross nesting construct.
- virtual void emitDoacrossInit(CodeGenFunction &CGF, const OMPLoopDirective &D,
- ArrayRef<Expr *> NumIterations);
-
- /// Emit code for doacross ordered directive with 'depend' clause.
- /// \param C 'depend' clause with 'sink|source' dependency kind.
- virtual void emitDoacrossOrdered(CodeGenFunction &CGF,
- const OMPDependClause *C);
-
- /// Translates the native parameter of outlined function if this is required
- /// for target.
- /// \param FD Field decl from captured record for the parameter.
- /// \param NativeParam Parameter itself.
- virtual const VarDecl *translateParameter(const FieldDecl *FD,
- const VarDecl *NativeParam) const {
- return NativeParam;
- }
-
- /// Gets the address of the native argument basing on the address of the
- /// target-specific parameter.
- /// \param NativeParam Parameter itself.
- /// \param TargetParam Corresponding target-specific parameter.
- virtual Address getParameterAddress(CodeGenFunction &CGF,
- const VarDecl *NativeParam,
- const VarDecl *TargetParam) const;
-
- /// Choose default schedule type and chunk value for the
- /// dist_schedule clause.
- virtual void getDefaultDistScheduleAndChunk(CodeGenFunction &CGF,
- const OMPLoopDirective &S, OpenMPDistScheduleClauseKind &ScheduleKind,
- llvm::Value *&Chunk) const {}
-
- /// Choose default schedule type and chunk value for the
- /// schedule clause.
- virtual void getDefaultScheduleAndChunk(CodeGenFunction &CGF,
- const OMPLoopDirective &S, OpenMPScheduleClauseKind &ScheduleKind,
- const Expr *&ChunkExpr) const {}
-
- /// Emits call of the outlined function with the provided arguments,
- /// translating these arguments to correct target-specific arguments.
- virtual void
- emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> Args = llvm::None) const;
-
- /// Emits OpenMP-specific function prolog.
- /// Required for device constructs.
- virtual void emitFunctionProlog(CodeGenFunction &CGF, const Decl *D) {}
-
- /// Gets the OpenMP-specific address of the local variable.
- virtual Address getAddressOfLocalVariable(CodeGenFunction &CGF,
- const VarDecl *VD);
-
- /// Marks the declaration as already emitted for the device code and returns
- /// true, if it was marked already, and false, otherwise.
- bool markAsGlobalTarget(GlobalDecl GD);
-
- /// Emit deferred declare target variables marked for deferred emission.
- void emitDeferredTargetDecls() const;
-
- /// Adjust some parameters for the target-based directives, like addresses of
- /// the variables captured by reference in lambdas.
- virtual void
- adjustTargetSpecificDataForLambdas(CodeGenFunction &CGF,
- const OMPExecutableDirective &D) const;
-
- /// Perform check on requires decl to ensure that target architecture
- /// supports unified addressing
- virtual void checkArchForUnifiedAddressing(CodeGenModule &CGM,
- const OMPRequiresDecl *D) const {}
-};
-
-/// Class supports emissionof SIMD-only code.
-class CGOpenMPSIMDRuntime final : public CGOpenMPRuntime {
-public:
- explicit CGOpenMPSIMDRuntime(CodeGenModule &CGM) : CGOpenMPRuntime(CGM) {}
- ~CGOpenMPSIMDRuntime() override {}
-
- /// Emits outlined function for the specified OpenMP parallel directive
- /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
- /// kmp_int32 BoundID, struct context_vars*).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- llvm::Value *
- emitParallelOutlinedFunction(const OMPExecutableDirective &D,
- const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) override;
-
- /// Emits outlined function for the specified OpenMP teams directive
- /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
- /// kmp_int32 BoundID, struct context_vars*).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- llvm::Value *
- emitTeamsOutlinedFunction(const OMPExecutableDirective &D,
- const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) override;
-
- /// Emits outlined function for the OpenMP task directive \a D. This
- /// outlined function has type void(*)(kmp_int32 ThreadID, struct task_t*
- /// TaskT).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param PartIDVar Variable for partition id in the current OpenMP untied
- /// task region.
- /// \param TaskTVar Variable for task_t argument.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- /// \param Tied true if task is generated for tied task, false otherwise.
- /// \param NumberOfParts Number of parts in untied task. Ignored for tied
- /// tasks.
- ///
- llvm::Value *emitTaskOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- const VarDecl *PartIDVar, const VarDecl *TaskTVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
- bool Tied, unsigned &NumberOfParts) override;
-
- /// Emits code for parallel or serial call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- /// \param IfCond Condition in the associated 'if' clause, if it was
- /// specified, nullptr otherwise.
- ///
- void emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars,
- const Expr *IfCond) override;
-
- /// Emits a critical region.
- /// \param CriticalName Name of the critical region.
- /// \param CriticalOpGen Generator for the statement associated with the given
- /// critical region.
- /// \param Hint Value of the 'hint' clause (optional).
- void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName,
- const RegionCodeGenTy &CriticalOpGen,
- SourceLocation Loc,
- const Expr *Hint = nullptr) override;
-
- /// Emits a master region.
- /// \param MasterOpGen Generator for the statement associated with the given
- /// master region.
- void emitMasterRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &MasterOpGen,
- SourceLocation Loc) override;
-
- /// Emits code for a taskyield directive.
- void emitTaskyieldCall(CodeGenFunction &CGF, SourceLocation Loc) override;
-
- /// Emit a taskgroup region.
- /// \param TaskgroupOpGen Generator for the statement associated with the
- /// given taskgroup region.
- void emitTaskgroupRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &TaskgroupOpGen,
- SourceLocation Loc) override;
-
- /// Emits a single region.
- /// \param SingleOpGen Generator for the statement associated with the given
- /// single region.
- void emitSingleRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &SingleOpGen, SourceLocation Loc,
- ArrayRef<const Expr *> CopyprivateVars,
- ArrayRef<const Expr *> DestExprs,
- ArrayRef<const Expr *> SrcExprs,
- ArrayRef<const Expr *> AssignmentOps) override;
-
- /// Emit an ordered region.
- /// \param OrderedOpGen Generator for the statement associated with the given
- /// ordered region.
- void emitOrderedRegion(CodeGenFunction &CGF,
- const RegionCodeGenTy &OrderedOpGen,
- SourceLocation Loc, bool IsThreads) override;
-
- /// Emit an implicit/explicit barrier for OpenMP threads.
- /// \param Kind Directive for which this implicit barrier call must be
- /// generated. Must be OMPD_barrier for explicit barrier generation.
- /// \param EmitChecks true if need to emit checks for cancellation barriers.
- /// \param ForceSimpleCall true simple barrier call must be emitted, false if
- /// runtime class decides which one to emit (simple or with cancellation
- /// checks).
- ///
- void emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind Kind, bool EmitChecks = true,
- bool ForceSimpleCall = false) override;
-
- /// This is used for non static scheduled types and when the ordered
- /// clause is present on the loop construct.
- /// Depending on the loop schedule, it is necessary to call some runtime
- /// routine before start of the OpenMP loop to get the loop upper / lower
- /// bounds \a LB and \a UB and stride \a ST.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
- /// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the iteration variable.
- /// \param Ordered true if loop is ordered, false otherwise.
- /// \param DispatchValues struct containing llvm values for lower bound, upper
- /// bound, and chunk expression.
- /// For the default (nullptr) value, the chunk 1 will be used.
- ///
- void emitForDispatchInit(CodeGenFunction &CGF, SourceLocation Loc,
- const OpenMPScheduleTy &ScheduleKind,
- unsigned IVSize, bool IVSigned, bool Ordered,
- const DispatchRTInput &DispatchValues) override;
-
- /// Call the appropriate runtime routine to initialize it before start
- /// of loop.
- ///
- /// This is used only in case of static schedule, when the user did not
- /// specify a ordered clause on the loop construct.
- /// Depending on the loop schedule, it is necessary to call some runtime
- /// routine before start of the OpenMP loop to get the loop upper / lower
- /// bounds LB and UB and stride ST.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param DKind Kind of the directive.
- /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
- /// \param Values Input arguments for the construct.
- ///
- void emitForStaticInit(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind DKind,
- const OpenMPScheduleTy &ScheduleKind,
- const StaticRTInput &Values) override;
-
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param SchedKind Schedule kind, specified by the 'dist_schedule' clause.
- /// \param Values Input arguments for the construct.
- ///
- void emitDistributeStaticInit(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDistScheduleClauseKind SchedKind,
- const StaticRTInput &Values) override;
-
- /// Call the appropriate runtime routine to notify that we finished
- /// iteration of the ordered loop with the dynamic scheduling.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the iteration variable.
- ///
- void emitForOrderedIterationEnd(CodeGenFunction &CGF, SourceLocation Loc,
- unsigned IVSize, bool IVSigned) override;
-
- /// Call the appropriate runtime routine to notify that we finished
- /// all the work with current loop.
- ///
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- /// \param DKind Kind of the directive for which the static finish is emitted.
- ///
- void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind DKind) override;
-
- /// Call __kmpc_dispatch_next(
- /// ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
- /// kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
- /// kmp_int[32|64] *p_stride);
- /// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the iteration variable.
- /// \param IL Address of the output variable in which the flag of the
- /// last iteration is returned.
- /// \param LB Address of the output variable in which the lower iteration
- /// number is returned.
- /// \param UB Address of the output variable in which the upper iteration
- /// number is returned.
- /// \param ST Address of the output variable in which the stride value is
- /// returned.
- llvm::Value *emitForNext(CodeGenFunction &CGF, SourceLocation Loc,
- unsigned IVSize, bool IVSigned, Address IL,
- Address LB, Address UB, Address ST) override;
-
- /// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
- /// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
- /// clause.
- /// \param NumThreads An integer value of threads.
- void emitNumThreadsClause(CodeGenFunction &CGF, llvm::Value *NumThreads,
- SourceLocation Loc) override;
-
- /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
- /// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
- void emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
- SourceLocation Loc) override;
-
- /// Returns address of the threadprivate variable for the current
- /// thread.
- /// \param VD Threadprivate variable.
- /// \param VDAddr Address of the global variable \a VD.
- /// \param Loc Location of the reference to threadprivate var.
- /// \return Address of the threadprivate variable for the current thread.
- Address getAddrOfThreadPrivate(CodeGenFunction &CGF, const VarDecl *VD,
- Address VDAddr, SourceLocation Loc) override;
-
- /// Emit a code for initialization of threadprivate variable. It emits
- /// a call to runtime library which adds initial value to the newly created
- /// threadprivate variable (if it is not constant) and registers destructor
- /// for the variable (if any).
- /// \param VD Threadprivate variable.
- /// \param VDAddr Address of the global variable \a VD.
- /// \param Loc Location of threadprivate declaration.
- /// \param PerformInit true if initialization expression is not constant.
- llvm::Function *
- emitThreadPrivateVarDefinition(const VarDecl *VD, Address VDAddr,
- SourceLocation Loc, bool PerformInit,
- CodeGenFunction *CGF = nullptr) override;
-
- /// Creates artificial threadprivate variable with name \p Name and type \p
- /// VarType.
- /// \param VarType Type of the artificial threadprivate variable.
- /// \param Name Name of the artificial threadprivate variable.
- Address getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
- QualType VarType,
- StringRef Name) override;
-
- /// Emit flush of the variables specified in 'omp flush' directive.
- /// \param Vars List of variables to flush.
- void emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *> Vars,
- SourceLocation Loc) override;
-
- /// Emit task region for the task directive. The task region is
- /// emitted in several steps:
- /// 1. Emit a call to kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32
- /// gtid, kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- /// kmp_routine_entry_t *task_entry). Here task_entry is a pointer to the
- /// function:
- /// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
- /// TaskFunction(gtid, tt->part_id, tt->shareds);
- /// return 0;
- /// }
- /// 2. Copy a list of shared variables to field shareds of the resulting
- /// structure kmp_task_t returned by the previous call (if any).
- /// 3. Copy a pointer to destructions function to field destructions of the
- /// resulting structure kmp_task_t.
- /// 4. Emit a call to kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid,
- /// kmp_task_t *new_task), where new_task is a resulting structure from
- /// previous items.
- /// \param D Current task directive.
- /// \param TaskFunction An LLVM function with type void (*)(i32 /*gtid*/, i32
- /// /*part_id*/, captured_struct */*__context*/);
- /// \param SharedsTy A type which contains references the shared variables.
- /// \param Shareds Context with the list of shared variables from the \p
- /// TaskFunction.
- /// \param IfCond Not a nullptr if 'if' clause was specified, nullptr
- /// otherwise.
- /// \param Data Additional data for task generation like tiednsee, final
- /// state, list of privates etc.
- void emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPExecutableDirective &D, llvm::Value *TaskFunction,
- QualType SharedsTy, Address Shareds, const Expr *IfCond,
- const OMPTaskDataTy &Data) override;
-
- /// Emit task region for the taskloop directive. The taskloop region is
- /// emitted in several steps:
- /// 1. Emit a call to kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32
- /// gtid, kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
- /// kmp_routine_entry_t *task_entry). Here task_entry is a pointer to the
- /// function:
- /// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
- /// TaskFunction(gtid, tt->part_id, tt->shareds);
- /// return 0;
- /// }
- /// 2. Copy a list of shared variables to field shareds of the resulting
- /// structure kmp_task_t returned by the previous call (if any).
- /// 3. Copy a pointer to destructions function to field destructions of the
- /// resulting structure kmp_task_t.
- /// 4. Emit a call to void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t
- /// *task, int if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int
- /// nogroup, int sched, kmp_uint64 grainsize, void *task_dup ), where new_task
- /// is a resulting structure from
- /// previous items.
- /// \param D Current task directive.
- /// \param TaskFunction An LLVM function with type void (*)(i32 /*gtid*/, i32
- /// /*part_id*/, captured_struct */*__context*/);
- /// \param SharedsTy A type which contains references the shared variables.
- /// \param Shareds Context with the list of shared variables from the \p
- /// TaskFunction.
- /// \param IfCond Not a nullptr if 'if' clause was specified, nullptr
- /// otherwise.
- /// \param Data Additional data for task generation like tiednsee, final
- /// state, list of privates etc.
- void emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
- const OMPLoopDirective &D, llvm::Value *TaskFunction,
- QualType SharedsTy, Address Shareds, const Expr *IfCond,
- const OMPTaskDataTy &Data) override;
-
- /// Emit a code for reduction clause. Next code should be emitted for
- /// reduction:
- /// \code
- ///
- /// static kmp_critical_name lock = { 0 };
- ///
- /// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
- /// ...
- /// *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
- /// ...
- /// }
- ///
- /// ...
- /// void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
- /// switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
- /// RedList, reduce_func, &<lock>)) {
- /// case 1:
- /// ...
- /// <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
- /// ...
- /// __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
- /// break;
- /// case 2:
- /// ...
- /// Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
- /// ...
- /// break;
- /// default:;
- /// }
- /// \endcode
- ///
- /// \param Privates List of private copies for original reduction arguments.
- /// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
- /// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
- /// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
- /// or 'operator binop(LHS, RHS)'.
- /// \param Options List of options for reduction codegen:
- /// WithNowait true if parent directive has also nowait clause, false
- /// otherwise.
- /// SimpleReduction Emit reduction operation only. Used for omp simd
- /// directive on the host.
- /// ReductionKind The kind of reduction to perform.
- void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps,
- ReductionOptionsTy Options) override;
-
- /// Emit a code for initialization of task reduction clause. Next code
- /// should be emitted for reduction:
- /// \code
- ///
- /// _task_red_item_t red_data[n];
- /// ...
- /// red_data[i].shar = &origs[i];
- /// red_data[i].size = sizeof(origs[i]);
- /// red_data[i].f_init = (void*)RedInit<i>;
- /// red_data[i].f_fini = (void*)RedDest<i>;
- /// red_data[i].f_comb = (void*)RedOp<i>;
- /// red_data[i].flags = <Flag_i>;
- /// ...
- /// void* tg1 = __kmpc_task_reduction_init(gtid, n, red_data);
- /// \endcode
- ///
- /// \param LHSExprs List of LHS in \a Data.ReductionOps reduction operations.
- /// \param RHSExprs List of RHS in \a Data.ReductionOps reduction operations.
- /// \param Data Additional data for task generation like tiedness, final
- /// state, list of privates, reductions etc.
- llvm::Value *emitTaskReductionInit(CodeGenFunction &CGF, SourceLocation Loc,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- const OMPTaskDataTy &Data) override;
-
- /// Required to resolve existing problems in the runtime. Emits threadprivate
- /// variables to store the size of the VLAs/array sections for
- /// initializer/combiner/finalizer functions + emits threadprivate variable to
- /// store the pointer to the original reduction item for the custom
- /// initializer defined by declare reduction construct.
- /// \param RCG Allows to reuse an existing data for the reductions.
- /// \param N Reduction item for which fixups must be emitted.
- void emitTaskReductionFixups(CodeGenFunction &CGF, SourceLocation Loc,
- ReductionCodeGen &RCG, unsigned N) override;
-
- /// Get the address of `void *` type of the privatue copy of the reduction
- /// item specified by the \p SharedLVal.
- /// \param ReductionsPtr Pointer to the reduction data returned by the
- /// emitTaskReductionInit function.
- /// \param SharedLVal Address of the original reduction item.
- Address getTaskReductionItem(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *ReductionsPtr,
- LValue SharedLVal) override;
-
- /// Emit code for 'taskwait' directive.
- void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc) override;
-
- /// Emit code for 'cancellation point' construct.
- /// \param CancelRegion Region kind for which the cancellation point must be
- /// emitted.
- ///
- void emitCancellationPointCall(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind CancelRegion) override;
-
- /// Emit code for 'cancel' construct.
- /// \param IfCond Condition in the associated 'if' clause, if it was
- /// specified, nullptr otherwise.
- /// \param CancelRegion Region kind for which the cancel must be emitted.
- ///
- void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
- const Expr *IfCond,
- OpenMPDirectiveKind CancelRegion) override;
-
- /// Emit outilined function for 'target' directive.
- /// \param D Directive to emit.
- /// \param ParentName Name of the function that encloses the target region.
- /// \param OutlinedFn Outlined function value to be defined by this call.
- /// \param OutlinedFnID Outlined function ID value to be defined by this call.
- /// \param IsOffloadEntry True if the outlined function is an offload entry.
- /// \param CodeGen Code generation sequence for the \a D directive.
- /// An outlined function may not be an entry if, e.g. the if clause always
- /// evaluates to false.
- void emitTargetOutlinedFunction(const OMPExecutableDirective &D,
- StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen) override;
-
- /// Emit the target offloading code associated with \a D. The emitted
- /// code attempts offloading the execution to the device, an the event of
- /// a failure it executes the host version outlined in \a OutlinedFn.
- /// \param D Directive to emit.
- /// \param OutlinedFn Host version of the code to be offloaded.
- /// \param OutlinedFnID ID of host version of the code to be offloaded.
- /// \param IfCond Expression evaluated in if clause associated with the target
- /// directive, or null if no if clause is used.
- /// \param Device Expression evaluated in device clause associated with the
- /// target directive, or null if no device clause is used.
- void emitTargetCall(CodeGenFunction &CGF, const OMPExecutableDirective &D,
- llvm::Value *OutlinedFn, llvm::Value *OutlinedFnID,
- const Expr *IfCond, const Expr *Device) override;
-
- /// Emit the target regions enclosed in \a GD function definition or
- /// the function itself in case it is a valid device function. Returns true if
- /// \a GD was dealt with successfully.
- /// \param GD Function to scan.
- bool emitTargetFunctions(GlobalDecl GD) override;
-
- /// Emit the global variable if it is a valid device global variable.
- /// Returns true if \a GD was dealt with successfully.
- /// \param GD Variable declaration to emit.
- bool emitTargetGlobalVariable(GlobalDecl GD) override;
-
- /// Emit the global \a GD if it is meaningful for the target. Returns
- /// if it was emitted successfully.
- /// \param GD Global to scan.
- bool emitTargetGlobal(GlobalDecl GD) override;
-
- /// Creates the offloading descriptor in the event any target region
- /// was emitted in the current module and return the function that registers
- /// it.
- llvm::Function *emitRegistrationFunction() override;
-
- /// Emits code for teams call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// \param OutlinedFn Outlined function to be run by team masters. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- ///
- void emitTeamsCall(CodeGenFunction &CGF, const OMPExecutableDirective &D,
- SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars) override;
-
- /// Emits call to void __kmpc_push_num_teams(ident_t *loc, kmp_int32
- /// global_tid, kmp_int32 num_teams, kmp_int32 thread_limit) to generate code
- /// for num_teams clause.
- /// \param NumTeams An integer expression of teams.
- /// \param ThreadLimit An integer expression of threads.
- void emitNumTeamsClause(CodeGenFunction &CGF, const Expr *NumTeams,
- const Expr *ThreadLimit, SourceLocation Loc) override;
-
- /// Emit the target data mapping code associated with \a D.
- /// \param D Directive to emit.
- /// \param IfCond Expression evaluated in if clause associated with the
- /// target directive, or null if no device clause is used.
- /// \param Device Expression evaluated in device clause associated with the
- /// target directive, or null if no device clause is used.
- /// \param Info A record used to store information that needs to be preserved
- /// until the region is closed.
- void emitTargetDataCalls(CodeGenFunction &CGF,
- const OMPExecutableDirective &D, const Expr *IfCond,
- const Expr *Device, const RegionCodeGenTy &CodeGen,
- TargetDataInfo &Info) override;
-
- /// Emit the data mapping/movement code associated with the directive
- /// \a D that should be of the form 'target [{enter|exit} data | update]'.
- /// \param D Directive to emit.
- /// \param IfCond Expression evaluated in if clause associated with the target
- /// directive, or null if no if clause is used.
- /// \param Device Expression evaluated in device clause associated with the
- /// target directive, or null if no device clause is used.
- void emitTargetDataStandAloneCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- const Expr *IfCond,
- const Expr *Device) override;
-
- /// Emit initialization for doacross loop nesting support.
- /// \param D Loop-based construct used in doacross nesting construct.
- void emitDoacrossInit(CodeGenFunction &CGF, const OMPLoopDirective &D,
- ArrayRef<Expr *> NumIterations) override;
-
- /// Emit code for doacross ordered directive with 'depend' clause.
- /// \param C 'depend' clause with 'sink|source' dependency kind.
- void emitDoacrossOrdered(CodeGenFunction &CGF,
- const OMPDependClause *C) override;
-
- /// Translates the native parameter of outlined function if this is required
- /// for target.
- /// \param FD Field decl from captured record for the parameter.
- /// \param NativeParam Parameter itself.
- const VarDecl *translateParameter(const FieldDecl *FD,
- const VarDecl *NativeParam) const override;
-
- /// Gets the address of the native argument basing on the address of the
- /// target-specific parameter.
- /// \param NativeParam Parameter itself.
- /// \param TargetParam Corresponding target-specific parameter.
- Address getParameterAddress(CodeGenFunction &CGF, const VarDecl *NativeParam,
- const VarDecl *TargetParam) const override;
-};
-
-} // namespace CodeGen
-} // namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
deleted file mode 100644
index 7046ab3aa35..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
+++ /dev/null
@@ -1,4604 +0,0 @@
-//===---- CGOpenMPRuntimeNVPTX.cpp - Interface to OpenMP NVPTX Runtimes ---===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides a class for OpenMP runtime code generation specialized to NVPTX
-// targets.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGOpenMPRuntimeNVPTX.h"
-#include "CodeGenFunction.h"
-#include "clang/AST/DeclOpenMP.h"
-#include "clang/AST/StmtOpenMP.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/Cuda.h"
-#include "llvm/ADT/SmallPtrSet.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-enum OpenMPRTLFunctionNVPTX {
- /// Call to void __kmpc_kernel_init(kmp_int32 thread_limit,
- /// int16_t RequiresOMPRuntime);
- OMPRTL_NVPTX__kmpc_kernel_init,
- /// Call to void __kmpc_kernel_deinit(int16_t IsOMPRuntimeInitialized);
- OMPRTL_NVPTX__kmpc_kernel_deinit,
- /// Call to void __kmpc_spmd_kernel_init(kmp_int32 thread_limit,
- /// int16_t RequiresOMPRuntime, int16_t RequiresDataSharing);
- OMPRTL_NVPTX__kmpc_spmd_kernel_init,
- /// Call to void __kmpc_spmd_kernel_deinit_v2(int16_t RequiresOMPRuntime);
- OMPRTL_NVPTX__kmpc_spmd_kernel_deinit_v2,
- /// Call to void __kmpc_kernel_prepare_parallel(void
- /// *outlined_function, int16_t
- /// IsOMPRuntimeInitialized);
- OMPRTL_NVPTX__kmpc_kernel_prepare_parallel,
- /// Call to bool __kmpc_kernel_parallel(void **outlined_function,
- /// int16_t IsOMPRuntimeInitialized);
- OMPRTL_NVPTX__kmpc_kernel_parallel,
- /// Call to void __kmpc_kernel_end_parallel();
- OMPRTL_NVPTX__kmpc_kernel_end_parallel,
- /// Call to void __kmpc_serialized_parallel(ident_t *loc, kmp_int32
- /// global_tid);
- OMPRTL_NVPTX__kmpc_serialized_parallel,
- /// Call to void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32
- /// global_tid);
- OMPRTL_NVPTX__kmpc_end_serialized_parallel,
- /// Call to int32_t __kmpc_shuffle_int32(int32_t element,
- /// int16_t lane_offset, int16_t warp_size);
- OMPRTL_NVPTX__kmpc_shuffle_int32,
- /// Call to int64_t __kmpc_shuffle_int64(int64_t element,
- /// int16_t lane_offset, int16_t warp_size);
- OMPRTL_NVPTX__kmpc_shuffle_int64,
- /// Call to __kmpc_nvptx_parallel_reduce_nowait_v2(ident_t *loc, kmp_int32
- /// global_tid, kmp_int32 num_vars, size_t reduce_size, void* reduce_data,
- /// void (*kmp_ShuffleReductFctPtr)(void *rhsData, int16_t lane_id, int16_t
- /// lane_offset, int16_t shortCircuit),
- /// void (*kmp_InterWarpCopyFctPtr)(void* src, int32_t warp_num));
- OMPRTL_NVPTX__kmpc_parallel_reduce_nowait_v2,
- /// Call to __kmpc_nvptx_teams_reduce_nowait_simple(ident_t *loc, kmp_int32
- /// global_tid, kmp_critical_name *lck)
- OMPRTL_NVPTX__kmpc_nvptx_teams_reduce_nowait_simple,
- /// Call to __kmpc_nvptx_teams_end_reduce_nowait_simple(ident_t *loc,
- /// kmp_int32 global_tid, kmp_critical_name *lck)
- OMPRTL_NVPTX__kmpc_nvptx_teams_end_reduce_nowait_simple,
- /// Call to __kmpc_nvptx_end_reduce_nowait(int32_t global_tid);
- OMPRTL_NVPTX__kmpc_end_reduce_nowait,
- /// Call to void __kmpc_data_sharing_init_stack();
- OMPRTL_NVPTX__kmpc_data_sharing_init_stack,
- /// Call to void __kmpc_data_sharing_init_stack_spmd();
- OMPRTL_NVPTX__kmpc_data_sharing_init_stack_spmd,
- /// Call to void* __kmpc_data_sharing_coalesced_push_stack(size_t size,
- /// int16_t UseSharedMemory);
- OMPRTL_NVPTX__kmpc_data_sharing_coalesced_push_stack,
- /// Call to void __kmpc_data_sharing_pop_stack(void *a);
- OMPRTL_NVPTX__kmpc_data_sharing_pop_stack,
- /// Call to void __kmpc_begin_sharing_variables(void ***args,
- /// size_t n_args);
- OMPRTL_NVPTX__kmpc_begin_sharing_variables,
- /// Call to void __kmpc_end_sharing_variables();
- OMPRTL_NVPTX__kmpc_end_sharing_variables,
- /// Call to void __kmpc_get_shared_variables(void ***GlobalArgs)
- OMPRTL_NVPTX__kmpc_get_shared_variables,
- /// Call to uint16_t __kmpc_parallel_level(ident_t *loc, kmp_int32
- /// global_tid);
- OMPRTL_NVPTX__kmpc_parallel_level,
- /// Call to int8_t __kmpc_is_spmd_exec_mode();
- OMPRTL_NVPTX__kmpc_is_spmd_exec_mode,
- /// Call to void __kmpc_get_team_static_memory(int16_t isSPMDExecutionMode,
- /// const void *buf, size_t size, int16_t is_shared, const void **res);
- OMPRTL_NVPTX__kmpc_get_team_static_memory,
- /// Call to void __kmpc_restore_team_static_memory(int16_t
- /// isSPMDExecutionMode, int16_t is_shared);
- OMPRTL_NVPTX__kmpc_restore_team_static_memory,
- /// Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
- OMPRTL__kmpc_barrier,
- /// Call to void __kmpc_barrier_simple_spmd(ident_t *loc, kmp_int32
- /// global_tid);
- OMPRTL__kmpc_barrier_simple_spmd,
-};
-
-/// Pre(post)-action for different OpenMP constructs specialized for NVPTX.
-class NVPTXActionTy final : public PrePostActionTy {
- llvm::Value *EnterCallee = nullptr;
- ArrayRef<llvm::Value *> EnterArgs;
- llvm::Value *ExitCallee = nullptr;
- ArrayRef<llvm::Value *> ExitArgs;
- bool Conditional = false;
- llvm::BasicBlock *ContBlock = nullptr;
-
-public:
- NVPTXActionTy(llvm::Value *EnterCallee, ArrayRef<llvm::Value *> EnterArgs,
- llvm::Value *ExitCallee, ArrayRef<llvm::Value *> ExitArgs,
- bool Conditional = false)
- : EnterCallee(EnterCallee), EnterArgs(EnterArgs), ExitCallee(ExitCallee),
- ExitArgs(ExitArgs), Conditional(Conditional) {}
- void Enter(CodeGenFunction &CGF) override {
- llvm::Value *EnterRes = CGF.EmitRuntimeCall(EnterCallee, EnterArgs);
- if (Conditional) {
- llvm::Value *CallBool = CGF.Builder.CreateIsNotNull(EnterRes);
- auto *ThenBlock = CGF.createBasicBlock("omp_if.then");
- ContBlock = CGF.createBasicBlock("omp_if.end");
- // Generate the branch (If-stmt)
- CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
- CGF.EmitBlock(ThenBlock);
- }
- }
- void Done(CodeGenFunction &CGF) {
- // Emit the rest of blocks/branches
- CGF.EmitBranch(ContBlock);
- CGF.EmitBlock(ContBlock, true);
- }
- void Exit(CodeGenFunction &CGF) override {
- CGF.EmitRuntimeCall(ExitCallee, ExitArgs);
- }
-};
-
-/// A class to track the execution mode when codegening directives within
-/// a target region. The appropriate mode (SPMD|NON-SPMD) is set on entry
-/// to the target region and used by containing directives such as 'parallel'
-/// to emit optimized code.
-class ExecutionRuntimeModesRAII {
-private:
- CGOpenMPRuntimeNVPTX::ExecutionMode SavedExecMode =
- CGOpenMPRuntimeNVPTX::EM_Unknown;
- CGOpenMPRuntimeNVPTX::ExecutionMode &ExecMode;
- bool SavedRuntimeMode = false;
- bool *RuntimeMode = nullptr;
-
-public:
- /// Constructor for Non-SPMD mode.
- ExecutionRuntimeModesRAII(CGOpenMPRuntimeNVPTX::ExecutionMode &ExecMode)
- : ExecMode(ExecMode) {
- SavedExecMode = ExecMode;
- ExecMode = CGOpenMPRuntimeNVPTX::EM_NonSPMD;
- }
- /// Constructor for SPMD mode.
- ExecutionRuntimeModesRAII(CGOpenMPRuntimeNVPTX::ExecutionMode &ExecMode,
- bool &RuntimeMode, bool FullRuntimeMode)
- : ExecMode(ExecMode), RuntimeMode(&RuntimeMode) {
- SavedExecMode = ExecMode;
- SavedRuntimeMode = RuntimeMode;
- ExecMode = CGOpenMPRuntimeNVPTX::EM_SPMD;
- RuntimeMode = FullRuntimeMode;
- }
- ~ExecutionRuntimeModesRAII() {
- ExecMode = SavedExecMode;
- if (RuntimeMode)
- *RuntimeMode = SavedRuntimeMode;
- }
-};
-
-/// GPU Configuration: This information can be derived from cuda registers,
-/// however, providing compile time constants helps generate more efficient
-/// code. For all practical purposes this is fine because the configuration
-/// is the same for all known NVPTX architectures.
-enum MachineConfiguration : unsigned {
- WarpSize = 32,
- /// Number of bits required to represent a lane identifier, which is
- /// computed as log_2(WarpSize).
- LaneIDBits = 5,
- LaneIDMask = WarpSize - 1,
-
- /// Global memory alignment for performance.
- GlobalMemoryAlignment = 128,
-
- /// Maximal size of the shared memory buffer.
- SharedMemorySize = 128,
-};
-
-static const ValueDecl *getPrivateItem(const Expr *RefExpr) {
- RefExpr = RefExpr->IgnoreParens();
- if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr)) {
- const Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
- while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- RefExpr = Base;
- } else if (auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr)) {
- const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
- while (const auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
- Base = TempOASE->getBase()->IgnoreParenImpCasts();
- while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- RefExpr = Base;
- }
- RefExpr = RefExpr->IgnoreParenImpCasts();
- if (const auto *DE = dyn_cast<DeclRefExpr>(RefExpr))
- return cast<ValueDecl>(DE->getDecl()->getCanonicalDecl());
- const auto *ME = cast<MemberExpr>(RefExpr);
- return cast<ValueDecl>(ME->getMemberDecl()->getCanonicalDecl());
-}
-
-typedef std::pair<CharUnits /*Align*/, const ValueDecl *> VarsDataTy;
-static bool stable_sort_comparator(const VarsDataTy P1, const VarsDataTy P2) {
- return P1.first > P2.first;
-}
-
-static RecordDecl *buildRecordForGlobalizedVars(
- ASTContext &C, ArrayRef<const ValueDecl *> EscapedDecls,
- ArrayRef<const ValueDecl *> EscapedDeclsForTeams,
- llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *>
- &MappedDeclsFields) {
- if (EscapedDecls.empty() && EscapedDeclsForTeams.empty())
- return nullptr;
- SmallVector<VarsDataTy, 4> GlobalizedVars;
- for (const ValueDecl *D : EscapedDecls)
- GlobalizedVars.emplace_back(
- CharUnits::fromQuantity(std::max(
- C.getDeclAlign(D).getQuantity(),
- static_cast<CharUnits::QuantityType>(GlobalMemoryAlignment))),
- D);
- for (const ValueDecl *D : EscapedDeclsForTeams)
- GlobalizedVars.emplace_back(C.getDeclAlign(D), D);
- std::stable_sort(GlobalizedVars.begin(), GlobalizedVars.end(),
- stable_sort_comparator);
- // Build struct _globalized_locals_ty {
- // /* globalized vars */[WarSize] align (max(decl_align,
- // GlobalMemoryAlignment))
- // /* globalized vars */ for EscapedDeclsForTeams
- // };
- RecordDecl *GlobalizedRD = C.buildImplicitRecord("_globalized_locals_ty");
- GlobalizedRD->startDefinition();
- llvm::SmallPtrSet<const ValueDecl *, 16> SingleEscaped(
- EscapedDeclsForTeams.begin(), EscapedDeclsForTeams.end());
- for (const auto &Pair : GlobalizedVars) {
- const ValueDecl *VD = Pair.second;
- QualType Type = VD->getType();
- if (Type->isLValueReferenceType())
- Type = C.getPointerType(Type.getNonReferenceType());
- else
- Type = Type.getNonReferenceType();
- SourceLocation Loc = VD->getLocation();
- FieldDecl *Field;
- if (SingleEscaped.count(VD)) {
- Field = FieldDecl::Create(
- C, GlobalizedRD, Loc, Loc, VD->getIdentifier(), Type,
- C.getTrivialTypeSourceInfo(Type, SourceLocation()),
- /*BW=*/nullptr, /*Mutable=*/false,
- /*InitStyle=*/ICIS_NoInit);
- Field->setAccess(AS_public);
- if (VD->hasAttrs()) {
- for (specific_attr_iterator<AlignedAttr> I(VD->getAttrs().begin()),
- E(VD->getAttrs().end());
- I != E; ++I)
- Field->addAttr(*I);
- }
- } else {
- llvm::APInt ArraySize(32, WarpSize);
- Type = C.getConstantArrayType(Type, ArraySize, ArrayType::Normal, 0);
- Field = FieldDecl::Create(
- C, GlobalizedRD, Loc, Loc, VD->getIdentifier(), Type,
- C.getTrivialTypeSourceInfo(Type, SourceLocation()),
- /*BW=*/nullptr, /*Mutable=*/false,
- /*InitStyle=*/ICIS_NoInit);
- Field->setAccess(AS_public);
- llvm::APInt Align(32, std::max(C.getDeclAlign(VD).getQuantity(),
- static_cast<CharUnits::QuantityType>(
- GlobalMemoryAlignment)));
- Field->addAttr(AlignedAttr::CreateImplicit(
- C, AlignedAttr::GNU_aligned, /*IsAlignmentExpr=*/true,
- IntegerLiteral::Create(C, Align,
- C.getIntTypeForBitwidth(32, /*Signed=*/0),
- SourceLocation())));
- }
- GlobalizedRD->addDecl(Field);
- MappedDeclsFields.try_emplace(VD, Field);
- }
- GlobalizedRD->completeDefinition();
- return GlobalizedRD;
-}
-
-/// Get the list of variables that can escape their declaration context.
-class CheckVarsEscapingDeclContext final
- : public ConstStmtVisitor<CheckVarsEscapingDeclContext> {
- CodeGenFunction &CGF;
- llvm::SetVector<const ValueDecl *> EscapedDecls;
- llvm::SetVector<const ValueDecl *> EscapedVariableLengthDecls;
- llvm::SmallPtrSet<const Decl *, 4> EscapedParameters;
- RecordDecl *GlobalizedRD = nullptr;
- llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *> MappedDeclsFields;
- bool AllEscaped = false;
- bool IsForCombinedParallelRegion = false;
-
- void markAsEscaped(const ValueDecl *VD) {
- // Do not globalize declare target variables.
- if (!isa<VarDecl>(VD) ||
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
- return;
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- // Variables captured by value must be globalized.
- if (auto *CSI = CGF.CapturedStmtInfo) {
- if (const FieldDecl *FD = CSI->lookup(cast<VarDecl>(VD))) {
- // Check if need to capture the variable that was already captured by
- // value in the outer region.
- if (!IsForCombinedParallelRegion) {
- if (!FD->hasAttrs())
- return;
- const auto *Attr = FD->getAttr<OMPCaptureKindAttr>();
- if (!Attr)
- return;
- if (((Attr->getCaptureKind() != OMPC_map) &&
- !isOpenMPPrivate(
- static_cast<OpenMPClauseKind>(Attr->getCaptureKind()))) ||
- ((Attr->getCaptureKind() == OMPC_map) &&
- !FD->getType()->isAnyPointerType()))
- return;
- }
- if (!FD->getType()->isReferenceType()) {
- assert(!VD->getType()->isVariablyModifiedType() &&
- "Parameter captured by value with variably modified type");
- EscapedParameters.insert(VD);
- } else if (!IsForCombinedParallelRegion) {
- return;
- }
- }
- }
- if ((!CGF.CapturedStmtInfo ||
- (IsForCombinedParallelRegion && CGF.CapturedStmtInfo)) &&
- VD->getType()->isReferenceType())
- // Do not globalize variables with reference type.
- return;
- if (VD->getType()->isVariablyModifiedType())
- EscapedVariableLengthDecls.insert(VD);
- else
- EscapedDecls.insert(VD);
- }
-
- void VisitValueDecl(const ValueDecl *VD) {
- if (VD->getType()->isLValueReferenceType())
- markAsEscaped(VD);
- if (const auto *VarD = dyn_cast<VarDecl>(VD)) {
- if (!isa<ParmVarDecl>(VarD) && VarD->hasInit()) {
- const bool SavedAllEscaped = AllEscaped;
- AllEscaped = VD->getType()->isLValueReferenceType();
- Visit(VarD->getInit());
- AllEscaped = SavedAllEscaped;
- }
- }
- }
- void VisitOpenMPCapturedStmt(const CapturedStmt *S,
- ArrayRef<OMPClause *> Clauses,
- bool IsCombinedParallelRegion) {
- if (!S)
- return;
- for (const CapturedStmt::Capture &C : S->captures()) {
- if (C.capturesVariable() && !C.capturesVariableByCopy()) {
- const ValueDecl *VD = C.getCapturedVar();
- bool SavedIsForCombinedParallelRegion = IsForCombinedParallelRegion;
- if (IsCombinedParallelRegion) {
- // Check if the variable is privatized in the combined construct and
- // those private copies must be shared in the inner parallel
- // directive.
- IsForCombinedParallelRegion = false;
- for (const OMPClause *C : Clauses) {
- if (!isOpenMPPrivate(C->getClauseKind()) ||
- C->getClauseKind() == OMPC_reduction ||
- C->getClauseKind() == OMPC_linear ||
- C->getClauseKind() == OMPC_private)
- continue;
- ArrayRef<const Expr *> Vars;
- if (const auto *PC = dyn_cast<OMPFirstprivateClause>(C))
- Vars = PC->getVarRefs();
- else if (const auto *PC = dyn_cast<OMPLastprivateClause>(C))
- Vars = PC->getVarRefs();
- else
- llvm_unreachable("Unexpected clause.");
- for (const auto *E : Vars) {
- const Decl *D =
- cast<DeclRefExpr>(E)->getDecl()->getCanonicalDecl();
- if (D == VD->getCanonicalDecl()) {
- IsForCombinedParallelRegion = true;
- break;
- }
- }
- if (IsForCombinedParallelRegion)
- break;
- }
- }
- markAsEscaped(VD);
- if (isa<OMPCapturedExprDecl>(VD))
- VisitValueDecl(VD);
- IsForCombinedParallelRegion = SavedIsForCombinedParallelRegion;
- }
- }
- }
-
- void buildRecordForGlobalizedVars(bool IsInTTDRegion) {
- assert(!GlobalizedRD &&
- "Record for globalized variables is built already.");
- ArrayRef<const ValueDecl *> EscapedDeclsForParallel, EscapedDeclsForTeams;
- if (IsInTTDRegion)
- EscapedDeclsForTeams = EscapedDecls.getArrayRef();
- else
- EscapedDeclsForParallel = EscapedDecls.getArrayRef();
- GlobalizedRD = ::buildRecordForGlobalizedVars(
- CGF.getContext(), EscapedDeclsForParallel, EscapedDeclsForTeams,
- MappedDeclsFields);
- }
-
-public:
- CheckVarsEscapingDeclContext(CodeGenFunction &CGF,
- ArrayRef<const ValueDecl *> TeamsReductions)
- : CGF(CGF), EscapedDecls(TeamsReductions.begin(), TeamsReductions.end()) {
- }
- virtual ~CheckVarsEscapingDeclContext() = default;
- void VisitDeclStmt(const DeclStmt *S) {
- if (!S)
- return;
- for (const Decl *D : S->decls())
- if (const auto *VD = dyn_cast_or_null<ValueDecl>(D))
- VisitValueDecl(VD);
- }
- void VisitOMPExecutableDirective(const OMPExecutableDirective *D) {
- if (!D)
- return;
- if (!D->hasAssociatedStmt())
- return;
- if (const auto *S =
- dyn_cast_or_null<CapturedStmt>(D->getAssociatedStmt())) {
- // Do not analyze directives that do not actually require capturing,
- // like `omp for` or `omp simd` directives.
- llvm::SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
- getOpenMPCaptureRegions(CaptureRegions, D->getDirectiveKind());
- if (CaptureRegions.size() == 1 && CaptureRegions.back() == OMPD_unknown) {
- VisitStmt(S->getCapturedStmt());
- return;
- }
- VisitOpenMPCapturedStmt(
- S, D->clauses(),
- CaptureRegions.back() == OMPD_parallel &&
- isOpenMPDistributeDirective(D->getDirectiveKind()));
- }
- }
- void VisitCapturedStmt(const CapturedStmt *S) {
- if (!S)
- return;
- for (const CapturedStmt::Capture &C : S->captures()) {
- if (C.capturesVariable() && !C.capturesVariableByCopy()) {
- const ValueDecl *VD = C.getCapturedVar();
- markAsEscaped(VD);
- if (isa<OMPCapturedExprDecl>(VD))
- VisitValueDecl(VD);
- }
- }
- }
- void VisitLambdaExpr(const LambdaExpr *E) {
- if (!E)
- return;
- for (const LambdaCapture &C : E->captures()) {
- if (C.capturesVariable()) {
- if (C.getCaptureKind() == LCK_ByRef) {
- const ValueDecl *VD = C.getCapturedVar();
- markAsEscaped(VD);
- if (E->isInitCapture(&C) || isa<OMPCapturedExprDecl>(VD))
- VisitValueDecl(VD);
- }
- }
- }
- }
- void VisitBlockExpr(const BlockExpr *E) {
- if (!E)
- return;
- for (const BlockDecl::Capture &C : E->getBlockDecl()->captures()) {
- if (C.isByRef()) {
- const VarDecl *VD = C.getVariable();
- markAsEscaped(VD);
- if (isa<OMPCapturedExprDecl>(VD) || VD->isInitCapture())
- VisitValueDecl(VD);
- }
- }
- }
- void VisitCallExpr(const CallExpr *E) {
- if (!E)
- return;
- for (const Expr *Arg : E->arguments()) {
- if (!Arg)
- continue;
- if (Arg->isLValue()) {
- const bool SavedAllEscaped = AllEscaped;
- AllEscaped = true;
- Visit(Arg);
- AllEscaped = SavedAllEscaped;
- } else {
- Visit(Arg);
- }
- }
- Visit(E->getCallee());
- }
- void VisitDeclRefExpr(const DeclRefExpr *E) {
- if (!E)
- return;
- const ValueDecl *VD = E->getDecl();
- if (AllEscaped)
- markAsEscaped(VD);
- if (isa<OMPCapturedExprDecl>(VD))
- VisitValueDecl(VD);
- else if (const auto *VarD = dyn_cast<VarDecl>(VD))
- if (VarD->isInitCapture())
- VisitValueDecl(VD);
- }
- void VisitUnaryOperator(const UnaryOperator *E) {
- if (!E)
- return;
- if (E->getOpcode() == UO_AddrOf) {
- const bool SavedAllEscaped = AllEscaped;
- AllEscaped = true;
- Visit(E->getSubExpr());
- AllEscaped = SavedAllEscaped;
- } else {
- Visit(E->getSubExpr());
- }
- }
- void VisitImplicitCastExpr(const ImplicitCastExpr *E) {
- if (!E)
- return;
- if (E->getCastKind() == CK_ArrayToPointerDecay) {
- const bool SavedAllEscaped = AllEscaped;
- AllEscaped = true;
- Visit(E->getSubExpr());
- AllEscaped = SavedAllEscaped;
- } else {
- Visit(E->getSubExpr());
- }
- }
- void VisitExpr(const Expr *E) {
- if (!E)
- return;
- bool SavedAllEscaped = AllEscaped;
- if (!E->isLValue())
- AllEscaped = false;
- for (const Stmt *Child : E->children())
- if (Child)
- Visit(Child);
- AllEscaped = SavedAllEscaped;
- }
- void VisitStmt(const Stmt *S) {
- if (!S)
- return;
- for (const Stmt *Child : S->children())
- if (Child)
- Visit(Child);
- }
-
- /// Returns the record that handles all the escaped local variables and used
- /// instead of their original storage.
- const RecordDecl *getGlobalizedRecord(bool IsInTTDRegion) {
- if (!GlobalizedRD)
- buildRecordForGlobalizedVars(IsInTTDRegion);
- return GlobalizedRD;
- }
-
- /// Returns the field in the globalized record for the escaped variable.
- const FieldDecl *getFieldForGlobalizedVar(const ValueDecl *VD) const {
- assert(GlobalizedRD &&
- "Record for globalized variables must be generated already.");
- auto I = MappedDeclsFields.find(VD);
- if (I == MappedDeclsFields.end())
- return nullptr;
- return I->getSecond();
- }
-
- /// Returns the list of the escaped local variables/parameters.
- ArrayRef<const ValueDecl *> getEscapedDecls() const {
- return EscapedDecls.getArrayRef();
- }
-
- /// Checks if the escaped local variable is actually a parameter passed by
- /// value.
- const llvm::SmallPtrSetImpl<const Decl *> &getEscapedParameters() const {
- return EscapedParameters;
- }
-
- /// Returns the list of the escaped variables with the variably modified
- /// types.
- ArrayRef<const ValueDecl *> getEscapedVariableLengthDecls() const {
- return EscapedVariableLengthDecls.getArrayRef();
- }
-};
-} // anonymous namespace
-
-/// Get the GPU warp size.
-static llvm::Value *getNVPTXWarpSize(CodeGenFunction &CGF) {
- return CGF.EmitRuntimeCall(
- llvm::Intrinsic::getDeclaration(
- &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_warpsize),
- "nvptx_warp_size");
-}
-
-/// Get the id of the current thread on the GPU.
-static llvm::Value *getNVPTXThreadID(CodeGenFunction &CGF) {
- return CGF.EmitRuntimeCall(
- llvm::Intrinsic::getDeclaration(
- &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_tid_x),
- "nvptx_tid");
-}
-
-/// Get the id of the warp in the block.
-/// We assume that the warp size is 32, which is always the case
-/// on the NVPTX device, to generate more efficient code.
-static llvm::Value *getNVPTXWarpID(CodeGenFunction &CGF) {
- CGBuilderTy &Bld = CGF.Builder;
- return Bld.CreateAShr(getNVPTXThreadID(CGF), LaneIDBits, "nvptx_warp_id");
-}
-
-/// Get the id of the current lane in the Warp.
-/// We assume that the warp size is 32, which is always the case
-/// on the NVPTX device, to generate more efficient code.
-static llvm::Value *getNVPTXLaneID(CodeGenFunction &CGF) {
- CGBuilderTy &Bld = CGF.Builder;
- return Bld.CreateAnd(getNVPTXThreadID(CGF), Bld.getInt32(LaneIDMask),
- "nvptx_lane_id");
-}
-
-/// Get the maximum number of threads in a block of the GPU.
-static llvm::Value *getNVPTXNumThreads(CodeGenFunction &CGF) {
- return CGF.EmitRuntimeCall(
- llvm::Intrinsic::getDeclaration(
- &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_ntid_x),
- "nvptx_num_threads");
-}
-
-/// Get the value of the thread_limit clause in the teams directive.
-/// For the 'generic' execution mode, the runtime encodes thread_limit in
-/// the launch parameters, always starting thread_limit+warpSize threads per
-/// CTA. The threads in the last warp are reserved for master execution.
-/// For the 'spmd' execution mode, all threads in a CTA are part of the team.
-static llvm::Value *getThreadLimit(CodeGenFunction &CGF,
- bool IsInSPMDExecutionMode = false) {
- CGBuilderTy &Bld = CGF.Builder;
- return IsInSPMDExecutionMode
- ? getNVPTXNumThreads(CGF)
- : Bld.CreateNUWSub(getNVPTXNumThreads(CGF), getNVPTXWarpSize(CGF),
- "thread_limit");
-}
-
-/// Get the thread id of the OMP master thread.
-/// The master thread id is the first thread (lane) of the last warp in the
-/// GPU block. Warp size is assumed to be some power of 2.
-/// Thread id is 0 indexed.
-/// E.g: If NumThreads is 33, master id is 32.
-/// If NumThreads is 64, master id is 32.
-/// If NumThreads is 1024, master id is 992.
-static llvm::Value *getMasterThreadID(CodeGenFunction &CGF) {
- CGBuilderTy &Bld = CGF.Builder;
- llvm::Value *NumThreads = getNVPTXNumThreads(CGF);
-
- // We assume that the warp size is a power of 2.
- llvm::Value *Mask = Bld.CreateNUWSub(getNVPTXWarpSize(CGF), Bld.getInt32(1));
-
- return Bld.CreateAnd(Bld.CreateNUWSub(NumThreads, Bld.getInt32(1)),
- Bld.CreateNot(Mask), "master_tid");
-}
-
-CGOpenMPRuntimeNVPTX::WorkerFunctionState::WorkerFunctionState(
- CodeGenModule &CGM, SourceLocation Loc)
- : WorkerFn(nullptr), CGFI(CGM.getTypes().arrangeNullaryFunction()),
- Loc(Loc) {
- createWorkerFunction(CGM);
-}
-
-void CGOpenMPRuntimeNVPTX::WorkerFunctionState::createWorkerFunction(
- CodeGenModule &CGM) {
- // Create an worker function with no arguments.
-
- WorkerFn = llvm::Function::Create(
- CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
- /*placeholder=*/"_worker", &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), WorkerFn, CGFI);
- WorkerFn->setDoesNotRecurse();
-}
-
-CGOpenMPRuntimeNVPTX::ExecutionMode
-CGOpenMPRuntimeNVPTX::getExecutionMode() const {
- return CurrentExecutionMode;
-}
-
-static CGOpenMPRuntimeNVPTX::DataSharingMode
-getDataSharingMode(CodeGenModule &CGM) {
- return CGM.getLangOpts().OpenMPCUDAMode ? CGOpenMPRuntimeNVPTX::CUDA
- : CGOpenMPRuntimeNVPTX::Generic;
-}
-
-/// Checks if the expression is constant or does not have non-trivial function
-/// calls.
-static bool isTrivial(ASTContext &Ctx, const Expr * E) {
- // We can skip constant expressions.
- // We can skip expressions with trivial calls or simple expressions.
- return (E->isEvaluatable(Ctx, Expr::SE_AllowUndefinedBehavior) ||
- !E->hasNonTrivialCall(Ctx)) &&
- !E->HasSideEffects(Ctx, /*IncludePossibleEffects=*/true);
-}
-
-/// Checks if the \p Body is the \a CompoundStmt and returns its child statement
-/// iff there is only one that is not evaluatable at the compile time.
-static const Stmt *getSingleCompoundChild(ASTContext &Ctx, const Stmt *Body) {
- if (const auto *C = dyn_cast<CompoundStmt>(Body)) {
- const Stmt *Child = nullptr;
- for (const Stmt *S : C->body()) {
- if (const auto *E = dyn_cast<Expr>(S)) {
- if (isTrivial(Ctx, E))
- continue;
- }
- // Some of the statements can be ignored.
- if (isa<AsmStmt>(S) || isa<NullStmt>(S) || isa<OMPFlushDirective>(S) ||
- isa<OMPBarrierDirective>(S) || isa<OMPTaskyieldDirective>(S))
- continue;
- // Analyze declarations.
- if (const auto *DS = dyn_cast<DeclStmt>(S)) {
- if (llvm::all_of(DS->decls(), [&Ctx](const Decl *D) {
- if (isa<EmptyDecl>(D) || isa<DeclContext>(D) ||
- isa<TypeDecl>(D) || isa<PragmaCommentDecl>(D) ||
- isa<PragmaDetectMismatchDecl>(D) || isa<UsingDecl>(D) ||
- isa<UsingDirectiveDecl>(D) ||
- isa<OMPDeclareReductionDecl>(D) ||
- isa<OMPThreadPrivateDecl>(D))
- return true;
- const auto *VD = dyn_cast<VarDecl>(D);
- if (!VD)
- return false;
- return VD->isConstexpr() ||
- ((VD->getType().isTrivialType(Ctx) ||
- VD->getType()->isReferenceType()) &&
- (!VD->hasInit() || isTrivial(Ctx, VD->getInit())));
- }))
- continue;
- }
- // Found multiple children - cannot get the one child only.
- if (Child)
- return Body;
- Child = S;
- }
- if (Child)
- return Child;
- }
- return Body;
-}
-
-/// Check if the parallel directive has an 'if' clause with non-constant or
-/// false condition. Also, check if the number of threads is strictly specified
-/// and run those directives in non-SPMD mode.
-static bool hasParallelIfNumThreadsClause(ASTContext &Ctx,
- const OMPExecutableDirective &D) {
- if (D.hasClausesOfKind<OMPNumThreadsClause>())
- return true;
- for (const auto *C : D.getClausesOfKind<OMPIfClause>()) {
- OpenMPDirectiveKind NameModifier = C->getNameModifier();
- if (NameModifier != OMPD_parallel && NameModifier != OMPD_unknown)
- continue;
- const Expr *Cond = C->getCondition();
- bool Result;
- if (!Cond->EvaluateAsBooleanCondition(Result, Ctx) || !Result)
- return true;
- }
- return false;
-}
-
-/// Check for inner (nested) SPMD construct, if any
-static bool hasNestedSPMDDirective(ASTContext &Ctx,
- const OMPExecutableDirective &D) {
- const auto *CS = D.getInnermostCapturedStmt();
- const auto *Body =
- CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
- const Stmt *ChildStmt = getSingleCompoundChild(Ctx, Body);
-
- if (const auto *NestedDir = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
- switch (D.getDirectiveKind()) {
- case OMPD_target:
- if (isOpenMPParallelDirective(DKind) &&
- !hasParallelIfNumThreadsClause(Ctx, *NestedDir))
- return true;
- if (DKind == OMPD_teams) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = getSingleCompoundChild(Ctx, Body);
- if (const auto *NND = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPParallelDirective(DKind) &&
- !hasParallelIfNumThreadsClause(Ctx, *NND))
- return true;
- }
- }
- return false;
- case OMPD_target_teams:
- return isOpenMPParallelDirective(DKind) &&
- !hasParallelIfNumThreadsClause(Ctx, *NestedDir);
- case OMPD_target_simd:
- case OMPD_target_parallel:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
- case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_target:
- case OMPD_end_declare_target:
- case OMPD_declare_reduction:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- llvm_unreachable("Unexpected directive.");
- }
- }
-
- return false;
-}
-
-static bool supportsSPMDExecutionMode(ASTContext &Ctx,
- const OMPExecutableDirective &D) {
- OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
- switch (DirectiveKind) {
- case OMPD_target:
- case OMPD_target_teams:
- return hasNestedSPMDDirective(Ctx, D);
- case OMPD_target_parallel:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- return !hasParallelIfNumThreadsClause(Ctx, D);
- case OMPD_target_simd:
- case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
- return false;
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_target:
- case OMPD_end_declare_target:
- case OMPD_declare_reduction:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- break;
- }
- llvm_unreachable(
- "Unknown programming model for OpenMP directive on NVPTX target.");
-}
-
-/// Check if the directive is loops based and has schedule clause at all or has
-/// static scheduling.
-static bool hasStaticScheduling(const OMPExecutableDirective &D) {
- assert(isOpenMPWorksharingDirective(D.getDirectiveKind()) &&
- isOpenMPLoopDirective(D.getDirectiveKind()) &&
- "Expected loop-based directive.");
- return !D.hasClausesOfKind<OMPOrderedClause>() &&
- (!D.hasClausesOfKind<OMPScheduleClause>() ||
- llvm::any_of(D.getClausesOfKind<OMPScheduleClause>(),
- [](const OMPScheduleClause *C) {
- return C->getScheduleKind() == OMPC_SCHEDULE_static;
- }));
-}
-
-/// Check for inner (nested) lightweight runtime construct, if any
-static bool hasNestedLightweightDirective(ASTContext &Ctx,
- const OMPExecutableDirective &D) {
- assert(supportsSPMDExecutionMode(Ctx, D) && "Expected SPMD mode directive.");
- const auto *CS = D.getInnermostCapturedStmt();
- const auto *Body =
- CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
- const Stmt *ChildStmt = getSingleCompoundChild(Ctx, Body);
-
- if (const auto *NestedDir = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
- switch (D.getDirectiveKind()) {
- case OMPD_target:
- if (isOpenMPParallelDirective(DKind) &&
- isOpenMPWorksharingDirective(DKind) && isOpenMPLoopDirective(DKind) &&
- hasStaticScheduling(*NestedDir))
- return true;
- if (DKind == OMPD_parallel) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = getSingleCompoundChild(Ctx, Body);
- if (const auto *NND = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- }
- } else if (DKind == OMPD_teams) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = getSingleCompoundChild(Ctx, Body);
- if (const auto *NND = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPParallelDirective(DKind) &&
- isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- if (DKind == OMPD_parallel) {
- Body = NND->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = getSingleCompoundChild(Ctx, Body);
- if (const auto *NND = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- }
- }
- }
- }
- return false;
- case OMPD_target_teams:
- if (isOpenMPParallelDirective(DKind) &&
- isOpenMPWorksharingDirective(DKind) && isOpenMPLoopDirective(DKind) &&
- hasStaticScheduling(*NestedDir))
- return true;
- if (DKind == OMPD_parallel) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = getSingleCompoundChild(Ctx, Body);
- if (const auto *NND = dyn_cast<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- }
- }
- return false;
- case OMPD_target_parallel:
- return isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NestedDir);
- case OMPD_target_teams_distribute:
- case OMPD_target_simd:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
- case OMPD_target_teams_distribute_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_target:
- case OMPD_end_declare_target:
- case OMPD_declare_reduction:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- llvm_unreachable("Unexpected directive.");
- }
- }
-
- return false;
-}
-
-/// Checks if the construct supports lightweight runtime. It must be SPMD
-/// construct + inner loop-based construct with static scheduling.
-static bool supportsLightweightRuntime(ASTContext &Ctx,
- const OMPExecutableDirective &D) {
- if (!supportsSPMDExecutionMode(Ctx, D))
- return false;
- OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
- switch (DirectiveKind) {
- case OMPD_target:
- case OMPD_target_teams:
- case OMPD_target_parallel:
- return hasNestedLightweightDirective(Ctx, D);
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- // (Last|First)-privates must be shared in parallel region.
- return hasStaticScheduling(D);
- case OMPD_target_simd:
- case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
- return false;
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_target:
- case OMPD_end_declare_target:
- case OMPD_declare_reduction:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- break;
- }
- llvm_unreachable(
- "Unknown programming model for OpenMP directive on NVPTX target.");
-}
-
-void CGOpenMPRuntimeNVPTX::emitNonSPMDKernel(const OMPExecutableDirective &D,
- StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen) {
- ExecutionRuntimeModesRAII ModeRAII(CurrentExecutionMode);
- EntryFunctionState EST;
- WorkerFunctionState WST(CGM, D.getBeginLoc());
- Work.clear();
- WrapperFunctionsMap.clear();
-
- // Emit target region as a standalone region.
- class NVPTXPrePostActionTy : public PrePostActionTy {
- CGOpenMPRuntimeNVPTX::EntryFunctionState &EST;
- CGOpenMPRuntimeNVPTX::WorkerFunctionState &WST;
-
- public:
- NVPTXPrePostActionTy(CGOpenMPRuntimeNVPTX::EntryFunctionState &EST,
- CGOpenMPRuntimeNVPTX::WorkerFunctionState &WST)
- : EST(EST), WST(WST) {}
- void Enter(CodeGenFunction &CGF) override {
- auto &RT =
- static_cast<CGOpenMPRuntimeNVPTX &>(CGF.CGM.getOpenMPRuntime());
- RT.emitNonSPMDEntryHeader(CGF, EST, WST);
- // Skip target region initialization.
- RT.setLocThreadIdInsertPt(CGF, /*AtCurrentPoint=*/true);
- }
- void Exit(CodeGenFunction &CGF) override {
- auto &RT =
- static_cast<CGOpenMPRuntimeNVPTX &>(CGF.CGM.getOpenMPRuntime());
- RT.clearLocThreadIdInsertPt(CGF);
- RT.emitNonSPMDEntryFooter(CGF, EST);
- }
- } Action(EST, WST);
- CodeGen.setAction(Action);
- IsInTTDRegion = true;
- // Reserve place for the globalized memory.
- GlobalizedRecords.emplace_back();
- if (!KernelStaticGlobalized) {
- KernelStaticGlobalized = new llvm::GlobalVariable(
- CGM.getModule(), CGM.VoidPtrTy, /*isConstant=*/false,
- llvm::GlobalValue::InternalLinkage,
- llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
- "_openmp_kernel_static_glob_rd$ptr", /*InsertBefore=*/nullptr,
- llvm::GlobalValue::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(LangAS::cuda_shared));
- }
- emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
- IsOffloadEntry, CodeGen);
- IsInTTDRegion = false;
-
- // Now change the name of the worker function to correspond to this target
- // region's entry function.
- WST.WorkerFn->setName(Twine(OutlinedFn->getName(), "_worker"));
-
- // Create the worker function
- emitWorkerFunction(WST);
-}
-
-// Setup NVPTX threads for master-worker OpenMP scheme.
-void CGOpenMPRuntimeNVPTX::emitNonSPMDEntryHeader(CodeGenFunction &CGF,
- EntryFunctionState &EST,
- WorkerFunctionState &WST) {
- CGBuilderTy &Bld = CGF.Builder;
-
- llvm::BasicBlock *WorkerBB = CGF.createBasicBlock(".worker");
- llvm::BasicBlock *MasterCheckBB = CGF.createBasicBlock(".mastercheck");
- llvm::BasicBlock *MasterBB = CGF.createBasicBlock(".master");
- EST.ExitBB = CGF.createBasicBlock(".exit");
-
- llvm::Value *IsWorker =
- Bld.CreateICmpULT(getNVPTXThreadID(CGF), getThreadLimit(CGF));
- Bld.CreateCondBr(IsWorker, WorkerBB, MasterCheckBB);
-
- CGF.EmitBlock(WorkerBB);
- emitCall(CGF, WST.Loc, WST.WorkerFn);
- CGF.EmitBranch(EST.ExitBB);
-
- CGF.EmitBlock(MasterCheckBB);
- llvm::Value *IsMaster =
- Bld.CreateICmpEQ(getNVPTXThreadID(CGF), getMasterThreadID(CGF));
- Bld.CreateCondBr(IsMaster, MasterBB, EST.ExitBB);
-
- CGF.EmitBlock(MasterBB);
- IsInTargetMasterThreadRegion = true;
- // SEQUENTIAL (MASTER) REGION START
- // First action in sequential region:
- // Initialize the state of the OpenMP runtime library on the GPU.
- // TODO: Optimize runtime initialization and pass in correct value.
- llvm::Value *Args[] = {getThreadLimit(CGF),
- Bld.getInt16(/*RequiresOMPRuntime=*/1)};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_init), Args);
-
- // For data sharing, we need to initialize the stack.
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_data_sharing_init_stack));
-
- emitGenericVarsProlog(CGF, WST.Loc);
-}
-
-void CGOpenMPRuntimeNVPTX::emitNonSPMDEntryFooter(CodeGenFunction &CGF,
- EntryFunctionState &EST) {
- IsInTargetMasterThreadRegion = false;
- if (!CGF.HaveInsertPoint())
- return;
-
- emitGenericVarsEpilog(CGF);
-
- if (!EST.ExitBB)
- EST.ExitBB = CGF.createBasicBlock(".exit");
-
- llvm::BasicBlock *TerminateBB = CGF.createBasicBlock(".termination.notifier");
- CGF.EmitBranch(TerminateBB);
-
- CGF.EmitBlock(TerminateBB);
- // Signal termination condition.
- // TODO: Optimize runtime initialization and pass in correct value.
- llvm::Value *Args[] = {CGF.Builder.getInt16(/*IsOMPRuntimeInitialized=*/1)};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_deinit), Args);
- // Barrier to terminate worker threads.
- syncCTAThreads(CGF);
- // Master thread jumps to exit point.
- CGF.EmitBranch(EST.ExitBB);
-
- CGF.EmitBlock(EST.ExitBB);
- EST.ExitBB = nullptr;
-}
-
-void CGOpenMPRuntimeNVPTX::emitSPMDKernel(const OMPExecutableDirective &D,
- StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen) {
- ExecutionRuntimeModesRAII ModeRAII(
- CurrentExecutionMode, RequiresFullRuntime,
- CGM.getLangOpts().OpenMPCUDAForceFullRuntime ||
- !supportsLightweightRuntime(CGM.getContext(), D));
- EntryFunctionState EST;
-
- // Emit target region as a standalone region.
- class NVPTXPrePostActionTy : public PrePostActionTy {
- CGOpenMPRuntimeNVPTX &RT;
- CGOpenMPRuntimeNVPTX::EntryFunctionState &EST;
- const OMPExecutableDirective &D;
-
- public:
- NVPTXPrePostActionTy(CGOpenMPRuntimeNVPTX &RT,
- CGOpenMPRuntimeNVPTX::EntryFunctionState &EST,
- const OMPExecutableDirective &D)
- : RT(RT), EST(EST), D(D) {}
- void Enter(CodeGenFunction &CGF) override {
- RT.emitSPMDEntryHeader(CGF, EST, D);
- // Skip target region initialization.
- RT.setLocThreadIdInsertPt(CGF, /*AtCurrentPoint=*/true);
- }
- void Exit(CodeGenFunction &CGF) override {
- RT.clearLocThreadIdInsertPt(CGF);
- RT.emitSPMDEntryFooter(CGF, EST);
- }
- } Action(*this, EST, D);
- CodeGen.setAction(Action);
- IsInTTDRegion = true;
- // Reserve place for the globalized memory.
- GlobalizedRecords.emplace_back();
- if (!KernelStaticGlobalized) {
- KernelStaticGlobalized = new llvm::GlobalVariable(
- CGM.getModule(), CGM.VoidPtrTy, /*isConstant=*/false,
- llvm::GlobalValue::InternalLinkage,
- llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
- "_openmp_kernel_static_glob_rd$ptr", /*InsertBefore=*/nullptr,
- llvm::GlobalValue::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(LangAS::cuda_shared));
- }
- emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
- IsOffloadEntry, CodeGen);
- IsInTTDRegion = false;
-}
-
-void CGOpenMPRuntimeNVPTX::emitSPMDEntryHeader(
- CodeGenFunction &CGF, EntryFunctionState &EST,
- const OMPExecutableDirective &D) {
- CGBuilderTy &Bld = CGF.Builder;
-
- // Setup BBs in entry function.
- llvm::BasicBlock *ExecuteBB = CGF.createBasicBlock(".execute");
- EST.ExitBB = CGF.createBasicBlock(".exit");
-
- llvm::Value *Args[] = {getThreadLimit(CGF, /*IsInSPMDExecutionMode=*/true),
- /*RequiresOMPRuntime=*/
- Bld.getInt16(RequiresFullRuntime ? 1 : 0),
- /*RequiresDataSharing=*/Bld.getInt16(0)};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_spmd_kernel_init), Args);
-
- if (RequiresFullRuntime) {
- // For data sharing, we need to initialize the stack.
- CGF.EmitRuntimeCall(createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_data_sharing_init_stack_spmd));
- }
-
- CGF.EmitBranch(ExecuteBB);
-
- CGF.EmitBlock(ExecuteBB);
-
- IsInTargetMasterThreadRegion = true;
-}
-
-void CGOpenMPRuntimeNVPTX::emitSPMDEntryFooter(CodeGenFunction &CGF,
- EntryFunctionState &EST) {
- IsInTargetMasterThreadRegion = false;
- if (!CGF.HaveInsertPoint())
- return;
-
- if (!EST.ExitBB)
- EST.ExitBB = CGF.createBasicBlock(".exit");
-
- llvm::BasicBlock *OMPDeInitBB = CGF.createBasicBlock(".omp.deinit");
- CGF.EmitBranch(OMPDeInitBB);
-
- CGF.EmitBlock(OMPDeInitBB);
- // DeInitialize the OMP state in the runtime; called by all active threads.
- llvm::Value *Args[] = {/*RequiresOMPRuntime=*/
- CGF.Builder.getInt16(RequiresFullRuntime ? 1 : 0)};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_spmd_kernel_deinit_v2), Args);
- CGF.EmitBranch(EST.ExitBB);
-
- CGF.EmitBlock(EST.ExitBB);
- EST.ExitBB = nullptr;
-}
-
-// Create a unique global variable to indicate the execution mode of this target
-// region. The execution mode is either 'generic', or 'spmd' depending on the
-// target directive. This variable is picked up by the offload library to setup
-// the device appropriately before kernel launch. If the execution mode is
-// 'generic', the runtime reserves one warp for the master, otherwise, all
-// warps participate in parallel work.
-static void setPropertyExecutionMode(CodeGenModule &CGM, StringRef Name,
- bool Mode) {
- auto *GVMode =
- new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::WeakAnyLinkage,
- llvm::ConstantInt::get(CGM.Int8Ty, Mode ? 0 : 1),
- Twine(Name, "_exec_mode"));
- CGM.addCompilerUsedGlobal(GVMode);
-}
-
-void CGOpenMPRuntimeNVPTX::emitWorkerFunction(WorkerFunctionState &WST) {
- ASTContext &Ctx = CGM.getContext();
-
- CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
- CGF.StartFunction(GlobalDecl(), Ctx.VoidTy, WST.WorkerFn, WST.CGFI, {},
- WST.Loc, WST.Loc);
- emitWorkerLoop(CGF, WST);
- CGF.FinishFunction();
-}
-
-void CGOpenMPRuntimeNVPTX::emitWorkerLoop(CodeGenFunction &CGF,
- WorkerFunctionState &WST) {
- //
- // The workers enter this loop and wait for parallel work from the master.
- // When the master encounters a parallel region it sets up the work + variable
- // arguments, and wakes up the workers. The workers first check to see if
- // they are required for the parallel region, i.e., within the # of requested
- // parallel threads. The activated workers load the variable arguments and
- // execute the parallel work.
- //
-
- CGBuilderTy &Bld = CGF.Builder;
-
- llvm::BasicBlock *AwaitBB = CGF.createBasicBlock(".await.work");
- llvm::BasicBlock *SelectWorkersBB = CGF.createBasicBlock(".select.workers");
- llvm::BasicBlock *ExecuteBB = CGF.createBasicBlock(".execute.parallel");
- llvm::BasicBlock *TerminateBB = CGF.createBasicBlock(".terminate.parallel");
- llvm::BasicBlock *BarrierBB = CGF.createBasicBlock(".barrier.parallel");
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".exit");
-
- CGF.EmitBranch(AwaitBB);
-
- // Workers wait for work from master.
- CGF.EmitBlock(AwaitBB);
- // Wait for parallel work
- syncCTAThreads(CGF);
-
- Address WorkFn =
- CGF.CreateDefaultAlignTempAlloca(CGF.Int8PtrTy, /*Name=*/"work_fn");
- Address ExecStatus =
- CGF.CreateDefaultAlignTempAlloca(CGF.Int8Ty, /*Name=*/"exec_status");
- CGF.InitTempAlloca(ExecStatus, Bld.getInt8(/*C=*/0));
- CGF.InitTempAlloca(WorkFn, llvm::Constant::getNullValue(CGF.Int8PtrTy));
-
- // TODO: Optimize runtime initialization and pass in correct value.
- llvm::Value *Args[] = {WorkFn.getPointer(),
- /*RequiresOMPRuntime=*/Bld.getInt16(1)};
- llvm::Value *Ret = CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_parallel), Args);
- Bld.CreateStore(Bld.CreateZExt(Ret, CGF.Int8Ty), ExecStatus);
-
- // On termination condition (workid == 0), exit loop.
- llvm::Value *WorkID = Bld.CreateLoad(WorkFn);
- llvm::Value *ShouldTerminate = Bld.CreateIsNull(WorkID, "should_terminate");
- Bld.CreateCondBr(ShouldTerminate, ExitBB, SelectWorkersBB);
-
- // Activate requested workers.
- CGF.EmitBlock(SelectWorkersBB);
- llvm::Value *IsActive =
- Bld.CreateIsNotNull(Bld.CreateLoad(ExecStatus), "is_active");
- Bld.CreateCondBr(IsActive, ExecuteBB, BarrierBB);
-
- // Signal start of parallel region.
- CGF.EmitBlock(ExecuteBB);
- // Skip initialization.
- setLocThreadIdInsertPt(CGF, /*AtCurrentPoint=*/true);
-
- // Process work items: outlined parallel functions.
- for (llvm::Function *W : Work) {
- // Try to match this outlined function.
- llvm::Value *ID = Bld.CreatePointerBitCastOrAddrSpaceCast(W, CGM.Int8PtrTy);
-
- llvm::Value *WorkFnMatch =
- Bld.CreateICmpEQ(Bld.CreateLoad(WorkFn), ID, "work_match");
-
- llvm::BasicBlock *ExecuteFNBB = CGF.createBasicBlock(".execute.fn");
- llvm::BasicBlock *CheckNextBB = CGF.createBasicBlock(".check.next");
- Bld.CreateCondBr(WorkFnMatch, ExecuteFNBB, CheckNextBB);
-
- // Execute this outlined function.
- CGF.EmitBlock(ExecuteFNBB);
-
- // Insert call to work function via shared wrapper. The shared
- // wrapper takes two arguments:
- // - the parallelism level;
- // - the thread ID;
- emitCall(CGF, WST.Loc, W,
- {Bld.getInt16(/*ParallelLevel=*/0), getThreadID(CGF, WST.Loc)});
-
- // Go to end of parallel region.
- CGF.EmitBranch(TerminateBB);
-
- CGF.EmitBlock(CheckNextBB);
- }
- // Default case: call to outlined function through pointer if the target
- // region makes a declare target call that may contain an orphaned parallel
- // directive.
- auto *ParallelFnTy =
- llvm::FunctionType::get(CGM.VoidTy, {CGM.Int16Ty, CGM.Int32Ty},
- /*isVarArg=*/false)
- ->getPointerTo();
- llvm::Value *WorkFnCast = Bld.CreateBitCast(WorkID, ParallelFnTy);
- // Insert call to work function via shared wrapper. The shared
- // wrapper takes two arguments:
- // - the parallelism level;
- // - the thread ID;
- emitCall(CGF, WST.Loc, WorkFnCast,
- {Bld.getInt16(/*ParallelLevel=*/0), getThreadID(CGF, WST.Loc)});
- // Go to end of parallel region.
- CGF.EmitBranch(TerminateBB);
-
- // Signal end of parallel region.
- CGF.EmitBlock(TerminateBB);
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_end_parallel),
- llvm::None);
- CGF.EmitBranch(BarrierBB);
-
- // All active and inactive workers wait at a barrier after parallel region.
- CGF.EmitBlock(BarrierBB);
- // Barrier after parallel region.
- syncCTAThreads(CGF);
- CGF.EmitBranch(AwaitBB);
-
- // Exit target region.
- CGF.EmitBlock(ExitBB);
- // Skip initialization.
- clearLocThreadIdInsertPt(CGF);
-}
-
-/// Returns specified OpenMP runtime function for the current OpenMP
-/// implementation. Specialized for the NVPTX device.
-/// \param Function OpenMP runtime function.
-/// \return Specified function.
-llvm::Constant *
-CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) {
- llvm::Constant *RTLFn = nullptr;
- switch (static_cast<OpenMPRTLFunctionNVPTX>(Function)) {
- case OMPRTL_NVPTX__kmpc_kernel_init: {
- // Build void __kmpc_kernel_init(kmp_int32 thread_limit, int16_t
- // RequiresOMPRuntime);
- llvm::Type *TypeParams[] = {CGM.Int32Ty, CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_init");
- break;
- }
- case OMPRTL_NVPTX__kmpc_kernel_deinit: {
- // Build void __kmpc_kernel_deinit(int16_t IsOMPRuntimeInitialized);
- llvm::Type *TypeParams[] = {CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_deinit");
- break;
- }
- case OMPRTL_NVPTX__kmpc_spmd_kernel_init: {
- // Build void __kmpc_spmd_kernel_init(kmp_int32 thread_limit,
- // int16_t RequiresOMPRuntime, int16_t RequiresDataSharing);
- llvm::Type *TypeParams[] = {CGM.Int32Ty, CGM.Int16Ty, CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_spmd_kernel_init");
- break;
- }
- case OMPRTL_NVPTX__kmpc_spmd_kernel_deinit_v2: {
- // Build void __kmpc_spmd_kernel_deinit_v2(int16_t RequiresOMPRuntime);
- llvm::Type *TypeParams[] = {CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_spmd_kernel_deinit_v2");
- break;
- }
- case OMPRTL_NVPTX__kmpc_kernel_prepare_parallel: {
- /// Build void __kmpc_kernel_prepare_parallel(
- /// void *outlined_function, int16_t IsOMPRuntimeInitialized);
- llvm::Type *TypeParams[] = {CGM.Int8PtrTy, CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_prepare_parallel");
- break;
- }
- case OMPRTL_NVPTX__kmpc_kernel_parallel: {
- /// Build bool __kmpc_kernel_parallel(void **outlined_function,
- /// int16_t IsOMPRuntimeInitialized);
- llvm::Type *TypeParams[] = {CGM.Int8PtrPtrTy, CGM.Int16Ty};
- llvm::Type *RetTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
- auto *FnTy =
- llvm::FunctionType::get(RetTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_parallel");
- break;
- }
- case OMPRTL_NVPTX__kmpc_kernel_end_parallel: {
- /// Build void __kmpc_kernel_end_parallel();
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, llvm::None, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_end_parallel");
- break;
- }
- case OMPRTL_NVPTX__kmpc_serialized_parallel: {
- // Build void __kmpc_serialized_parallel(ident_t *loc, kmp_int32
- // global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_serialized_parallel");
- break;
- }
- case OMPRTL_NVPTX__kmpc_end_serialized_parallel: {
- // Build void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32
- // global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_serialized_parallel");
- break;
- }
- case OMPRTL_NVPTX__kmpc_shuffle_int32: {
- // Build int32_t __kmpc_shuffle_int32(int32_t element,
- // int16_t lane_offset, int16_t warp_size);
- llvm::Type *TypeParams[] = {CGM.Int32Ty, CGM.Int16Ty, CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_shuffle_int32");
- break;
- }
- case OMPRTL_NVPTX__kmpc_shuffle_int64: {
- // Build int64_t __kmpc_shuffle_int64(int64_t element,
- // int16_t lane_offset, int16_t warp_size);
- llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.Int16Ty, CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int64Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_shuffle_int64");
- break;
- }
- case OMPRTL_NVPTX__kmpc_parallel_reduce_nowait_v2: {
- // Build int32_t kmpc_nvptx_parallel_reduce_nowait_v2(ident_t *loc,
- // kmp_int32 global_tid, kmp_int32 num_vars, size_t reduce_size, void*
- // reduce_data, void (*kmp_ShuffleReductFctPtr)(void *rhsData, int16_t
- // lane_id, int16_t lane_offset, int16_t Algorithm Version), void
- // (*kmp_InterWarpCopyFctPtr)(void* src, int warp_num));
- llvm::Type *ShuffleReduceTypeParams[] = {CGM.VoidPtrTy, CGM.Int16Ty,
- CGM.Int16Ty, CGM.Int16Ty};
- auto *ShuffleReduceFnTy =
- llvm::FunctionType::get(CGM.VoidTy, ShuffleReduceTypeParams,
- /*isVarArg=*/false);
- llvm::Type *InterWarpCopyTypeParams[] = {CGM.VoidPtrTy, CGM.Int32Ty};
- auto *InterWarpCopyFnTy =
- llvm::FunctionType::get(CGM.VoidTy, InterWarpCopyTypeParams,
- /*isVarArg=*/false);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(),
- CGM.Int32Ty,
- CGM.Int32Ty,
- CGM.SizeTy,
- CGM.VoidPtrTy,
- ShuffleReduceFnTy->getPointerTo(),
- InterWarpCopyFnTy->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(
- FnTy, /*Name=*/"__kmpc_nvptx_parallel_reduce_nowait_v2");
- break;
- }
- case OMPRTL_NVPTX__kmpc_end_reduce_nowait: {
- // Build __kmpc_end_reduce_nowait(kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(
- FnTy, /*Name=*/"__kmpc_nvptx_end_reduce_nowait");
- break;
- }
- case OMPRTL_NVPTX__kmpc_nvptx_teams_reduce_nowait_simple: {
- // Build __kmpc_nvptx_teams_reduce_nowait_simple(ident_t *loc, kmp_int32
- // global_tid, kmp_critical_name *lck)
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty,
- llvm::PointerType::getUnqual(getKmpCriticalNameTy())};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(
- FnTy, /*Name=*/"__kmpc_nvptx_teams_reduce_nowait_simple");
- break;
- }
- case OMPRTL_NVPTX__kmpc_nvptx_teams_end_reduce_nowait_simple: {
- // Build __kmpc_nvptx_teams_end_reduce_nowait_simple(ident_t *loc, kmp_int32
- // global_tid, kmp_critical_name *lck)
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), CGM.Int32Ty,
- llvm::PointerType::getUnqual(getKmpCriticalNameTy())};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(
- FnTy, /*Name=*/"__kmpc_nvptx_teams_end_reduce_nowait_simple");
- break;
- }
- case OMPRTL_NVPTX__kmpc_data_sharing_init_stack: {
- /// Build void __kmpc_data_sharing_init_stack();
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, llvm::None, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_data_sharing_init_stack");
- break;
- }
- case OMPRTL_NVPTX__kmpc_data_sharing_init_stack_spmd: {
- /// Build void __kmpc_data_sharing_init_stack_spmd();
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, llvm::None, /*isVarArg*/ false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, "__kmpc_data_sharing_init_stack_spmd");
- break;
- }
- case OMPRTL_NVPTX__kmpc_data_sharing_coalesced_push_stack: {
- // Build void *__kmpc_data_sharing_coalesced_push_stack(size_t size,
- // int16_t UseSharedMemory);
- llvm::Type *TypeParams[] = {CGM.SizeTy, CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(
- FnTy, /*Name=*/"__kmpc_data_sharing_coalesced_push_stack");
- break;
- }
- case OMPRTL_NVPTX__kmpc_data_sharing_pop_stack: {
- // Build void __kmpc_data_sharing_pop_stack(void *a);
- llvm::Type *TypeParams[] = {CGM.VoidPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy,
- /*Name=*/"__kmpc_data_sharing_pop_stack");
- break;
- }
- case OMPRTL_NVPTX__kmpc_begin_sharing_variables: {
- /// Build void __kmpc_begin_sharing_variables(void ***args,
- /// size_t n_args);
- llvm::Type *TypeParams[] = {CGM.Int8PtrPtrTy->getPointerTo(), CGM.SizeTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_begin_sharing_variables");
- break;
- }
- case OMPRTL_NVPTX__kmpc_end_sharing_variables: {
- /// Build void __kmpc_end_sharing_variables();
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, llvm::None, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_sharing_variables");
- break;
- }
- case OMPRTL_NVPTX__kmpc_get_shared_variables: {
- /// Build void __kmpc_get_shared_variables(void ***GlobalArgs);
- llvm::Type *TypeParams[] = {CGM.Int8PtrPtrTy->getPointerTo()};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_get_shared_variables");
- break;
- }
- case OMPRTL_NVPTX__kmpc_parallel_level: {
- // Build uint16_t __kmpc_parallel_level(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.Int16Ty, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_parallel_level");
- break;
- }
- case OMPRTL_NVPTX__kmpc_is_spmd_exec_mode: {
- // Build int8_t __kmpc_is_spmd_exec_mode();
- auto *FnTy = llvm::FunctionType::get(CGM.Int8Ty, /*isVarArg=*/false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_is_spmd_exec_mode");
- break;
- }
- case OMPRTL_NVPTX__kmpc_get_team_static_memory: {
- // Build void __kmpc_get_team_static_memory(int16_t isSPMDExecutionMode,
- // const void *buf, size_t size, int16_t is_shared, const void **res);
- llvm::Type *TypeParams[] = {CGM.Int16Ty, CGM.VoidPtrTy, CGM.SizeTy,
- CGM.Int16Ty, CGM.VoidPtrPtrTy};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_get_team_static_memory");
- break;
- }
- case OMPRTL_NVPTX__kmpc_restore_team_static_memory: {
- // Build void __kmpc_restore_team_static_memory(int16_t isSPMDExecutionMode,
- // int16_t is_shared);
- llvm::Type *TypeParams[] = {CGM.Int16Ty, CGM.Int16Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, "__kmpc_restore_team_static_memory");
- break;
- }
- case OMPRTL__kmpc_barrier: {
- // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
- cast<llvm::Function>(RTLFn)->addFnAttr(llvm::Attribute::Convergent);
- break;
- }
- case OMPRTL__kmpc_barrier_simple_spmd: {
- // Build void __kmpc_barrier_simple_spmd(ident_t *loc, kmp_int32
- // global_tid);
- llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
- auto *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn =
- CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier_simple_spmd");
- cast<llvm::Function>(RTLFn)->addFnAttr(llvm::Attribute::Convergent);
- break;
- }
- }
- return RTLFn;
-}
-
-void CGOpenMPRuntimeNVPTX::createOffloadEntry(llvm::Constant *ID,
- llvm::Constant *Addr,
- uint64_t Size, int32_t,
- llvm::GlobalValue::LinkageTypes) {
- // TODO: Add support for global variables on the device after declare target
- // support.
- if (!isa<llvm::Function>(Addr))
- return;
- llvm::Module &M = CGM.getModule();
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
-
- // Get "nvvm.annotations" metadata node
- llvm::NamedMDNode *MD = M.getOrInsertNamedMetadata("nvvm.annotations");
-
- llvm::Metadata *MDVals[] = {
- llvm::ConstantAsMetadata::get(Addr), llvm::MDString::get(Ctx, "kernel"),
- llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 1))};
- // Append metadata to nvvm.annotations
- MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
-}
-
-void CGOpenMPRuntimeNVPTX::emitTargetOutlinedFunction(
- const OMPExecutableDirective &D, StringRef ParentName,
- llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
- if (!IsOffloadEntry) // Nothing to do.
- return;
-
- assert(!ParentName.empty() && "Invalid target region parent name!");
-
- bool Mode = supportsSPMDExecutionMode(CGM.getContext(), D);
- if (Mode)
- emitSPMDKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry,
- CodeGen);
- else
- emitNonSPMDKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry,
- CodeGen);
-
- setPropertyExecutionMode(CGM, OutlinedFn->getName(), Mode);
-}
-
-namespace {
-LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
-/// Enum for accesseing the reserved_2 field of the ident_t struct.
-enum ModeFlagsTy : unsigned {
- /// Bit set to 1 when in SPMD mode.
- KMP_IDENT_SPMD_MODE = 0x01,
- /// Bit set to 1 when a simplified runtime is used.
- KMP_IDENT_SIMPLE_RT_MODE = 0x02,
- LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/KMP_IDENT_SIMPLE_RT_MODE)
-};
-
-/// Special mode Undefined. Is the combination of Non-SPMD mode + SimpleRuntime.
-static const ModeFlagsTy UndefinedMode =
- (~KMP_IDENT_SPMD_MODE) & KMP_IDENT_SIMPLE_RT_MODE;
-} // anonymous namespace
-
-unsigned CGOpenMPRuntimeNVPTX::getDefaultLocationReserved2Flags() const {
- switch (getExecutionMode()) {
- case EM_SPMD:
- if (requiresFullRuntime())
- return KMP_IDENT_SPMD_MODE & (~KMP_IDENT_SIMPLE_RT_MODE);
- return KMP_IDENT_SPMD_MODE | KMP_IDENT_SIMPLE_RT_MODE;
- case EM_NonSPMD:
- assert(requiresFullRuntime() && "Expected full runtime.");
- return (~KMP_IDENT_SPMD_MODE) & (~KMP_IDENT_SIMPLE_RT_MODE);
- case EM_Unknown:
- return UndefinedMode;
- }
- llvm_unreachable("Unknown flags are requested.");
-}
-
-CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM)
- : CGOpenMPRuntime(CGM, "_", "$") {
- if (!CGM.getLangOpts().OpenMPIsDevice)
- llvm_unreachable("OpenMP NVPTX can only handle device code.");
-}
-
-void CGOpenMPRuntimeNVPTX::emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
- SourceLocation Loc) {
- // Do nothing in case of SPMD mode and L0 parallel.
- if (getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD)
- return;
-
- CGOpenMPRuntime::emitProcBindClause(CGF, ProcBind, Loc);
-}
-
-void CGOpenMPRuntimeNVPTX::emitNumThreadsClause(CodeGenFunction &CGF,
- llvm::Value *NumThreads,
- SourceLocation Loc) {
- // Do nothing in case of SPMD mode and L0 parallel.
- if (getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD)
- return;
-
- CGOpenMPRuntime::emitNumThreadsClause(CGF, NumThreads, Loc);
-}
-
-void CGOpenMPRuntimeNVPTX::emitNumTeamsClause(CodeGenFunction &CGF,
- const Expr *NumTeams,
- const Expr *ThreadLimit,
- SourceLocation Loc) {}
-
-llvm::Value *CGOpenMPRuntimeNVPTX::emitParallelOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
- // Emit target region as a standalone region.
- class NVPTXPrePostActionTy : public PrePostActionTy {
- bool &IsInParallelRegion;
- bool PrevIsInParallelRegion;
-
- public:
- NVPTXPrePostActionTy(bool &IsInParallelRegion)
- : IsInParallelRegion(IsInParallelRegion) {}
- void Enter(CodeGenFunction &CGF) override {
- PrevIsInParallelRegion = IsInParallelRegion;
- IsInParallelRegion = true;
- }
- void Exit(CodeGenFunction &CGF) override {
- IsInParallelRegion = PrevIsInParallelRegion;
- }
- } Action(IsInParallelRegion);
- CodeGen.setAction(Action);
- bool PrevIsInTTDRegion = IsInTTDRegion;
- IsInTTDRegion = false;
- bool PrevIsInTargetMasterThreadRegion = IsInTargetMasterThreadRegion;
- IsInTargetMasterThreadRegion = false;
- auto *OutlinedFun =
- cast<llvm::Function>(CGOpenMPRuntime::emitParallelOutlinedFunction(
- D, ThreadIDVar, InnermostKind, CodeGen));
- IsInTargetMasterThreadRegion = PrevIsInTargetMasterThreadRegion;
- IsInTTDRegion = PrevIsInTTDRegion;
- if (getExecutionMode() != CGOpenMPRuntimeNVPTX::EM_SPMD &&
- !IsInParallelRegion) {
- llvm::Function *WrapperFun =
- createParallelDataSharingWrapper(OutlinedFun, D);
- WrapperFunctionsMap[OutlinedFun] = WrapperFun;
- }
-
- return OutlinedFun;
-}
-
-/// Get list of lastprivate variables from the teams distribute ... or
-/// teams {distribute ...} directives.
-static void
-getDistributeLastprivateVars(ASTContext &Ctx, const OMPExecutableDirective &D,
- llvm::SmallVectorImpl<const ValueDecl *> &Vars) {
- assert(isOpenMPTeamsDirective(D.getDirectiveKind()) &&
- "expected teams directive.");
- const OMPExecutableDirective *Dir = &D;
- if (!isOpenMPDistributeDirective(D.getDirectiveKind())) {
- if (const Stmt *S = getSingleCompoundChild(
- Ctx,
- D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true))) {
- Dir = dyn_cast<OMPExecutableDirective>(S);
- if (Dir && !isOpenMPDistributeDirective(Dir->getDirectiveKind()))
- Dir = nullptr;
- }
- }
- if (!Dir)
- return;
- for (const auto *C : Dir->getClausesOfKind<OMPLastprivateClause>()) {
- for (const Expr *E : C->getVarRefs())
- Vars.push_back(getPrivateItem(E));
- }
-}
-
-/// Get list of reduction variables from the teams ... directives.
-static void
-getTeamsReductionVars(ASTContext &Ctx, const OMPExecutableDirective &D,
- llvm::SmallVectorImpl<const ValueDecl *> &Vars) {
- assert(isOpenMPTeamsDirective(D.getDirectiveKind()) &&
- "expected teams directive.");
- for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
- for (const Expr *E : C->privates())
- Vars.push_back(getPrivateItem(E));
- }
-}
-
-llvm::Value *CGOpenMPRuntimeNVPTX::emitTeamsOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
- SourceLocation Loc = D.getBeginLoc();
-
- const RecordDecl *GlobalizedRD = nullptr;
- llvm::SmallVector<const ValueDecl *, 4> LastPrivatesReductions;
- llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *> MappedDeclsFields;
- // Globalize team reductions variable unconditionally in all modes.
- getTeamsReductionVars(CGM.getContext(), D, LastPrivatesReductions);
- if (getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD) {
- getDistributeLastprivateVars(CGM.getContext(), D, LastPrivatesReductions);
- if (!LastPrivatesReductions.empty()) {
- GlobalizedRD = ::buildRecordForGlobalizedVars(
- CGM.getContext(), llvm::None, LastPrivatesReductions,
- MappedDeclsFields);
- }
- } else if (!LastPrivatesReductions.empty()) {
- assert(!TeamAndReductions.first &&
- "Previous team declaration is not expected.");
- TeamAndReductions.first = D.getCapturedStmt(OMPD_teams)->getCapturedDecl();
- std::swap(TeamAndReductions.second, LastPrivatesReductions);
- }
-
- // Emit target region as a standalone region.
- class NVPTXPrePostActionTy : public PrePostActionTy {
- SourceLocation &Loc;
- const RecordDecl *GlobalizedRD;
- llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *>
- &MappedDeclsFields;
-
- public:
- NVPTXPrePostActionTy(
- SourceLocation &Loc, const RecordDecl *GlobalizedRD,
- llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *>
- &MappedDeclsFields)
- : Loc(Loc), GlobalizedRD(GlobalizedRD),
- MappedDeclsFields(MappedDeclsFields) {}
- void Enter(CodeGenFunction &CGF) override {
- auto &Rt =
- static_cast<CGOpenMPRuntimeNVPTX &>(CGF.CGM.getOpenMPRuntime());
- if (GlobalizedRD) {
- auto I = Rt.FunctionGlobalizedDecls.try_emplace(CGF.CurFn).first;
- I->getSecond().GlobalRecord = GlobalizedRD;
- I->getSecond().MappedParams =
- llvm::make_unique<CodeGenFunction::OMPMapVars>();
- DeclToAddrMapTy &Data = I->getSecond().LocalVarData;
- for (const auto &Pair : MappedDeclsFields) {
- assert(Pair.getFirst()->isCanonicalDecl() &&
- "Expected canonical declaration");
- Data.insert(std::make_pair(Pair.getFirst(),
- MappedVarData(Pair.getSecond(),
- /*IsOnePerTeam=*/true)));
- }
- }
- Rt.emitGenericVarsProlog(CGF, Loc);
- }
- void Exit(CodeGenFunction &CGF) override {
- static_cast<CGOpenMPRuntimeNVPTX &>(CGF.CGM.getOpenMPRuntime())
- .emitGenericVarsEpilog(CGF);
- }
- } Action(Loc, GlobalizedRD, MappedDeclsFields);
- CodeGen.setAction(Action);
- llvm::Value *OutlinedFunVal = CGOpenMPRuntime::emitTeamsOutlinedFunction(
- D, ThreadIDVar, InnermostKind, CodeGen);
- llvm::Function *OutlinedFun = cast<llvm::Function>(OutlinedFunVal);
- OutlinedFun->removeFnAttr(llvm::Attribute::NoInline);
- OutlinedFun->removeFnAttr(llvm::Attribute::OptimizeNone);
- OutlinedFun->addFnAttr(llvm::Attribute::AlwaysInline);
-
- return OutlinedFun;
-}
-
-void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF,
- SourceLocation Loc,
- bool WithSPMDCheck) {
- if (getDataSharingMode(CGM) != CGOpenMPRuntimeNVPTX::Generic &&
- getExecutionMode() != CGOpenMPRuntimeNVPTX::EM_SPMD)
- return;
-
- CGBuilderTy &Bld = CGF.Builder;
-
- const auto I = FunctionGlobalizedDecls.find(CGF.CurFn);
- if (I == FunctionGlobalizedDecls.end())
- return;
- if (const RecordDecl *GlobalizedVarsRecord = I->getSecond().GlobalRecord) {
- QualType GlobalRecTy = CGM.getContext().getRecordType(GlobalizedVarsRecord);
- QualType SecGlobalRecTy;
-
- // Recover pointer to this function's global record. The runtime will
- // handle the specifics of the allocation of the memory.
- // Use actual memory size of the record including the padding
- // for alignment purposes.
- unsigned Alignment =
- CGM.getContext().getTypeAlignInChars(GlobalRecTy).getQuantity();
- unsigned GlobalRecordSize =
- CGM.getContext().getTypeSizeInChars(GlobalRecTy).getQuantity();
- GlobalRecordSize = llvm::alignTo(GlobalRecordSize, Alignment);
-
- llvm::PointerType *GlobalRecPtrTy =
- CGF.ConvertTypeForMem(GlobalRecTy)->getPointerTo();
- llvm::Value *GlobalRecCastAddr;
- llvm::Value *IsTTD = nullptr;
- if (!IsInTTDRegion &&
- (WithSPMDCheck ||
- getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_Unknown)) {
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".exit");
- llvm::BasicBlock *SPMDBB = CGF.createBasicBlock(".spmd");
- llvm::BasicBlock *NonSPMDBB = CGF.createBasicBlock(".non-spmd");
- if (I->getSecond().SecondaryGlobalRecord.hasValue()) {
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- llvm::Value *ThreadID = getThreadID(CGF, Loc);
- llvm::Value *PL = CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_parallel_level),
- {RTLoc, ThreadID});
- IsTTD = Bld.CreateIsNull(PL);
- }
- llvm::Value *IsSPMD = Bld.CreateIsNotNull(CGF.EmitNounwindRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_is_spmd_exec_mode)));
- Bld.CreateCondBr(IsSPMD, SPMDBB, NonSPMDBB);
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(SPMDBB);
- Address RecPtr = Address(llvm::ConstantPointerNull::get(GlobalRecPtrTy),
- CharUnits::fromQuantity(Alignment));
- CGF.EmitBranch(ExitBB);
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(NonSPMDBB);
- llvm::Value *Size = llvm::ConstantInt::get(CGM.SizeTy, GlobalRecordSize);
- if (const RecordDecl *SecGlobalizedVarsRecord =
- I->getSecond().SecondaryGlobalRecord.getValueOr(nullptr)) {
- SecGlobalRecTy =
- CGM.getContext().getRecordType(SecGlobalizedVarsRecord);
-
- // Recover pointer to this function's global record. The runtime will
- // handle the specifics of the allocation of the memory.
- // Use actual memory size of the record including the padding
- // for alignment purposes.
- unsigned Alignment =
- CGM.getContext().getTypeAlignInChars(SecGlobalRecTy).getQuantity();
- unsigned GlobalRecordSize =
- CGM.getContext().getTypeSizeInChars(SecGlobalRecTy).getQuantity();
- GlobalRecordSize = llvm::alignTo(GlobalRecordSize, Alignment);
- Size = Bld.CreateSelect(
- IsTTD, llvm::ConstantInt::get(CGM.SizeTy, GlobalRecordSize), Size);
- }
- // TODO: allow the usage of shared memory to be controlled by
- // the user, for now, default to global.
- llvm::Value *GlobalRecordSizeArg[] = {
- Size, CGF.Builder.getInt16(/*UseSharedMemory=*/0)};
- llvm::Value *GlobalRecValue = CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_data_sharing_coalesced_push_stack),
- GlobalRecordSizeArg);
- GlobalRecCastAddr = Bld.CreatePointerBitCastOrAddrSpaceCast(
- GlobalRecValue, GlobalRecPtrTy);
- CGF.EmitBlock(ExitBB);
- auto *Phi = Bld.CreatePHI(GlobalRecPtrTy,
- /*NumReservedValues=*/2, "_select_stack");
- Phi->addIncoming(RecPtr.getPointer(), SPMDBB);
- Phi->addIncoming(GlobalRecCastAddr, NonSPMDBB);
- GlobalRecCastAddr = Phi;
- I->getSecond().GlobalRecordAddr = Phi;
- I->getSecond().IsInSPMDModeFlag = IsSPMD;
- } else if (IsInTTDRegion) {
- assert(GlobalizedRecords.back().Records.size() < 2 &&
- "Expected less than 2 globalized records: one for target and one "
- "for teams.");
- unsigned Offset = 0;
- for (const RecordDecl *RD : GlobalizedRecords.back().Records) {
- QualType RDTy = CGM.getContext().getRecordType(RD);
- unsigned Alignment =
- CGM.getContext().getTypeAlignInChars(RDTy).getQuantity();
- unsigned Size = CGM.getContext().getTypeSizeInChars(RDTy).getQuantity();
- Offset =
- llvm::alignTo(llvm::alignTo(Offset, Alignment) + Size, Alignment);
- }
- unsigned Alignment =
- CGM.getContext().getTypeAlignInChars(GlobalRecTy).getQuantity();
- Offset = llvm::alignTo(Offset, Alignment);
- GlobalizedRecords.back().Records.push_back(GlobalizedVarsRecord);
- ++GlobalizedRecords.back().RegionCounter;
- if (GlobalizedRecords.back().Records.size() == 1) {
- assert(KernelStaticGlobalized &&
- "Kernel static pointer must be initialized already.");
- auto *UseSharedMemory = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int16Ty, /*isConstant=*/true,
- llvm::GlobalValue::InternalLinkage, nullptr,
- "_openmp_static_kernel$is_shared");
- UseSharedMemory->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- QualType Int16Ty = CGM.getContext().getIntTypeForBitwidth(
- /*DestWidth=*/16, /*Signed=*/0);
- llvm::Value *IsInSharedMemory = CGF.EmitLoadOfScalar(
- Address(UseSharedMemory,
- CGM.getContext().getTypeAlignInChars(Int16Ty)),
- /*Volatile=*/false, Int16Ty, Loc);
- auto *StaticGlobalized = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,
- llvm::GlobalValue::CommonLinkage, nullptr);
- auto *RecSize = new llvm::GlobalVariable(
- CGM.getModule(), CGM.SizeTy, /*isConstant=*/true,
- llvm::GlobalValue::InternalLinkage, nullptr,
- "_openmp_static_kernel$size");
- RecSize->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- llvm::Value *Ld = CGF.EmitLoadOfScalar(
- Address(RecSize, CGM.getSizeAlign()), /*Volatile=*/false,
- CGM.getContext().getSizeType(), Loc);
- llvm::Value *ResAddr = Bld.CreatePointerBitCastOrAddrSpaceCast(
- KernelStaticGlobalized, CGM.VoidPtrPtrTy);
- llvm::Value *GlobalRecordSizeArg[] = {
- llvm::ConstantInt::get(
- CGM.Int16Ty,
- getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD ? 1 : 0),
- StaticGlobalized, Ld, IsInSharedMemory, ResAddr};
- CGF.EmitRuntimeCall(createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_get_team_static_memory),
- GlobalRecordSizeArg);
- GlobalizedRecords.back().Buffer = StaticGlobalized;
- GlobalizedRecords.back().RecSize = RecSize;
- GlobalizedRecords.back().UseSharedMemory = UseSharedMemory;
- GlobalizedRecords.back().Loc = Loc;
- }
- assert(KernelStaticGlobalized && "Global address must be set already.");
- Address FrameAddr = CGF.EmitLoadOfPointer(
- Address(KernelStaticGlobalized, CGM.getPointerAlign()),
- CGM.getContext()
- .getPointerType(CGM.getContext().VoidPtrTy)
- .castAs<PointerType>());
- llvm::Value *GlobalRecValue =
- Bld.CreateConstInBoundsGEP(FrameAddr, Offset, CharUnits::One())
- .getPointer();
- I->getSecond().GlobalRecordAddr = GlobalRecValue;
- I->getSecond().IsInSPMDModeFlag = nullptr;
- GlobalRecCastAddr = Bld.CreatePointerBitCastOrAddrSpaceCast(
- GlobalRecValue, CGF.ConvertTypeForMem(GlobalRecTy)->getPointerTo());
- } else {
- // TODO: allow the usage of shared memory to be controlled by
- // the user, for now, default to global.
- llvm::Value *GlobalRecordSizeArg[] = {
- llvm::ConstantInt::get(CGM.SizeTy, GlobalRecordSize),
- CGF.Builder.getInt16(/*UseSharedMemory=*/0)};
- llvm::Value *GlobalRecValue = CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_data_sharing_coalesced_push_stack),
- GlobalRecordSizeArg);
- GlobalRecCastAddr = Bld.CreatePointerBitCastOrAddrSpaceCast(
- GlobalRecValue, GlobalRecPtrTy);
- I->getSecond().GlobalRecordAddr = GlobalRecValue;
- I->getSecond().IsInSPMDModeFlag = nullptr;
- }
- LValue Base =
- CGF.MakeNaturalAlignPointeeAddrLValue(GlobalRecCastAddr, GlobalRecTy);
-
- // Emit the "global alloca" which is a GEP from the global declaration
- // record using the pointer returned by the runtime.
- LValue SecBase;
- decltype(I->getSecond().LocalVarData)::const_iterator SecIt;
- if (IsTTD) {
- SecIt = I->getSecond().SecondaryLocalVarData->begin();
- llvm::PointerType *SecGlobalRecPtrTy =
- CGF.ConvertTypeForMem(SecGlobalRecTy)->getPointerTo();
- SecBase = CGF.MakeNaturalAlignPointeeAddrLValue(
- Bld.CreatePointerBitCastOrAddrSpaceCast(
- I->getSecond().GlobalRecordAddr, SecGlobalRecPtrTy),
- SecGlobalRecTy);
- }
- for (auto &Rec : I->getSecond().LocalVarData) {
- bool EscapedParam = I->getSecond().EscapedParameters.count(Rec.first);
- llvm::Value *ParValue;
- if (EscapedParam) {
- const auto *VD = cast<VarDecl>(Rec.first);
- LValue ParLVal =
- CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType());
- ParValue = CGF.EmitLoadOfScalar(ParLVal, Loc);
- }
- LValue VarAddr = CGF.EmitLValueForField(Base, Rec.second.FD);
- // Emit VarAddr basing on lane-id if required.
- QualType VarTy;
- if (Rec.second.IsOnePerTeam) {
- VarTy = Rec.second.FD->getType();
- } else {
- llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP(
- VarAddr.getAddress().getPointer(),
- {Bld.getInt32(0), getNVPTXLaneID(CGF)});
- VarTy =
- Rec.second.FD->getType()->castAsArrayTypeUnsafe()->getElementType();
- VarAddr = CGF.MakeAddrLValue(
- Address(Ptr, CGM.getContext().getDeclAlign(Rec.first)), VarTy,
- AlignmentSource::Decl);
- }
- Rec.second.PrivateAddr = VarAddr.getAddress();
- if (!IsInTTDRegion &&
- (WithSPMDCheck ||
- getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_Unknown)) {
- assert(I->getSecond().IsInSPMDModeFlag &&
- "Expected unknown execution mode or required SPMD check.");
- if (IsTTD) {
- assert(SecIt->second.IsOnePerTeam &&
- "Secondary glob data must be one per team.");
- LValue SecVarAddr = CGF.EmitLValueForField(SecBase, SecIt->second.FD);
- VarAddr.setAddress(
- Address(Bld.CreateSelect(IsTTD, SecVarAddr.getPointer(),
- VarAddr.getPointer()),
- VarAddr.getAlignment()));
- Rec.second.PrivateAddr = VarAddr.getAddress();
- }
- Address GlobalPtr = Rec.second.PrivateAddr;
- Address LocalAddr = CGF.CreateMemTemp(VarTy, Rec.second.FD->getName());
- Rec.second.PrivateAddr = Address(
- Bld.CreateSelect(I->getSecond().IsInSPMDModeFlag,
- LocalAddr.getPointer(), GlobalPtr.getPointer()),
- LocalAddr.getAlignment());
- }
- if (EscapedParam) {
- const auto *VD = cast<VarDecl>(Rec.first);
- CGF.EmitStoreOfScalar(ParValue, VarAddr);
- I->getSecond().MappedParams->setVarAddr(CGF, VD, VarAddr.getAddress());
- }
- if (IsTTD)
- ++SecIt;
- }
- }
- for (const ValueDecl *VD : I->getSecond().EscapedVariableLengthDecls) {
- // Recover pointer to this function's global record. The runtime will
- // handle the specifics of the allocation of the memory.
- // Use actual memory size of the record including the padding
- // for alignment purposes.
- CGBuilderTy &Bld = CGF.Builder;
- llvm::Value *Size = CGF.getTypeSize(VD->getType());
- CharUnits Align = CGM.getContext().getDeclAlign(VD);
- Size = Bld.CreateNUWAdd(
- Size, llvm::ConstantInt::get(CGF.SizeTy, Align.getQuantity() - 1));
- llvm::Value *AlignVal =
- llvm::ConstantInt::get(CGF.SizeTy, Align.getQuantity());
- Size = Bld.CreateUDiv(Size, AlignVal);
- Size = Bld.CreateNUWMul(Size, AlignVal);
- // TODO: allow the usage of shared memory to be controlled by
- // the user, for now, default to global.
- llvm::Value *GlobalRecordSizeArg[] = {
- Size, CGF.Builder.getInt16(/*UseSharedMemory=*/0)};
- llvm::Value *GlobalRecValue = CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_data_sharing_coalesced_push_stack),
- GlobalRecordSizeArg);
- llvm::Value *GlobalRecCastAddr = Bld.CreatePointerBitCastOrAddrSpaceCast(
- GlobalRecValue, CGF.ConvertTypeForMem(VD->getType())->getPointerTo());
- LValue Base = CGF.MakeAddrLValue(GlobalRecCastAddr, VD->getType(),
- CGM.getContext().getDeclAlign(VD),
- AlignmentSource::Decl);
- I->getSecond().MappedParams->setVarAddr(CGF, cast<VarDecl>(VD),
- Base.getAddress());
- I->getSecond().EscapedVariableLengthDeclsAddrs.emplace_back(GlobalRecValue);
- }
- I->getSecond().MappedParams->apply(CGF);
-}
-
-void CGOpenMPRuntimeNVPTX::emitGenericVarsEpilog(CodeGenFunction &CGF,
- bool WithSPMDCheck) {
- if (getDataSharingMode(CGM) != CGOpenMPRuntimeNVPTX::Generic &&
- getExecutionMode() != CGOpenMPRuntimeNVPTX::EM_SPMD)
- return;
-
- const auto I = FunctionGlobalizedDecls.find(CGF.CurFn);
- if (I != FunctionGlobalizedDecls.end()) {
- I->getSecond().MappedParams->restore(CGF);
- if (!CGF.HaveInsertPoint())
- return;
- for (llvm::Value *Addr :
- llvm::reverse(I->getSecond().EscapedVariableLengthDeclsAddrs)) {
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_data_sharing_pop_stack),
- Addr);
- }
- if (I->getSecond().GlobalRecordAddr) {
- if (!IsInTTDRegion &&
- (WithSPMDCheck ||
- getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_Unknown)) {
- CGBuilderTy &Bld = CGF.Builder;
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".exit");
- llvm::BasicBlock *NonSPMDBB = CGF.createBasicBlock(".non-spmd");
- Bld.CreateCondBr(I->getSecond().IsInSPMDModeFlag, ExitBB, NonSPMDBB);
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(NonSPMDBB);
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_data_sharing_pop_stack),
- CGF.EmitCastToVoidPtr(I->getSecond().GlobalRecordAddr));
- CGF.EmitBlock(ExitBB);
- } else if (IsInTTDRegion) {
- assert(GlobalizedRecords.back().RegionCounter > 0 &&
- "region counter must be > 0.");
- --GlobalizedRecords.back().RegionCounter;
- // Emit the restore function only in the target region.
- if (GlobalizedRecords.back().RegionCounter == 0) {
- QualType Int16Ty = CGM.getContext().getIntTypeForBitwidth(
- /*DestWidth=*/16, /*Signed=*/0);
- llvm::Value *IsInSharedMemory = CGF.EmitLoadOfScalar(
- Address(GlobalizedRecords.back().UseSharedMemory,
- CGM.getContext().getTypeAlignInChars(Int16Ty)),
- /*Volatile=*/false, Int16Ty, GlobalizedRecords.back().Loc);
- llvm::Value *Args[] = {
- llvm::ConstantInt::get(
- CGM.Int16Ty,
- getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD ? 1 : 0),
- IsInSharedMemory};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_restore_team_static_memory),
- Args);
- }
- } else {
- CGF.EmitRuntimeCall(createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_data_sharing_pop_stack),
- I->getSecond().GlobalRecordAddr);
- }
- }
- }
-}
-
-void CGOpenMPRuntimeNVPTX::emitTeamsCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars) {
- if (!CGF.HaveInsertPoint())
- return;
-
- Address ZeroAddr = CGF.CreateMemTemp(
- CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
- /*Name*/ ".zero.addr");
- CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
- llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
- OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).getPointer());
- OutlinedFnArgs.push_back(ZeroAddr.getPointer());
- OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
-}
-
-void CGOpenMPRuntimeNVPTX::emitParallelCall(
- CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond) {
- if (!CGF.HaveInsertPoint())
- return;
-
- if (getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD)
- emitSPMDParallelCall(CGF, Loc, OutlinedFn, CapturedVars, IfCond);
- else
- emitNonSPMDParallelCall(CGF, Loc, OutlinedFn, CapturedVars, IfCond);
-}
-
-void CGOpenMPRuntimeNVPTX::emitNonSPMDParallelCall(
- CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond) {
- llvm::Function *Fn = cast<llvm::Function>(OutlinedFn);
-
- // Force inline this outlined function at its call site.
- Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
-
- Address ZeroAddr = CGF.CreateMemTemp(CGF.getContext().getIntTypeForBitwidth(
- /*DestWidth=*/32, /*Signed=*/1),
- ".zero.addr");
- CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
- // ThreadId for serialized parallels is 0.
- Address ThreadIDAddr = ZeroAddr;
- auto &&CodeGen = [this, Fn, CapturedVars, Loc, ZeroAddr, &ThreadIDAddr](
- CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
-
- llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
- OutlinedFnArgs.push_back(ThreadIDAddr.getPointer());
- OutlinedFnArgs.push_back(ZeroAddr.getPointer());
- OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- emitOutlinedFunctionCall(CGF, Loc, Fn, OutlinedFnArgs);
- };
- auto &&SeqGen = [this, &CodeGen, Loc](CodeGenFunction &CGF,
- PrePostActionTy &) {
-
- RegionCodeGenTy RCG(CodeGen);
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- llvm::Value *ThreadID = getThreadID(CGF, Loc);
- llvm::Value *Args[] = {RTLoc, ThreadID};
-
- NVPTXActionTy Action(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_serialized_parallel),
- Args,
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_end_serialized_parallel),
- Args);
- RCG.setAction(Action);
- RCG(CGF);
- };
-
- auto &&L0ParallelGen = [this, CapturedVars, Fn](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- CGBuilderTy &Bld = CGF.Builder;
- llvm::Function *WFn = WrapperFunctionsMap[Fn];
- assert(WFn && "Wrapper function does not exist!");
- llvm::Value *ID = Bld.CreateBitOrPointerCast(WFn, CGM.Int8PtrTy);
-
- // Prepare for parallel region. Indicate the outlined function.
- llvm::Value *Args[] = {ID, /*RequiresOMPRuntime=*/Bld.getInt16(1)};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_prepare_parallel),
- Args);
-
- // Create a private scope that will globalize the arguments
- // passed from the outside of the target region.
- CodeGenFunction::OMPPrivateScope PrivateArgScope(CGF);
-
- // There's something to share.
- if (!CapturedVars.empty()) {
- // Prepare for parallel region. Indicate the outlined function.
- Address SharedArgs =
- CGF.CreateDefaultAlignTempAlloca(CGF.VoidPtrPtrTy, "shared_arg_refs");
- llvm::Value *SharedArgsPtr = SharedArgs.getPointer();
-
- llvm::Value *DataSharingArgs[] = {
- SharedArgsPtr,
- llvm::ConstantInt::get(CGM.SizeTy, CapturedVars.size())};
- CGF.EmitRuntimeCall(createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_begin_sharing_variables),
- DataSharingArgs);
-
- // Store variable address in a list of references to pass to workers.
- unsigned Idx = 0;
- ASTContext &Ctx = CGF.getContext();
- Address SharedArgListAddress = CGF.EmitLoadOfPointer(
- SharedArgs, Ctx.getPointerType(Ctx.getPointerType(Ctx.VoidPtrTy))
- .castAs<PointerType>());
- for (llvm::Value *V : CapturedVars) {
- Address Dst = Bld.CreateConstInBoundsGEP(SharedArgListAddress, Idx,
- CGF.getPointerSize());
- llvm::Value *PtrV;
- if (V->getType()->isIntegerTy())
- PtrV = Bld.CreateIntToPtr(V, CGF.VoidPtrTy);
- else
- PtrV = Bld.CreatePointerBitCastOrAddrSpaceCast(V, CGF.VoidPtrTy);
- CGF.EmitStoreOfScalar(PtrV, Dst, /*Volatile=*/false,
- Ctx.getPointerType(Ctx.VoidPtrTy));
- ++Idx;
- }
- }
-
- // Activate workers. This barrier is used by the master to signal
- // work for the workers.
- syncCTAThreads(CGF);
-
- // OpenMP [2.5, Parallel Construct, p.49]
- // There is an implied barrier at the end of a parallel region. After the
- // end of a parallel region, only the master thread of the team resumes
- // execution of the enclosing task region.
- //
- // The master waits at this barrier until all workers are done.
- syncCTAThreads(CGF);
-
- if (!CapturedVars.empty())
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_end_sharing_variables));
-
- // Remember for post-processing in worker loop.
- Work.emplace_back(WFn);
- };
-
- auto &&LNParallelGen = [this, Loc, &SeqGen, &L0ParallelGen](
- CodeGenFunction &CGF, PrePostActionTy &Action) {
- if (IsInParallelRegion) {
- SeqGen(CGF, Action);
- } else if (IsInTargetMasterThreadRegion) {
- L0ParallelGen(CGF, Action);
- } else {
- // Check for master and then parallelism:
- // if (__kmpc_is_spmd_exec_mode() || __kmpc_parallel_level(loc, gtid)) {
- // Serialized execution.
- // } else {
- // Worker call.
- // }
- CGBuilderTy &Bld = CGF.Builder;
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".exit");
- llvm::BasicBlock *SeqBB = CGF.createBasicBlock(".sequential");
- llvm::BasicBlock *ParallelCheckBB = CGF.createBasicBlock(".parcheck");
- llvm::BasicBlock *MasterBB = CGF.createBasicBlock(".master");
- llvm::Value *IsSPMD = Bld.CreateIsNotNull(CGF.EmitNounwindRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_is_spmd_exec_mode)));
- Bld.CreateCondBr(IsSPMD, SeqBB, ParallelCheckBB);
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(ParallelCheckBB);
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- llvm::Value *ThreadID = getThreadID(CGF, Loc);
- llvm::Value *PL = CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_parallel_level),
- {RTLoc, ThreadID});
- llvm::Value *Res = Bld.CreateIsNotNull(PL);
- Bld.CreateCondBr(Res, SeqBB, MasterBB);
- CGF.EmitBlock(SeqBB);
- SeqGen(CGF, Action);
- CGF.EmitBranch(ExitBB);
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(MasterBB);
- L0ParallelGen(CGF, Action);
- CGF.EmitBranch(ExitBB);
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- // Emit the continuation block for code after the if.
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
- }
- };
-
- if (IfCond) {
- emitOMPIfClause(CGF, IfCond, LNParallelGen, SeqGen);
- } else {
- CodeGenFunction::RunCleanupsScope Scope(CGF);
- RegionCodeGenTy ThenRCG(LNParallelGen);
- ThenRCG(CGF);
- }
-}
-
-void CGOpenMPRuntimeNVPTX::emitSPMDParallelCall(
- CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond) {
- // Just call the outlined function to execute the parallel region.
- // OutlinedFn(&GTid, &zero, CapturedStruct);
- //
- llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
-
- Address ZeroAddr = CGF.CreateMemTemp(CGF.getContext().getIntTypeForBitwidth(
- /*DestWidth=*/32, /*Signed=*/1),
- ".zero.addr");
- CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
- // ThreadId for serialized parallels is 0.
- Address ThreadIDAddr = ZeroAddr;
- auto &&CodeGen = [this, OutlinedFn, CapturedVars, Loc, ZeroAddr,
- &ThreadIDAddr](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
-
- llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
- OutlinedFnArgs.push_back(ThreadIDAddr.getPointer());
- OutlinedFnArgs.push_back(ZeroAddr.getPointer());
- OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
- };
- auto &&SeqGen = [this, &CodeGen, Loc](CodeGenFunction &CGF,
- PrePostActionTy &) {
-
- RegionCodeGenTy RCG(CodeGen);
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- llvm::Value *ThreadID = getThreadID(CGF, Loc);
- llvm::Value *Args[] = {RTLoc, ThreadID};
-
- NVPTXActionTy Action(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_serialized_parallel),
- Args,
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_end_serialized_parallel),
- Args);
- RCG.setAction(Action);
- RCG(CGF);
- };
-
- if (IsInTargetMasterThreadRegion) {
- // In the worker need to use the real thread id.
- ThreadIDAddr = emitThreadIDAddress(CGF, Loc);
- RegionCodeGenTy RCG(CodeGen);
- RCG(CGF);
- } else {
- // If we are not in the target region, it is definitely L2 parallelism or
- // more, because for SPMD mode we always has L1 parallel level, sowe don't
- // need to check for orphaned directives.
- RegionCodeGenTy RCG(SeqGen);
- RCG(CGF);
- }
-}
-
-void CGOpenMPRuntimeNVPTX::syncCTAThreads(CodeGenFunction &CGF) {
- // Always emit simple barriers!
- if (!CGF.HaveInsertPoint())
- return;
- // Build call __kmpc_barrier_simple_spmd(nullptr, 0);
- // This function does not use parameters, so we can emit just default values.
- llvm::Value *Args[] = {
- llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(getIdentTyPointerTy())),
- llvm::ConstantInt::get(CGF.Int32Ty, /*V=*/0, /*isSigned=*/true)};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL__kmpc_barrier_simple_spmd), Args);
-}
-
-void CGOpenMPRuntimeNVPTX::emitBarrierCall(CodeGenFunction &CGF,
- SourceLocation Loc,
- OpenMPDirectiveKind Kind, bool,
- bool) {
- // Always emit simple barriers!
- if (!CGF.HaveInsertPoint())
- return;
- // Build call __kmpc_cancel_barrier(loc, thread_id);
- unsigned Flags = getDefaultFlagsForBarriers(Kind);
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
- getThreadID(CGF, Loc)};
- CGF.EmitRuntimeCall(createNVPTXRuntimeFunction(OMPRTL__kmpc_barrier), Args);
-}
-
-void CGOpenMPRuntimeNVPTX::emitCriticalRegion(
- CodeGenFunction &CGF, StringRef CriticalName,
- const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc,
- const Expr *Hint) {
- llvm::BasicBlock *LoopBB = CGF.createBasicBlock("omp.critical.loop");
- llvm::BasicBlock *TestBB = CGF.createBasicBlock("omp.critical.test");
- llvm::BasicBlock *SyncBB = CGF.createBasicBlock("omp.critical.sync");
- llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.critical.body");
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock("omp.critical.exit");
-
- // Fetch team-local id of the thread.
- llvm::Value *ThreadID = getNVPTXThreadID(CGF);
-
- // Get the width of the team.
- llvm::Value *TeamWidth = getNVPTXNumThreads(CGF);
-
- // Initialize the counter variable for the loop.
- QualType Int32Ty =
- CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/0);
- Address Counter = CGF.CreateMemTemp(Int32Ty, "critical_counter");
- LValue CounterLVal = CGF.MakeAddrLValue(Counter, Int32Ty);
- CGF.EmitStoreOfScalar(llvm::Constant::getNullValue(CGM.Int32Ty), CounterLVal,
- /*isInit=*/true);
-
- // Block checks if loop counter exceeds upper bound.
- CGF.EmitBlock(LoopBB);
- llvm::Value *CounterVal = CGF.EmitLoadOfScalar(CounterLVal, Loc);
- llvm::Value *CmpLoopBound = CGF.Builder.CreateICmpSLT(CounterVal, TeamWidth);
- CGF.Builder.CreateCondBr(CmpLoopBound, TestBB, ExitBB);
-
- // Block tests which single thread should execute region, and which threads
- // should go straight to synchronisation point.
- CGF.EmitBlock(TestBB);
- CounterVal = CGF.EmitLoadOfScalar(CounterLVal, Loc);
- llvm::Value *CmpThreadToCounter =
- CGF.Builder.CreateICmpEQ(ThreadID, CounterVal);
- CGF.Builder.CreateCondBr(CmpThreadToCounter, BodyBB, SyncBB);
-
- // Block emits the body of the critical region.
- CGF.EmitBlock(BodyBB);
-
- // Output the critical statement.
- CGOpenMPRuntime::emitCriticalRegion(CGF, CriticalName, CriticalOpGen, Loc,
- Hint);
-
- // After the body surrounded by the critical region, the single executing
- // thread will jump to the synchronisation point.
- // Block waits for all threads in current team to finish then increments the
- // counter variable and returns to the loop.
- CGF.EmitBlock(SyncBB);
- emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
-
- llvm::Value *IncCounterVal =
- CGF.Builder.CreateNSWAdd(CounterVal, CGF.Builder.getInt32(1));
- CGF.EmitStoreOfScalar(IncCounterVal, CounterLVal);
- CGF.EmitBranch(LoopBB);
-
- // Block that is reached when all threads in the team complete the region.
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
-}
-
-/// Cast value to the specified type.
-static llvm::Value *castValueToType(CodeGenFunction &CGF, llvm::Value *Val,
- QualType ValTy, QualType CastTy,
- SourceLocation Loc) {
- assert(!CGF.getContext().getTypeSizeInChars(CastTy).isZero() &&
- "Cast type must sized.");
- assert(!CGF.getContext().getTypeSizeInChars(ValTy).isZero() &&
- "Val type must sized.");
- llvm::Type *LLVMCastTy = CGF.ConvertTypeForMem(CastTy);
- if (ValTy == CastTy)
- return Val;
- if (CGF.getContext().getTypeSizeInChars(ValTy) ==
- CGF.getContext().getTypeSizeInChars(CastTy))
- return CGF.Builder.CreateBitCast(Val, LLVMCastTy);
- if (CastTy->isIntegerType() && ValTy->isIntegerType())
- return CGF.Builder.CreateIntCast(Val, LLVMCastTy,
- CastTy->hasSignedIntegerRepresentation());
- Address CastItem = CGF.CreateMemTemp(CastTy);
- Address ValCastItem = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CastItem, Val->getType()->getPointerTo(CastItem.getAddressSpace()));
- CGF.EmitStoreOfScalar(Val, ValCastItem, /*Volatile=*/false, ValTy);
- return CGF.EmitLoadOfScalar(CastItem, /*Volatile=*/false, CastTy, Loc);
-}
-
-/// This function creates calls to one of two shuffle functions to copy
-/// variables between lanes in a warp.
-static llvm::Value *createRuntimeShuffleFunction(CodeGenFunction &CGF,
- llvm::Value *Elem,
- QualType ElemType,
- llvm::Value *Offset,
- SourceLocation Loc) {
- CodeGenModule &CGM = CGF.CGM;
- CGBuilderTy &Bld = CGF.Builder;
- CGOpenMPRuntimeNVPTX &RT =
- *(static_cast<CGOpenMPRuntimeNVPTX *>(&CGM.getOpenMPRuntime()));
-
- CharUnits Size = CGF.getContext().getTypeSizeInChars(ElemType);
- assert(Size.getQuantity() <= 8 &&
- "Unsupported bitwidth in shuffle instruction.");
-
- OpenMPRTLFunctionNVPTX ShuffleFn = Size.getQuantity() <= 4
- ? OMPRTL_NVPTX__kmpc_shuffle_int32
- : OMPRTL_NVPTX__kmpc_shuffle_int64;
-
- // Cast all types to 32- or 64-bit values before calling shuffle routines.
- QualType CastTy = CGF.getContext().getIntTypeForBitwidth(
- Size.getQuantity() <= 4 ? 32 : 64, /*Signed=*/1);
- llvm::Value *ElemCast = castValueToType(CGF, Elem, ElemType, CastTy, Loc);
- llvm::Value *WarpSize =
- Bld.CreateIntCast(getNVPTXWarpSize(CGF), CGM.Int16Ty, /*isSigned=*/true);
-
- llvm::Value *ShuffledVal = CGF.EmitRuntimeCall(
- RT.createNVPTXRuntimeFunction(ShuffleFn), {ElemCast, Offset, WarpSize});
-
- return castValueToType(CGF, ShuffledVal, CastTy, ElemType, Loc);
-}
-
-static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr,
- Address DestAddr, QualType ElemType,
- llvm::Value *Offset, SourceLocation Loc) {
- CGBuilderTy &Bld = CGF.Builder;
-
- CharUnits Size = CGF.getContext().getTypeSizeInChars(ElemType);
- // Create the loop over the big sized data.
- // ptr = (void*)Elem;
- // ptrEnd = (void*) Elem + 1;
- // Step = 8;
- // while (ptr + Step < ptrEnd)
- // shuffle((int64_t)*ptr);
- // Step = 4;
- // while (ptr + Step < ptrEnd)
- // shuffle((int32_t)*ptr);
- // ...
- Address ElemPtr = DestAddr;
- Address Ptr = SrcAddr;
- Address PtrEnd = Bld.CreatePointerBitCastOrAddrSpaceCast(
- Bld.CreateConstGEP(SrcAddr, 1, Size), CGF.VoidPtrTy);
- for (int IntSize = 8; IntSize >= 1; IntSize /= 2) {
- if (Size < CharUnits::fromQuantity(IntSize))
- continue;
- QualType IntType = CGF.getContext().getIntTypeForBitwidth(
- CGF.getContext().toBits(CharUnits::fromQuantity(IntSize)),
- /*Signed=*/1);
- llvm::Type *IntTy = CGF.ConvertTypeForMem(IntType);
- Ptr = Bld.CreatePointerBitCastOrAddrSpaceCast(Ptr, IntTy->getPointerTo());
- ElemPtr =
- Bld.CreatePointerBitCastOrAddrSpaceCast(ElemPtr, IntTy->getPointerTo());
- if (Size.getQuantity() / IntSize > 1) {
- llvm::BasicBlock *PreCondBB = CGF.createBasicBlock(".shuffle.pre_cond");
- llvm::BasicBlock *ThenBB = CGF.createBasicBlock(".shuffle.then");
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".shuffle.exit");
- llvm::BasicBlock *CurrentBB = Bld.GetInsertBlock();
- CGF.EmitBlock(PreCondBB);
- llvm::PHINode *PhiSrc =
- Bld.CreatePHI(Ptr.getType(), /*NumReservedValues=*/2);
- PhiSrc->addIncoming(Ptr.getPointer(), CurrentBB);
- llvm::PHINode *PhiDest =
- Bld.CreatePHI(ElemPtr.getType(), /*NumReservedValues=*/2);
- PhiDest->addIncoming(ElemPtr.getPointer(), CurrentBB);
- Ptr = Address(PhiSrc, Ptr.getAlignment());
- ElemPtr = Address(PhiDest, ElemPtr.getAlignment());
- llvm::Value *PtrDiff = Bld.CreatePtrDiff(
- PtrEnd.getPointer(), Bld.CreatePointerBitCastOrAddrSpaceCast(
- Ptr.getPointer(), CGF.VoidPtrTy));
- Bld.CreateCondBr(Bld.CreateICmpSGT(PtrDiff, Bld.getInt64(IntSize - 1)),
- ThenBB, ExitBB);
- CGF.EmitBlock(ThenBB);
- llvm::Value *Res = createRuntimeShuffleFunction(
- CGF, CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc),
- IntType, Offset, Loc);
- CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType);
- Address LocalPtr =
- Bld.CreateConstGEP(Ptr, 1, CharUnits::fromQuantity(IntSize));
- Address LocalElemPtr =
- Bld.CreateConstGEP(ElemPtr, 1, CharUnits::fromQuantity(IntSize));
- PhiSrc->addIncoming(LocalPtr.getPointer(), ThenBB);
- PhiDest->addIncoming(LocalElemPtr.getPointer(), ThenBB);
- CGF.EmitBranch(PreCondBB);
- CGF.EmitBlock(ExitBB);
- } else {
- llvm::Value *Res = createRuntimeShuffleFunction(
- CGF, CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc),
- IntType, Offset, Loc);
- CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType);
- Ptr = Bld.CreateConstGEP(Ptr, 1, CharUnits::fromQuantity(IntSize));
- ElemPtr =
- Bld.CreateConstGEP(ElemPtr, 1, CharUnits::fromQuantity(IntSize));
- }
- Size = Size % IntSize;
- }
-}
-
-namespace {
-enum CopyAction : unsigned {
- // RemoteLaneToThread: Copy over a Reduce list from a remote lane in
- // the warp using shuffle instructions.
- RemoteLaneToThread,
- // ThreadCopy: Make a copy of a Reduce list on the thread's stack.
- ThreadCopy,
- // ThreadToScratchpad: Copy a team-reduced array to the scratchpad.
- ThreadToScratchpad,
- // ScratchpadToThread: Copy from a scratchpad array in global memory
- // containing team-reduced data to a thread's stack.
- ScratchpadToThread,
-};
-} // namespace
-
-struct CopyOptionsTy {
- llvm::Value *RemoteLaneOffset;
- llvm::Value *ScratchpadIndex;
- llvm::Value *ScratchpadWidth;
-};
-
-/// Emit instructions to copy a Reduce list, which contains partially
-/// aggregated values, in the specified direction.
-static void emitReductionListCopy(
- CopyAction Action, CodeGenFunction &CGF, QualType ReductionArrayTy,
- ArrayRef<const Expr *> Privates, Address SrcBase, Address DestBase,
- CopyOptionsTy CopyOptions = {nullptr, nullptr, nullptr}) {
-
- CodeGenModule &CGM = CGF.CGM;
- ASTContext &C = CGM.getContext();
- CGBuilderTy &Bld = CGF.Builder;
-
- llvm::Value *RemoteLaneOffset = CopyOptions.RemoteLaneOffset;
- llvm::Value *ScratchpadIndex = CopyOptions.ScratchpadIndex;
- llvm::Value *ScratchpadWidth = CopyOptions.ScratchpadWidth;
-
- // Iterates, element-by-element, through the source Reduce list and
- // make a copy.
- unsigned Idx = 0;
- unsigned Size = Privates.size();
- for (const Expr *Private : Privates) {
- Address SrcElementAddr = Address::invalid();
- Address DestElementAddr = Address::invalid();
- Address DestElementPtrAddr = Address::invalid();
- // Should we shuffle in an element from a remote lane?
- bool ShuffleInElement = false;
- // Set to true to update the pointer in the dest Reduce list to a
- // newly created element.
- bool UpdateDestListPtr = false;
- // Increment the src or dest pointer to the scratchpad, for each
- // new element.
- bool IncrScratchpadSrc = false;
- bool IncrScratchpadDest = false;
-
- switch (Action) {
- case RemoteLaneToThread: {
- // Step 1.1: Get the address for the src element in the Reduce list.
- Address SrcElementPtrAddr =
- Bld.CreateConstArrayGEP(SrcBase, Idx, CGF.getPointerSize());
- SrcElementAddr = CGF.EmitLoadOfPointer(
- SrcElementPtrAddr,
- C.getPointerType(Private->getType())->castAs<PointerType>());
-
- // Step 1.2: Create a temporary to store the element in the destination
- // Reduce list.
- DestElementPtrAddr =
- Bld.CreateConstArrayGEP(DestBase, Idx, CGF.getPointerSize());
- DestElementAddr =
- CGF.CreateMemTemp(Private->getType(), ".omp.reduction.element");
- ShuffleInElement = true;
- UpdateDestListPtr = true;
- break;
- }
- case ThreadCopy: {
- // Step 1.1: Get the address for the src element in the Reduce list.
- Address SrcElementPtrAddr =
- Bld.CreateConstArrayGEP(SrcBase, Idx, CGF.getPointerSize());
- SrcElementAddr = CGF.EmitLoadOfPointer(
- SrcElementPtrAddr,
- C.getPointerType(Private->getType())->castAs<PointerType>());
-
- // Step 1.2: Get the address for dest element. The destination
- // element has already been created on the thread's stack.
- DestElementPtrAddr =
- Bld.CreateConstArrayGEP(DestBase, Idx, CGF.getPointerSize());
- DestElementAddr = CGF.EmitLoadOfPointer(
- DestElementPtrAddr,
- C.getPointerType(Private->getType())->castAs<PointerType>());
- break;
- }
- case ThreadToScratchpad: {
- // Step 1.1: Get the address for the src element in the Reduce list.
- Address SrcElementPtrAddr =
- Bld.CreateConstArrayGEP(SrcBase, Idx, CGF.getPointerSize());
- SrcElementAddr = CGF.EmitLoadOfPointer(
- SrcElementPtrAddr,
- C.getPointerType(Private->getType())->castAs<PointerType>());
-
- // Step 1.2: Get the address for dest element:
- // address = base + index * ElementSizeInChars.
- llvm::Value *ElementSizeInChars = CGF.getTypeSize(Private->getType());
- llvm::Value *CurrentOffset =
- Bld.CreateNUWMul(ElementSizeInChars, ScratchpadIndex);
- llvm::Value *ScratchPadElemAbsolutePtrVal =
- Bld.CreateNUWAdd(DestBase.getPointer(), CurrentOffset);
- ScratchPadElemAbsolutePtrVal =
- Bld.CreateIntToPtr(ScratchPadElemAbsolutePtrVal, CGF.VoidPtrTy);
- DestElementAddr = Address(ScratchPadElemAbsolutePtrVal,
- C.getTypeAlignInChars(Private->getType()));
- IncrScratchpadDest = true;
- break;
- }
- case ScratchpadToThread: {
- // Step 1.1: Get the address for the src element in the scratchpad.
- // address = base + index * ElementSizeInChars.
- llvm::Value *ElementSizeInChars = CGF.getTypeSize(Private->getType());
- llvm::Value *CurrentOffset =
- Bld.CreateNUWMul(ElementSizeInChars, ScratchpadIndex);
- llvm::Value *ScratchPadElemAbsolutePtrVal =
- Bld.CreateNUWAdd(SrcBase.getPointer(), CurrentOffset);
- ScratchPadElemAbsolutePtrVal =
- Bld.CreateIntToPtr(ScratchPadElemAbsolutePtrVal, CGF.VoidPtrTy);
- SrcElementAddr = Address(ScratchPadElemAbsolutePtrVal,
- C.getTypeAlignInChars(Private->getType()));
- IncrScratchpadSrc = true;
-
- // Step 1.2: Create a temporary to store the element in the destination
- // Reduce list.
- DestElementPtrAddr =
- Bld.CreateConstArrayGEP(DestBase, Idx, CGF.getPointerSize());
- DestElementAddr =
- CGF.CreateMemTemp(Private->getType(), ".omp.reduction.element");
- UpdateDestListPtr = true;
- break;
- }
- }
-
- // Regardless of src and dest of copy, we emit the load of src
- // element as this is required in all directions
- SrcElementAddr = Bld.CreateElementBitCast(
- SrcElementAddr, CGF.ConvertTypeForMem(Private->getType()));
- DestElementAddr = Bld.CreateElementBitCast(DestElementAddr,
- SrcElementAddr.getElementType());
-
- // Now that all active lanes have read the element in the
- // Reduce list, shuffle over the value from the remote lane.
- if (ShuffleInElement) {
- shuffleAndStore(CGF, SrcElementAddr, DestElementAddr, Private->getType(),
- RemoteLaneOffset, Private->getExprLoc());
- } else {
- if (Private->getType()->isScalarType()) {
- llvm::Value *Elem =
- CGF.EmitLoadOfScalar(SrcElementAddr, /*Volatile=*/false,
- Private->getType(), Private->getExprLoc());
- // Store the source element value to the dest element address.
- CGF.EmitStoreOfScalar(Elem, DestElementAddr, /*Volatile=*/false,
- Private->getType());
- } else {
- CGF.EmitAggregateCopy(
- CGF.MakeAddrLValue(DestElementAddr, Private->getType()),
- CGF.MakeAddrLValue(SrcElementAddr, Private->getType()),
- Private->getType(), AggValueSlot::DoesNotOverlap);
- }
- }
-
- // Step 3.1: Modify reference in dest Reduce list as needed.
- // Modifying the reference in Reduce list to point to the newly
- // created element. The element is live in the current function
- // scope and that of functions it invokes (i.e., reduce_function).
- // RemoteReduceData[i] = (void*)&RemoteElem
- if (UpdateDestListPtr) {
- CGF.EmitStoreOfScalar(Bld.CreatePointerBitCastOrAddrSpaceCast(
- DestElementAddr.getPointer(), CGF.VoidPtrTy),
- DestElementPtrAddr, /*Volatile=*/false,
- C.VoidPtrTy);
- }
-
- // Step 4.1: Increment SrcBase/DestBase so that it points to the starting
- // address of the next element in scratchpad memory, unless we're currently
- // processing the last one. Memory alignment is also taken care of here.
- if ((IncrScratchpadDest || IncrScratchpadSrc) && (Idx + 1 < Size)) {
- llvm::Value *ScratchpadBasePtr =
- IncrScratchpadDest ? DestBase.getPointer() : SrcBase.getPointer();
- llvm::Value *ElementSizeInChars = CGF.getTypeSize(Private->getType());
- ScratchpadBasePtr = Bld.CreateNUWAdd(
- ScratchpadBasePtr,
- Bld.CreateNUWMul(ScratchpadWidth, ElementSizeInChars));
-
- // Take care of global memory alignment for performance
- ScratchpadBasePtr = Bld.CreateNUWSub(
- ScratchpadBasePtr, llvm::ConstantInt::get(CGM.SizeTy, 1));
- ScratchpadBasePtr = Bld.CreateUDiv(
- ScratchpadBasePtr,
- llvm::ConstantInt::get(CGM.SizeTy, GlobalMemoryAlignment));
- ScratchpadBasePtr = Bld.CreateNUWAdd(
- ScratchpadBasePtr, llvm::ConstantInt::get(CGM.SizeTy, 1));
- ScratchpadBasePtr = Bld.CreateNUWMul(
- ScratchpadBasePtr,
- llvm::ConstantInt::get(CGM.SizeTy, GlobalMemoryAlignment));
-
- if (IncrScratchpadDest)
- DestBase = Address(ScratchpadBasePtr, CGF.getPointerAlign());
- else /* IncrScratchpadSrc = true */
- SrcBase = Address(ScratchpadBasePtr, CGF.getPointerAlign());
- }
-
- ++Idx;
- }
-}
-
-/// This function emits a helper that gathers Reduce lists from the first
-/// lane of every active warp to lanes in the first warp.
-///
-/// void inter_warp_copy_func(void* reduce_data, num_warps)
-/// shared smem[warp_size];
-/// For all data entries D in reduce_data:
-/// sync
-/// If (I am the first lane in each warp)
-/// Copy my local D to smem[warp_id]
-/// sync
-/// if (I am the first warp)
-/// Copy smem[thread_id] to my local D
-static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM,
- ArrayRef<const Expr *> Privates,
- QualType ReductionArrayTy,
- SourceLocation Loc) {
- ASTContext &C = CGM.getContext();
- llvm::Module &M = CGM.getModule();
-
- // ReduceList: thread local Reduce list.
- // At the stage of the computation when this function is called, partially
- // aggregated values reside in the first lane of every active warp.
- ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.VoidPtrTy, ImplicitParamDecl::Other);
- // NumWarps: number of warps active in the parallel region. This could
- // be smaller than 32 (max warps in a CTA) for partial block reduction.
- ImplicitParamDecl NumWarpsArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.getIntTypeForBitwidth(32, /* Signed */ true),
- ImplicitParamDecl::Other);
- FunctionArgList Args;
- Args.push_back(&ReduceListArg);
- Args.push_back(&NumWarpsArg);
-
- const CGFunctionInfo &CGFI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- auto *Fn = llvm::Function::Create(
- CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
- "_omp_reduction_inter_warp_copy_func", &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
- Fn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
-
- CGBuilderTy &Bld = CGF.Builder;
-
- // This array is used as a medium to transfer, one reduce element at a time,
- // the data from the first lane of every warp to lanes in the first warp
- // in order to perform the final step of a reduction in a parallel region
- // (reduction across warps). The array is placed in NVPTX __shared__ memory
- // for reduced latency, as well as to have a distinct copy for concurrently
- // executing target regions. The array is declared with common linkage so
- // as to be shared across compilation units.
- StringRef TransferMediumName =
- "__openmp_nvptx_data_transfer_temporary_storage";
- llvm::GlobalVariable *TransferMedium =
- M.getGlobalVariable(TransferMediumName);
- if (!TransferMedium) {
- auto *Ty = llvm::ArrayType::get(CGM.Int32Ty, WarpSize);
- unsigned SharedAddressSpace = C.getTargetAddressSpace(LangAS::cuda_shared);
- TransferMedium = new llvm::GlobalVariable(
- M, Ty, /*isConstant=*/false, llvm::GlobalVariable::CommonLinkage,
- llvm::Constant::getNullValue(Ty), TransferMediumName,
- /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal,
- SharedAddressSpace);
- CGM.addCompilerUsedGlobal(TransferMedium);
- }
-
- // Get the CUDA thread id of the current OpenMP thread on the GPU.
- llvm::Value *ThreadID = getNVPTXThreadID(CGF);
- // nvptx_lane_id = nvptx_id % warpsize
- llvm::Value *LaneID = getNVPTXLaneID(CGF);
- // nvptx_warp_id = nvptx_id / warpsize
- llvm::Value *WarpID = getNVPTXWarpID(CGF);
-
- Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg);
- Address LocalReduceList(
- Bld.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false,
- C.VoidPtrTy, Loc),
- CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo()),
- CGF.getPointerAlign());
-
- unsigned Idx = 0;
- for (const Expr *Private : Privates) {
- //
- // Warp master copies reduce element to transfer medium in __shared__
- // memory.
- //
- unsigned RealTySize =
- C.getTypeSizeInChars(Private->getType())
- .alignTo(C.getTypeAlignInChars(Private->getType()))
- .getQuantity();
- for (unsigned TySize = 4; TySize > 0 && RealTySize > 0; TySize /=2) {
- unsigned NumIters = RealTySize / TySize;
- if (NumIters == 0)
- continue;
- QualType CType = C.getIntTypeForBitwidth(
- C.toBits(CharUnits::fromQuantity(TySize)), /*Signed=*/1);
- llvm::Type *CopyType = CGF.ConvertTypeForMem(CType);
- CharUnits Align = CharUnits::fromQuantity(TySize);
- llvm::Value *Cnt = nullptr;
- Address CntAddr = Address::invalid();
- llvm::BasicBlock *PrecondBB = nullptr;
- llvm::BasicBlock *ExitBB = nullptr;
- if (NumIters > 1) {
- CntAddr = CGF.CreateMemTemp(C.IntTy, ".cnt.addr");
- CGF.EmitStoreOfScalar(llvm::Constant::getNullValue(CGM.IntTy), CntAddr,
- /*Volatile=*/false, C.IntTy);
- PrecondBB = CGF.createBasicBlock("precond");
- ExitBB = CGF.createBasicBlock("exit");
- llvm::BasicBlock *BodyBB = CGF.createBasicBlock("body");
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(PrecondBB);
- Cnt = CGF.EmitLoadOfScalar(CntAddr, /*Volatile=*/false, C.IntTy, Loc);
- llvm::Value *Cmp =
- Bld.CreateICmpULT(Cnt, llvm::ConstantInt::get(CGM.IntTy, NumIters));
- Bld.CreateCondBr(Cmp, BodyBB, ExitBB);
- CGF.EmitBlock(BodyBB);
- }
- // kmpc_barrier.
- CGM.getOpenMPRuntime().emitBarrierCall(CGF, Loc, OMPD_unknown,
- /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
- llvm::BasicBlock *ThenBB = CGF.createBasicBlock("then");
- llvm::BasicBlock *ElseBB = CGF.createBasicBlock("else");
- llvm::BasicBlock *MergeBB = CGF.createBasicBlock("ifcont");
-
- // if (lane_id == 0)
- llvm::Value *IsWarpMaster = Bld.CreateIsNull(LaneID, "warp_master");
- Bld.CreateCondBr(IsWarpMaster, ThenBB, ElseBB);
- CGF.EmitBlock(ThenBB);
-
- // Reduce element = LocalReduceList[i]
- Address ElemPtrPtrAddr =
- Bld.CreateConstArrayGEP(LocalReduceList, Idx, CGF.getPointerSize());
- llvm::Value *ElemPtrPtr = CGF.EmitLoadOfScalar(
- ElemPtrPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
- // elemptr = ((CopyType*)(elemptrptr)) + I
- Address ElemPtr = Address(ElemPtrPtr, Align);
- ElemPtr = Bld.CreateElementBitCast(ElemPtr, CopyType);
- if (NumIters > 1) {
- ElemPtr = Address(Bld.CreateGEP(ElemPtr.getPointer(), Cnt),
- ElemPtr.getAlignment());
- }
-
- // Get pointer to location in transfer medium.
- // MediumPtr = &medium[warp_id]
- llvm::Value *MediumPtrVal = Bld.CreateInBoundsGEP(
- TransferMedium, {llvm::Constant::getNullValue(CGM.Int64Ty), WarpID});
- Address MediumPtr(MediumPtrVal, Align);
- // Casting to actual data type.
- // MediumPtr = (CopyType*)MediumPtrAddr;
- MediumPtr = Bld.CreateElementBitCast(MediumPtr, CopyType);
-
- // elem = *elemptr
- //*MediumPtr = elem
- llvm::Value *Elem =
- CGF.EmitLoadOfScalar(ElemPtr, /*Volatile=*/false, CType, Loc);
- // Store the source element value to the dest element address.
- CGF.EmitStoreOfScalar(Elem, MediumPtr, /*Volatile=*/true, CType);
-
- Bld.CreateBr(MergeBB);
-
- CGF.EmitBlock(ElseBB);
- Bld.CreateBr(MergeBB);
-
- CGF.EmitBlock(MergeBB);
-
- // kmpc_barrier.
- CGM.getOpenMPRuntime().emitBarrierCall(CGF, Loc, OMPD_unknown,
- /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
-
- //
- // Warp 0 copies reduce element from transfer medium.
- //
- llvm::BasicBlock *W0ThenBB = CGF.createBasicBlock("then");
- llvm::BasicBlock *W0ElseBB = CGF.createBasicBlock("else");
- llvm::BasicBlock *W0MergeBB = CGF.createBasicBlock("ifcont");
-
- Address AddrNumWarpsArg = CGF.GetAddrOfLocalVar(&NumWarpsArg);
- llvm::Value *NumWarpsVal = CGF.EmitLoadOfScalar(
- AddrNumWarpsArg, /*Volatile=*/false, C.IntTy, Loc);
-
- // Up to 32 threads in warp 0 are active.
- llvm::Value *IsActiveThread =
- Bld.CreateICmpULT(ThreadID, NumWarpsVal, "is_active_thread");
- Bld.CreateCondBr(IsActiveThread, W0ThenBB, W0ElseBB);
-
- CGF.EmitBlock(W0ThenBB);
-
- // SrcMediumPtr = &medium[tid]
- llvm::Value *SrcMediumPtrVal = Bld.CreateInBoundsGEP(
- TransferMedium,
- {llvm::Constant::getNullValue(CGM.Int64Ty), ThreadID});
- Address SrcMediumPtr(SrcMediumPtrVal, Align);
- // SrcMediumVal = *SrcMediumPtr;
- SrcMediumPtr = Bld.CreateElementBitCast(SrcMediumPtr, CopyType);
-
- // TargetElemPtr = (CopyType*)(SrcDataAddr[i]) + I
- Address TargetElemPtrPtr =
- Bld.CreateConstArrayGEP(LocalReduceList, Idx, CGF.getPointerSize());
- llvm::Value *TargetElemPtrVal = CGF.EmitLoadOfScalar(
- TargetElemPtrPtr, /*Volatile=*/false, C.VoidPtrTy, Loc);
- Address TargetElemPtr = Address(TargetElemPtrVal, Align);
- TargetElemPtr = Bld.CreateElementBitCast(TargetElemPtr, CopyType);
- if (NumIters > 1) {
- TargetElemPtr = Address(Bld.CreateGEP(TargetElemPtr.getPointer(), Cnt),
- TargetElemPtr.getAlignment());
- }
-
- // *TargetElemPtr = SrcMediumVal;
- llvm::Value *SrcMediumValue =
- CGF.EmitLoadOfScalar(SrcMediumPtr, /*Volatile=*/true, CType, Loc);
- CGF.EmitStoreOfScalar(SrcMediumValue, TargetElemPtr, /*Volatile=*/false,
- CType);
- Bld.CreateBr(W0MergeBB);
-
- CGF.EmitBlock(W0ElseBB);
- Bld.CreateBr(W0MergeBB);
-
- CGF.EmitBlock(W0MergeBB);
-
- if (NumIters > 1) {
- Cnt = Bld.CreateNSWAdd(Cnt, llvm::ConstantInt::get(CGM.IntTy, /*V=*/1));
- CGF.EmitStoreOfScalar(Cnt, CntAddr, /*Volatile=*/false, C.IntTy);
- CGF.EmitBranch(PrecondBB);
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(ExitBB);
- }
- RealTySize %= TySize;
- }
- ++Idx;
- }
-
- CGF.FinishFunction();
- return Fn;
-}
-
-/// Emit a helper that reduces data across two OpenMP threads (lanes)
-/// in the same warp. It uses shuffle instructions to copy over data from
-/// a remote lane's stack. The reduction algorithm performed is specified
-/// by the fourth parameter.
-///
-/// Algorithm Versions.
-/// Full Warp Reduce (argument value 0):
-/// This algorithm assumes that all 32 lanes are active and gathers
-/// data from these 32 lanes, producing a single resultant value.
-/// Contiguous Partial Warp Reduce (argument value 1):
-/// This algorithm assumes that only a *contiguous* subset of lanes
-/// are active. This happens for the last warp in a parallel region
-/// when the user specified num_threads is not an integer multiple of
-/// 32. This contiguous subset always starts with the zeroth lane.
-/// Partial Warp Reduce (argument value 2):
-/// This algorithm gathers data from any number of lanes at any position.
-/// All reduced values are stored in the lowest possible lane. The set
-/// of problems every algorithm addresses is a super set of those
-/// addressable by algorithms with a lower version number. Overhead
-/// increases as algorithm version increases.
-///
-/// Terminology
-/// Reduce element:
-/// Reduce element refers to the individual data field with primitive
-/// data types to be combined and reduced across threads.
-/// Reduce list:
-/// Reduce list refers to a collection of local, thread-private
-/// reduce elements.
-/// Remote Reduce list:
-/// Remote Reduce list refers to a collection of remote (relative to
-/// the current thread) reduce elements.
-///
-/// We distinguish between three states of threads that are important to
-/// the implementation of this function.
-/// Alive threads:
-/// Threads in a warp executing the SIMT instruction, as distinguished from
-/// threads that are inactive due to divergent control flow.
-/// Active threads:
-/// The minimal set of threads that has to be alive upon entry to this
-/// function. The computation is correct iff active threads are alive.
-/// Some threads are alive but they are not active because they do not
-/// contribute to the computation in any useful manner. Turning them off
-/// may introduce control flow overheads without any tangible benefits.
-/// Effective threads:
-/// In order to comply with the argument requirements of the shuffle
-/// function, we must keep all lanes holding data alive. But at most
-/// half of them perform value aggregation; we refer to this half of
-/// threads as effective. The other half is simply handing off their
-/// data.
-///
-/// Procedure
-/// Value shuffle:
-/// In this step active threads transfer data from higher lane positions
-/// in the warp to lower lane positions, creating Remote Reduce list.
-/// Value aggregation:
-/// In this step, effective threads combine their thread local Reduce list
-/// with Remote Reduce list and store the result in the thread local
-/// Reduce list.
-/// Value copy:
-/// In this step, we deal with the assumption made by algorithm 2
-/// (i.e. contiguity assumption). When we have an odd number of lanes
-/// active, say 2k+1, only k threads will be effective and therefore k
-/// new values will be produced. However, the Reduce list owned by the
-/// (2k+1)th thread is ignored in the value aggregation. Therefore
-/// we copy the Reduce list from the (2k+1)th lane to (k+1)th lane so
-/// that the contiguity assumption still holds.
-static llvm::Value *emitShuffleAndReduceFunction(
- CodeGenModule &CGM, ArrayRef<const Expr *> Privates,
- QualType ReductionArrayTy, llvm::Value *ReduceFn, SourceLocation Loc) {
- ASTContext &C = CGM.getContext();
-
- // Thread local Reduce list used to host the values of data to be reduced.
- ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.VoidPtrTy, ImplicitParamDecl::Other);
- // Current lane id; could be logical.
- ImplicitParamDecl LaneIDArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.ShortTy,
- ImplicitParamDecl::Other);
- // Offset of the remote source lane relative to the current lane.
- ImplicitParamDecl RemoteLaneOffsetArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.ShortTy, ImplicitParamDecl::Other);
- // Algorithm version. This is expected to be known at compile time.
- ImplicitParamDecl AlgoVerArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.ShortTy, ImplicitParamDecl::Other);
- FunctionArgList Args;
- Args.push_back(&ReduceListArg);
- Args.push_back(&LaneIDArg);
- Args.push_back(&RemoteLaneOffsetArg);
- Args.push_back(&AlgoVerArg);
-
- const CGFunctionInfo &CGFI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- auto *Fn = llvm::Function::Create(
- CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
- "_omp_reduction_shuffle_and_reduce_func", &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
- Fn->setDoesNotRecurse();
- CodeGenFunction CGF(CGM);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
-
- CGBuilderTy &Bld = CGF.Builder;
-
- Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg);
- Address LocalReduceList(
- Bld.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false,
- C.VoidPtrTy, SourceLocation()),
- CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo()),
- CGF.getPointerAlign());
-
- Address AddrLaneIDArg = CGF.GetAddrOfLocalVar(&LaneIDArg);
- llvm::Value *LaneIDArgVal = CGF.EmitLoadOfScalar(
- AddrLaneIDArg, /*Volatile=*/false, C.ShortTy, SourceLocation());
-
- Address AddrRemoteLaneOffsetArg = CGF.GetAddrOfLocalVar(&RemoteLaneOffsetArg);
- llvm::Value *RemoteLaneOffsetArgVal = CGF.EmitLoadOfScalar(
- AddrRemoteLaneOffsetArg, /*Volatile=*/false, C.ShortTy, SourceLocation());
-
- Address AddrAlgoVerArg = CGF.GetAddrOfLocalVar(&AlgoVerArg);
- llvm::Value *AlgoVerArgVal = CGF.EmitLoadOfScalar(
- AddrAlgoVerArg, /*Volatile=*/false, C.ShortTy, SourceLocation());
-
- // Create a local thread-private variable to host the Reduce list
- // from a remote lane.
- Address RemoteReduceList =
- CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.remote_reduce_list");
-
- // This loop iterates through the list of reduce elements and copies,
- // element by element, from a remote lane in the warp to RemoteReduceList,
- // hosted on the thread's stack.
- emitReductionListCopy(RemoteLaneToThread, CGF, ReductionArrayTy, Privates,
- LocalReduceList, RemoteReduceList,
- {/*RemoteLaneOffset=*/RemoteLaneOffsetArgVal,
- /*ScratchpadIndex=*/nullptr,
- /*ScratchpadWidth=*/nullptr});
-
- // The actions to be performed on the Remote Reduce list is dependent
- // on the algorithm version.
- //
- // if (AlgoVer==0) || (AlgoVer==1 && (LaneId < Offset)) || (AlgoVer==2 &&
- // LaneId % 2 == 0 && Offset > 0):
- // do the reduction value aggregation
- //
- // The thread local variable Reduce list is mutated in place to host the
- // reduced data, which is the aggregated value produced from local and
- // remote lanes.
- //
- // Note that AlgoVer is expected to be a constant integer known at compile
- // time.
- // When AlgoVer==0, the first conjunction evaluates to true, making
- // the entire predicate true during compile time.
- // When AlgoVer==1, the second conjunction has only the second part to be
- // evaluated during runtime. Other conjunctions evaluates to false
- // during compile time.
- // When AlgoVer==2, the third conjunction has only the second part to be
- // evaluated during runtime. Other conjunctions evaluates to false
- // during compile time.
- llvm::Value *CondAlgo0 = Bld.CreateIsNull(AlgoVerArgVal);
-
- llvm::Value *Algo1 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(1));
- llvm::Value *CondAlgo1 = Bld.CreateAnd(
- Algo1, Bld.CreateICmpULT(LaneIDArgVal, RemoteLaneOffsetArgVal));
-
- llvm::Value *Algo2 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(2));
- llvm::Value *CondAlgo2 = Bld.CreateAnd(
- Algo2, Bld.CreateIsNull(Bld.CreateAnd(LaneIDArgVal, Bld.getInt16(1))));
- CondAlgo2 = Bld.CreateAnd(
- CondAlgo2, Bld.CreateICmpSGT(RemoteLaneOffsetArgVal, Bld.getInt16(0)));
-
- llvm::Value *CondReduce = Bld.CreateOr(CondAlgo0, CondAlgo1);
- CondReduce = Bld.CreateOr(CondReduce, CondAlgo2);
-
- llvm::BasicBlock *ThenBB = CGF.createBasicBlock("then");
- llvm::BasicBlock *ElseBB = CGF.createBasicBlock("else");
- llvm::BasicBlock *MergeBB = CGF.createBasicBlock("ifcont");
- Bld.CreateCondBr(CondReduce, ThenBB, ElseBB);
-
- CGF.EmitBlock(ThenBB);
- // reduce_function(LocalReduceList, RemoteReduceList)
- llvm::Value *LocalReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast(
- LocalReduceList.getPointer(), CGF.VoidPtrTy);
- llvm::Value *RemoteReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast(
- RemoteReduceList.getPointer(), CGF.VoidPtrTy);
- CGM.getOpenMPRuntime().emitOutlinedFunctionCall(
- CGF, Loc, ReduceFn, {LocalReduceListPtr, RemoteReduceListPtr});
- Bld.CreateBr(MergeBB);
-
- CGF.EmitBlock(ElseBB);
- Bld.CreateBr(MergeBB);
-
- CGF.EmitBlock(MergeBB);
-
- // if (AlgoVer==1 && (LaneId >= Offset)) copy Remote Reduce list to local
- // Reduce list.
- Algo1 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(1));
- llvm::Value *CondCopy = Bld.CreateAnd(
- Algo1, Bld.CreateICmpUGE(LaneIDArgVal, RemoteLaneOffsetArgVal));
-
- llvm::BasicBlock *CpyThenBB = CGF.createBasicBlock("then");
- llvm::BasicBlock *CpyElseBB = CGF.createBasicBlock("else");
- llvm::BasicBlock *CpyMergeBB = CGF.createBasicBlock("ifcont");
- Bld.CreateCondBr(CondCopy, CpyThenBB, CpyElseBB);
-
- CGF.EmitBlock(CpyThenBB);
- emitReductionListCopy(ThreadCopy, CGF, ReductionArrayTy, Privates,
- RemoteReduceList, LocalReduceList);
- Bld.CreateBr(CpyMergeBB);
-
- CGF.EmitBlock(CpyElseBB);
- Bld.CreateBr(CpyMergeBB);
-
- CGF.EmitBlock(CpyMergeBB);
-
- CGF.FinishFunction();
- return Fn;
-}
-
-///
-/// Design of OpenMP reductions on the GPU
-///
-/// Consider a typical OpenMP program with one or more reduction
-/// clauses:
-///
-/// float foo;
-/// double bar;
-/// #pragma omp target teams distribute parallel for \
-/// reduction(+:foo) reduction(*:bar)
-/// for (int i = 0; i < N; i++) {
-/// foo += A[i]; bar *= B[i];
-/// }
-///
-/// where 'foo' and 'bar' are reduced across all OpenMP threads in
-/// all teams. In our OpenMP implementation on the NVPTX device an
-/// OpenMP team is mapped to a CUDA threadblock and OpenMP threads
-/// within a team are mapped to CUDA threads within a threadblock.
-/// Our goal is to efficiently aggregate values across all OpenMP
-/// threads such that:
-///
-/// - the compiler and runtime are logically concise, and
-/// - the reduction is performed efficiently in a hierarchical
-/// manner as follows: within OpenMP threads in the same warp,
-/// across warps in a threadblock, and finally across teams on
-/// the NVPTX device.
-///
-/// Introduction to Decoupling
-///
-/// We would like to decouple the compiler and the runtime so that the
-/// latter is ignorant of the reduction variables (number, data types)
-/// and the reduction operators. This allows a simpler interface
-/// and implementation while still attaining good performance.
-///
-/// Pseudocode for the aforementioned OpenMP program generated by the
-/// compiler is as follows:
-///
-/// 1. Create private copies of reduction variables on each OpenMP
-/// thread: 'foo_private', 'bar_private'
-/// 2. Each OpenMP thread reduces the chunk of 'A' and 'B' assigned
-/// to it and writes the result in 'foo_private' and 'bar_private'
-/// respectively.
-/// 3. Call the OpenMP runtime on the GPU to reduce within a team
-/// and store the result on the team master:
-///
-/// __kmpc_nvptx_parallel_reduce_nowait_v2(...,
-/// reduceData, shuffleReduceFn, interWarpCpyFn)
-///
-/// where:
-/// struct ReduceData {
-/// double *foo;
-/// double *bar;
-/// } reduceData
-/// reduceData.foo = &foo_private
-/// reduceData.bar = &bar_private
-///
-/// 'shuffleReduceFn' and 'interWarpCpyFn' are pointers to two
-/// auxiliary functions generated by the compiler that operate on
-/// variables of type 'ReduceData'. They aid the runtime perform
-/// algorithmic steps in a data agnostic manner.
-///
-/// 'shuffleReduceFn' is a pointer to a function that reduces data
-/// of type 'ReduceData' across two OpenMP threads (lanes) in the
-/// same warp. It takes the following arguments as input:
-///
-/// a. variable of type 'ReduceData' on the calling lane,
-/// b. its lane_id,
-/// c. an offset relative to the current lane_id to generate a
-/// remote_lane_id. The remote lane contains the second
-/// variable of type 'ReduceData' that is to be reduced.
-/// d. an algorithm version parameter determining which reduction
-/// algorithm to use.
-///
-/// 'shuffleReduceFn' retrieves data from the remote lane using
-/// efficient GPU shuffle intrinsics and reduces, using the
-/// algorithm specified by the 4th parameter, the two operands
-/// element-wise. The result is written to the first operand.
-///
-/// Different reduction algorithms are implemented in different
-/// runtime functions, all calling 'shuffleReduceFn' to perform
-/// the essential reduction step. Therefore, based on the 4th
-/// parameter, this function behaves slightly differently to
-/// cooperate with the runtime to ensure correctness under
-/// different circumstances.
-///
-/// 'InterWarpCpyFn' is a pointer to a function that transfers
-/// reduced variables across warps. It tunnels, through CUDA
-/// shared memory, the thread-private data of type 'ReduceData'
-/// from lane 0 of each warp to a lane in the first warp.
-/// 4. Call the OpenMP runtime on the GPU to reduce across teams.
-/// The last team writes the global reduced value to memory.
-///
-/// ret = __kmpc_nvptx_teams_reduce_nowait(...,
-/// reduceData, shuffleReduceFn, interWarpCpyFn,
-/// scratchpadCopyFn, loadAndReduceFn)
-///
-/// 'scratchpadCopyFn' is a helper that stores reduced
-/// data from the team master to a scratchpad array in
-/// global memory.
-///
-/// 'loadAndReduceFn' is a helper that loads data from
-/// the scratchpad array and reduces it with the input
-/// operand.
-///
-/// These compiler generated functions hide address
-/// calculation and alignment information from the runtime.
-/// 5. if ret == 1:
-/// The team master of the last team stores the reduced
-/// result to the globals in memory.
-/// foo += reduceData.foo; bar *= reduceData.bar
-///
-///
-/// Warp Reduction Algorithms
-///
-/// On the warp level, we have three algorithms implemented in the
-/// OpenMP runtime depending on the number of active lanes:
-///
-/// Full Warp Reduction
-///
-/// The reduce algorithm within a warp where all lanes are active
-/// is implemented in the runtime as follows:
-///
-/// full_warp_reduce(void *reduce_data,
-/// kmp_ShuffleReductFctPtr ShuffleReduceFn) {
-/// for (int offset = WARPSIZE/2; offset > 0; offset /= 2)
-/// ShuffleReduceFn(reduce_data, 0, offset, 0);
-/// }
-///
-/// The algorithm completes in log(2, WARPSIZE) steps.
-///
-/// 'ShuffleReduceFn' is used here with lane_id set to 0 because it is
-/// not used therefore we save instructions by not retrieving lane_id
-/// from the corresponding special registers. The 4th parameter, which
-/// represents the version of the algorithm being used, is set to 0 to
-/// signify full warp reduction.
-///
-/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
-///
-/// #reduce_elem refers to an element in the local lane's data structure
-/// #remote_elem is retrieved from a remote lane
-/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
-/// reduce_elem = reduce_elem REDUCE_OP remote_elem;
-///
-/// Contiguous Partial Warp Reduction
-///
-/// This reduce algorithm is used within a warp where only the first
-/// 'n' (n <= WARPSIZE) lanes are active. It is typically used when the
-/// number of OpenMP threads in a parallel region is not a multiple of
-/// WARPSIZE. The algorithm is implemented in the runtime as follows:
-///
-/// void
-/// contiguous_partial_reduce(void *reduce_data,
-/// kmp_ShuffleReductFctPtr ShuffleReduceFn,
-/// int size, int lane_id) {
-/// int curr_size;
-/// int offset;
-/// curr_size = size;
-/// mask = curr_size/2;
-/// while (offset>0) {
-/// ShuffleReduceFn(reduce_data, lane_id, offset, 1);
-/// curr_size = (curr_size+1)/2;
-/// offset = curr_size/2;
-/// }
-/// }
-///
-/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
-///
-/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
-/// if (lane_id < offset)
-/// reduce_elem = reduce_elem REDUCE_OP remote_elem
-/// else
-/// reduce_elem = remote_elem
-///
-/// This algorithm assumes that the data to be reduced are located in a
-/// contiguous subset of lanes starting from the first. When there is
-/// an odd number of active lanes, the data in the last lane is not
-/// aggregated with any other lane's dat but is instead copied over.
-///
-/// Dispersed Partial Warp Reduction
-///
-/// This algorithm is used within a warp when any discontiguous subset of
-/// lanes are active. It is used to implement the reduction operation
-/// across lanes in an OpenMP simd region or in a nested parallel region.
-///
-/// void
-/// dispersed_partial_reduce(void *reduce_data,
-/// kmp_ShuffleReductFctPtr ShuffleReduceFn) {
-/// int size, remote_id;
-/// int logical_lane_id = number_of_active_lanes_before_me() * 2;
-/// do {
-/// remote_id = next_active_lane_id_right_after_me();
-/// # the above function returns 0 of no active lane
-/// # is present right after the current lane.
-/// size = number_of_active_lanes_in_this_warp();
-/// logical_lane_id /= 2;
-/// ShuffleReduceFn(reduce_data, logical_lane_id,
-/// remote_id-1-threadIdx.x, 2);
-/// } while (logical_lane_id % 2 == 0 && size > 1);
-/// }
-///
-/// There is no assumption made about the initial state of the reduction.
-/// Any number of lanes (>=1) could be active at any position. The reduction
-/// result is returned in the first active lane.
-///
-/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
-///
-/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
-/// if (lane_id % 2 == 0 && offset > 0)
-/// reduce_elem = reduce_elem REDUCE_OP remote_elem
-/// else
-/// reduce_elem = remote_elem
-///
-///
-/// Intra-Team Reduction
-///
-/// This function, as implemented in the runtime call
-/// '__kmpc_nvptx_parallel_reduce_nowait_v2', aggregates data across OpenMP
-/// threads in a team. It first reduces within a warp using the
-/// aforementioned algorithms. We then proceed to gather all such
-/// reduced values at the first warp.
-///
-/// The runtime makes use of the function 'InterWarpCpyFn', which copies
-/// data from each of the "warp master" (zeroth lane of each warp, where
-/// warp-reduced data is held) to the zeroth warp. This step reduces (in
-/// a mathematical sense) the problem of reduction across warp masters in
-/// a block to the problem of warp reduction.
-///
-///
-/// Inter-Team Reduction
-///
-/// Once a team has reduced its data to a single value, it is stored in
-/// a global scratchpad array. Since each team has a distinct slot, this
-/// can be done without locking.
-///
-/// The last team to write to the scratchpad array proceeds to reduce the
-/// scratchpad array. One or more workers in the last team use the helper
-/// 'loadAndReduceDataFn' to load and reduce values from the array, i.e.,
-/// the k'th worker reduces every k'th element.
-///
-/// Finally, a call is made to '__kmpc_nvptx_parallel_reduce_nowait_v2' to
-/// reduce across workers and compute a globally reduced value.
-///
-void CGOpenMPRuntimeNVPTX::emitReduction(
- CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs, ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps, ReductionOptionsTy Options) {
- if (!CGF.HaveInsertPoint())
- return;
-
- bool ParallelReduction = isOpenMPParallelDirective(Options.ReductionKind);
-#ifndef NDEBUG
- bool TeamsReduction = isOpenMPTeamsDirective(Options.ReductionKind);
-#endif
-
- if (Options.SimpleReduction) {
- assert(!TeamsReduction && !ParallelReduction &&
- "Invalid reduction selection in emitReduction.");
- CGOpenMPRuntime::emitReduction(CGF, Loc, Privates, LHSExprs, RHSExprs,
- ReductionOps, Options);
- return;
- }
-
- assert((TeamsReduction || ParallelReduction) &&
- "Invalid reduction selection in emitReduction.");
-
- // Build res = __kmpc_reduce{_nowait}(<gtid>, <n>, sizeof(RedList),
- // RedList, shuffle_reduce_func, interwarp_copy_func);
- // or
- // Build res = __kmpc_reduce_teams_nowait_simple(<loc>, <gtid>, <lck>);
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- llvm::Value *ThreadId = getThreadID(CGF, Loc);
-
- llvm::Value *Res;
- if (ParallelReduction) {
- ASTContext &C = CGM.getContext();
- // 1. Build a list of reduction variables.
- // void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
- auto Size = RHSExprs.size();
- for (const Expr *E : Privates) {
- if (E->getType()->isVariablyModifiedType())
- // Reserve place for array size.
- ++Size;
- }
- llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
- QualType ReductionArrayTy =
- C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- Address ReductionList =
- CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
- auto IPriv = Privates.begin();
- unsigned Idx = 0;
- for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) {
- Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx,
- CGF.getPointerSize());
- CGF.Builder.CreateStore(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy),
- Elem);
- if ((*IPriv)->getType()->isVariablyModifiedType()) {
- // Store array size.
- ++Idx;
- Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx,
- CGF.getPointerSize());
- llvm::Value *Size = CGF.Builder.CreateIntCast(
- CGF.getVLASize(
- CGF.getContext().getAsVariableArrayType((*IPriv)->getType()))
- .NumElts,
- CGF.SizeTy, /*isSigned=*/false);
- CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy),
- Elem);
- }
- }
-
- llvm::Value *ReductionArrayTySize = CGF.getTypeSize(ReductionArrayTy);
- llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- ReductionList.getPointer(), CGF.VoidPtrTy);
- llvm::Value *ReductionFn = emitReductionFunction(
- CGM, Loc, CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo(),
- Privates, LHSExprs, RHSExprs, ReductionOps);
- llvm::Value *ShuffleAndReduceFn = emitShuffleAndReduceFunction(
- CGM, Privates, ReductionArrayTy, ReductionFn, Loc);
- llvm::Value *InterWarpCopyFn =
- emitInterWarpCopyFunction(CGM, Privates, ReductionArrayTy, Loc);
-
- llvm::Value *Args[] = {RTLoc,
- ThreadId,
- CGF.Builder.getInt32(RHSExprs.size()),
- ReductionArrayTySize,
- RL,
- ShuffleAndReduceFn,
- InterWarpCopyFn};
-
- Res = CGF.EmitRuntimeCall(createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_parallel_reduce_nowait_v2),
- Args);
- } else {
- assert(TeamsReduction && "expected teams reduction.");
- std::string Name = getName({"reduction"});
- llvm::Value *Lock = getCriticalRegionLock(Name);
- llvm::Value *Args[] = {RTLoc, ThreadId, Lock};
- Res = CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_nvptx_teams_reduce_nowait_simple),
- Args);
- }
-
- // 5. Build if (res == 1)
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.reduction.done");
- llvm::BasicBlock *ThenBB = CGF.createBasicBlock(".omp.reduction.then");
- llvm::Value *Cond = CGF.Builder.CreateICmpEQ(
- Res, llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1));
- CGF.Builder.CreateCondBr(Cond, ThenBB, ExitBB);
-
- // 6. Build then branch: where we have reduced values in the master
- // thread in each team.
- // __kmpc_end_reduce{_nowait}(<gtid>);
- // break;
- CGF.EmitBlock(ThenBB);
-
- // Add emission of __kmpc_end_reduce{_nowait}(<gtid>);
- auto &&CodeGen = [Privates, LHSExprs, RHSExprs, ReductionOps,
- this](CodeGenFunction &CGF, PrePostActionTy &Action) {
- auto IPriv = Privates.begin();
- auto ILHS = LHSExprs.begin();
- auto IRHS = RHSExprs.begin();
- for (const Expr *E : ReductionOps) {
- emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
- cast<DeclRefExpr>(*IRHS));
- ++IPriv;
- ++ILHS;
- ++IRHS;
- }
- };
- if (ParallelReduction) {
- llvm::Value *EndArgs[] = {ThreadId};
- RegionCodeGenTy RCG(CodeGen);
- NVPTXActionTy Action(
- nullptr, llvm::None,
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_end_reduce_nowait),
- EndArgs);
- RCG.setAction(Action);
- RCG(CGF);
- } else {
- assert(TeamsReduction && "expected teams reduction.");
- llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
- std::string Name = getName({"reduction"});
- llvm::Value *Lock = getCriticalRegionLock(Name);
- llvm::Value *EndArgs[] = {RTLoc, ThreadId, Lock};
- RegionCodeGenTy RCG(CodeGen);
- NVPTXActionTy Action(
- nullptr, llvm::None,
- createNVPTXRuntimeFunction(
- OMPRTL_NVPTX__kmpc_nvptx_teams_end_reduce_nowait_simple),
- EndArgs);
- RCG.setAction(Action);
- RCG(CGF);
- }
- // There is no need to emit line number for unconditional branch.
- (void)ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
-}
-
-const VarDecl *
-CGOpenMPRuntimeNVPTX::translateParameter(const FieldDecl *FD,
- const VarDecl *NativeParam) const {
- if (!NativeParam->getType()->isReferenceType())
- return NativeParam;
- QualType ArgType = NativeParam->getType();
- QualifierCollector QC;
- const Type *NonQualTy = QC.strip(ArgType);
- QualType PointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType();
- if (const auto *Attr = FD->getAttr<OMPCaptureKindAttr>()) {
- if (Attr->getCaptureKind() == OMPC_map) {
- PointeeTy = CGM.getContext().getAddrSpaceQualType(PointeeTy,
- LangAS::opencl_global);
- }
- }
- ArgType = CGM.getContext().getPointerType(PointeeTy);
- QC.addRestrict();
- enum { NVPTX_local_addr = 5 };
- QC.addAddressSpace(getLangASFromTargetAS(NVPTX_local_addr));
- ArgType = QC.apply(CGM.getContext(), ArgType);
- if (isa<ImplicitParamDecl>(NativeParam))
- return ImplicitParamDecl::Create(
- CGM.getContext(), /*DC=*/nullptr, NativeParam->getLocation(),
- NativeParam->getIdentifier(), ArgType, ImplicitParamDecl::Other);
- return ParmVarDecl::Create(
- CGM.getContext(),
- const_cast<DeclContext *>(NativeParam->getDeclContext()),
- NativeParam->getBeginLoc(), NativeParam->getLocation(),
- NativeParam->getIdentifier(), ArgType,
- /*TInfo=*/nullptr, SC_None, /*DefArg=*/nullptr);
-}
-
-Address
-CGOpenMPRuntimeNVPTX::getParameterAddress(CodeGenFunction &CGF,
- const VarDecl *NativeParam,
- const VarDecl *TargetParam) const {
- assert(NativeParam != TargetParam &&
- NativeParam->getType()->isReferenceType() &&
- "Native arg must not be the same as target arg.");
- Address LocalAddr = CGF.GetAddrOfLocalVar(TargetParam);
- QualType NativeParamType = NativeParam->getType();
- QualifierCollector QC;
- const Type *NonQualTy = QC.strip(NativeParamType);
- QualType NativePointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType();
- unsigned NativePointeeAddrSpace =
- CGF.getContext().getTargetAddressSpace(NativePointeeTy);
- QualType TargetTy = TargetParam->getType();
- llvm::Value *TargetAddr = CGF.EmitLoadOfScalar(
- LocalAddr, /*Volatile=*/false, TargetTy, SourceLocation());
- // First cast to generic.
- TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo(
- /*AddrSpace=*/0));
- // Cast from generic to native address space.
- TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo(
- NativePointeeAddrSpace));
- Address NativeParamAddr = CGF.CreateMemTemp(NativeParamType);
- CGF.EmitStoreOfScalar(TargetAddr, NativeParamAddr, /*Volatile=*/false,
- NativeParamType);
- return NativeParamAddr;
-}
-
-void CGOpenMPRuntimeNVPTX::emitOutlinedFunctionCall(
- CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> Args) const {
- SmallVector<llvm::Value *, 4> TargetArgs;
- TargetArgs.reserve(Args.size());
- auto *FnType =
- cast<llvm::FunctionType>(OutlinedFn->getType()->getPointerElementType());
- for (unsigned I = 0, E = Args.size(); I < E; ++I) {
- if (FnType->isVarArg() && FnType->getNumParams() <= I) {
- TargetArgs.append(std::next(Args.begin(), I), Args.end());
- break;
- }
- llvm::Type *TargetType = FnType->getParamType(I);
- llvm::Value *NativeArg = Args[I];
- if (!TargetType->isPointerTy()) {
- TargetArgs.emplace_back(NativeArg);
- continue;
- }
- llvm::Value *TargetArg = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- NativeArg,
- NativeArg->getType()->getPointerElementType()->getPointerTo());
- TargetArgs.emplace_back(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TargetArg, TargetType));
- }
- CGOpenMPRuntime::emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, TargetArgs);
-}
-
-/// Emit function which wraps the outline parallel region
-/// and controls the arguments which are passed to this function.
-/// The wrapper ensures that the outlined function is called
-/// with the correct arguments when data is shared.
-llvm::Function *CGOpenMPRuntimeNVPTX::createParallelDataSharingWrapper(
- llvm::Function *OutlinedParallelFn, const OMPExecutableDirective &D) {
- ASTContext &Ctx = CGM.getContext();
- const auto &CS = *D.getCapturedStmt(OMPD_parallel);
-
- // Create a function that takes as argument the source thread.
- FunctionArgList WrapperArgs;
- QualType Int16QTy =
- Ctx.getIntTypeForBitwidth(/*DestWidth=*/16, /*Signed=*/false);
- QualType Int32QTy =
- Ctx.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false);
- ImplicitParamDecl ParallelLevelArg(Ctx, /*DC=*/nullptr, D.getBeginLoc(),
- /*Id=*/nullptr, Int16QTy,
- ImplicitParamDecl::Other);
- ImplicitParamDecl WrapperArg(Ctx, /*DC=*/nullptr, D.getBeginLoc(),
- /*Id=*/nullptr, Int32QTy,
- ImplicitParamDecl::Other);
- WrapperArgs.emplace_back(&ParallelLevelArg);
- WrapperArgs.emplace_back(&WrapperArg);
-
- const CGFunctionInfo &CGFI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, WrapperArgs);
-
- auto *Fn = llvm::Function::Create(
- CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
- Twine(OutlinedParallelFn->getName(), "_wrapper"), &CGM.getModule());
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
- Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
- Fn->setDoesNotRecurse();
-
- CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
- CGF.StartFunction(GlobalDecl(), Ctx.VoidTy, Fn, CGFI, WrapperArgs,
- D.getBeginLoc(), D.getBeginLoc());
-
- const auto *RD = CS.getCapturedRecordDecl();
- auto CurField = RD->field_begin();
-
- Address ZeroAddr = CGF.CreateMemTemp(
- CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
- /*Name*/ ".zero.addr");
- CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
- // Get the array of arguments.
- SmallVector<llvm::Value *, 8> Args;
-
- Args.emplace_back(CGF.GetAddrOfLocalVar(&WrapperArg).getPointer());
- Args.emplace_back(ZeroAddr.getPointer());
-
- CGBuilderTy &Bld = CGF.Builder;
- auto CI = CS.capture_begin();
-
- // Use global memory for data sharing.
- // Handle passing of global args to workers.
- Address GlobalArgs =
- CGF.CreateDefaultAlignTempAlloca(CGF.VoidPtrPtrTy, "global_args");
- llvm::Value *GlobalArgsPtr = GlobalArgs.getPointer();
- llvm::Value *DataSharingArgs[] = {GlobalArgsPtr};
- CGF.EmitRuntimeCall(
- createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_get_shared_variables),
- DataSharingArgs);
-
- // Retrieve the shared variables from the list of references returned
- // by the runtime. Pass the variables to the outlined function.
- Address SharedArgListAddress = Address::invalid();
- if (CS.capture_size() > 0 ||
- isOpenMPLoopBoundSharingDirective(D.getDirectiveKind())) {
- SharedArgListAddress = CGF.EmitLoadOfPointer(
- GlobalArgs, CGF.getContext()
- .getPointerType(CGF.getContext().getPointerType(
- CGF.getContext().VoidPtrTy))
- .castAs<PointerType>());
- }
- unsigned Idx = 0;
- if (isOpenMPLoopBoundSharingDirective(D.getDirectiveKind())) {
- Address Src = Bld.CreateConstInBoundsGEP(SharedArgListAddress, Idx,
- CGF.getPointerSize());
- Address TypedAddress = Bld.CreatePointerBitCastOrAddrSpaceCast(
- Src, CGF.SizeTy->getPointerTo());
- llvm::Value *LB = CGF.EmitLoadOfScalar(
- TypedAddress,
- /*Volatile=*/false,
- CGF.getContext().getPointerType(CGF.getContext().getSizeType()),
- cast<OMPLoopDirective>(D).getLowerBoundVariable()->getExprLoc());
- Args.emplace_back(LB);
- ++Idx;
- Src = Bld.CreateConstInBoundsGEP(SharedArgListAddress, Idx,
- CGF.getPointerSize());
- TypedAddress = Bld.CreatePointerBitCastOrAddrSpaceCast(
- Src, CGF.SizeTy->getPointerTo());
- llvm::Value *UB = CGF.EmitLoadOfScalar(
- TypedAddress,
- /*Volatile=*/false,
- CGF.getContext().getPointerType(CGF.getContext().getSizeType()),
- cast<OMPLoopDirective>(D).getUpperBoundVariable()->getExprLoc());
- Args.emplace_back(UB);
- ++Idx;
- }
- if (CS.capture_size() > 0) {
- ASTContext &CGFContext = CGF.getContext();
- for (unsigned I = 0, E = CS.capture_size(); I < E; ++I, ++CI, ++CurField) {
- QualType ElemTy = CurField->getType();
- Address Src = Bld.CreateConstInBoundsGEP(SharedArgListAddress, I + Idx,
- CGF.getPointerSize());
- Address TypedAddress = Bld.CreatePointerBitCastOrAddrSpaceCast(
- Src, CGF.ConvertTypeForMem(CGFContext.getPointerType(ElemTy)));
- llvm::Value *Arg = CGF.EmitLoadOfScalar(TypedAddress,
- /*Volatile=*/false,
- CGFContext.getPointerType(ElemTy),
- CI->getLocation());
- if (CI->capturesVariableByCopy() &&
- !CI->getCapturedVar()->getType()->isAnyPointerType()) {
- Arg = castValueToType(CGF, Arg, ElemTy, CGFContext.getUIntPtrType(),
- CI->getLocation());
- }
- Args.emplace_back(Arg);
- }
- }
-
- emitOutlinedFunctionCall(CGF, D.getBeginLoc(), OutlinedParallelFn, Args);
- CGF.FinishFunction();
- return Fn;
-}
-
-void CGOpenMPRuntimeNVPTX::emitFunctionProlog(CodeGenFunction &CGF,
- const Decl *D) {
- if (getDataSharingMode(CGM) != CGOpenMPRuntimeNVPTX::Generic)
- return;
-
- assert(D && "Expected function or captured|block decl.");
- assert(FunctionGlobalizedDecls.count(CGF.CurFn) == 0 &&
- "Function is registered already.");
- assert((!TeamAndReductions.first || TeamAndReductions.first == D) &&
- "Team is set but not processed.");
- const Stmt *Body = nullptr;
- bool NeedToDelayGlobalization = false;
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- Body = FD->getBody();
- } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
- Body = BD->getBody();
- } else if (const auto *CD = dyn_cast<CapturedDecl>(D)) {
- Body = CD->getBody();
- NeedToDelayGlobalization = CGF.CapturedStmtInfo->getKind() == CR_OpenMP;
- if (NeedToDelayGlobalization &&
- getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD)
- return;
- }
- if (!Body)
- return;
- CheckVarsEscapingDeclContext VarChecker(CGF, TeamAndReductions.second);
- VarChecker.Visit(Body);
- const RecordDecl *GlobalizedVarsRecord =
- VarChecker.getGlobalizedRecord(IsInTTDRegion);
- TeamAndReductions.first = nullptr;
- TeamAndReductions.second.clear();
- ArrayRef<const ValueDecl *> EscapedVariableLengthDecls =
- VarChecker.getEscapedVariableLengthDecls();
- if (!GlobalizedVarsRecord && EscapedVariableLengthDecls.empty())
- return;
- auto I = FunctionGlobalizedDecls.try_emplace(CGF.CurFn).first;
- I->getSecond().MappedParams =
- llvm::make_unique<CodeGenFunction::OMPMapVars>();
- I->getSecond().GlobalRecord = GlobalizedVarsRecord;
- I->getSecond().EscapedParameters.insert(
- VarChecker.getEscapedParameters().begin(),
- VarChecker.getEscapedParameters().end());
- I->getSecond().EscapedVariableLengthDecls.append(
- EscapedVariableLengthDecls.begin(), EscapedVariableLengthDecls.end());
- DeclToAddrMapTy &Data = I->getSecond().LocalVarData;
- for (const ValueDecl *VD : VarChecker.getEscapedDecls()) {
- assert(VD->isCanonicalDecl() && "Expected canonical declaration");
- const FieldDecl *FD = VarChecker.getFieldForGlobalizedVar(VD);
- Data.insert(std::make_pair(VD, MappedVarData(FD, IsInTTDRegion)));
- }
- if (!IsInTTDRegion && !NeedToDelayGlobalization && !IsInParallelRegion) {
- CheckVarsEscapingDeclContext VarChecker(CGF, llvm::None);
- VarChecker.Visit(Body);
- I->getSecond().SecondaryGlobalRecord =
- VarChecker.getGlobalizedRecord(/*IsInTTDRegion=*/true);
- I->getSecond().SecondaryLocalVarData.emplace();
- DeclToAddrMapTy &Data = I->getSecond().SecondaryLocalVarData.getValue();
- for (const ValueDecl *VD : VarChecker.getEscapedDecls()) {
- assert(VD->isCanonicalDecl() && "Expected canonical declaration");
- const FieldDecl *FD = VarChecker.getFieldForGlobalizedVar(VD);
- Data.insert(
- std::make_pair(VD, MappedVarData(FD, /*IsInTTDRegion=*/true)));
- }
- }
- if (!NeedToDelayGlobalization) {
- emitGenericVarsProlog(CGF, D->getBeginLoc(), /*WithSPMDCheck=*/true);
- struct GlobalizationScope final : EHScopeStack::Cleanup {
- GlobalizationScope() = default;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- static_cast<CGOpenMPRuntimeNVPTX &>(CGF.CGM.getOpenMPRuntime())
- .emitGenericVarsEpilog(CGF, /*WithSPMDCheck=*/true);
- }
- };
- CGF.EHStack.pushCleanup<GlobalizationScope>(NormalAndEHCleanup);
- }
-}
-
-Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF,
- const VarDecl *VD) {
- if (getDataSharingMode(CGM) != CGOpenMPRuntimeNVPTX::Generic)
- return Address::invalid();
-
- VD = VD->getCanonicalDecl();
- auto I = FunctionGlobalizedDecls.find(CGF.CurFn);
- if (I == FunctionGlobalizedDecls.end())
- return Address::invalid();
- auto VDI = I->getSecond().LocalVarData.find(VD);
- if (VDI != I->getSecond().LocalVarData.end())
- return VDI->second.PrivateAddr;
- if (VD->hasAttrs()) {
- for (specific_attr_iterator<OMPReferencedVarAttr> IT(VD->attr_begin()),
- E(VD->attr_end());
- IT != E; ++IT) {
- auto VDI = I->getSecond().LocalVarData.find(
- cast<VarDecl>(cast<DeclRefExpr>(IT->getRef())->getDecl())
- ->getCanonicalDecl());
- if (VDI != I->getSecond().LocalVarData.end())
- return VDI->second.PrivateAddr;
- }
- }
- return Address::invalid();
-}
-
-void CGOpenMPRuntimeNVPTX::functionFinished(CodeGenFunction &CGF) {
- FunctionGlobalizedDecls.erase(CGF.CurFn);
- CGOpenMPRuntime::functionFinished(CGF);
-}
-
-void CGOpenMPRuntimeNVPTX::getDefaultDistScheduleAndChunk(
- CodeGenFunction &CGF, const OMPLoopDirective &S,
- OpenMPDistScheduleClauseKind &ScheduleKind,
- llvm::Value *&Chunk) const {
- if (getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD) {
- ScheduleKind = OMPC_DIST_SCHEDULE_static;
- Chunk = CGF.EmitScalarConversion(getNVPTXNumThreads(CGF),
- CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
- S.getIterationVariable()->getType(), S.getBeginLoc());
- return;
- }
- CGOpenMPRuntime::getDefaultDistScheduleAndChunk(
- CGF, S, ScheduleKind, Chunk);
-}
-
-void CGOpenMPRuntimeNVPTX::getDefaultScheduleAndChunk(
- CodeGenFunction &CGF, const OMPLoopDirective &S,
- OpenMPScheduleClauseKind &ScheduleKind,
- const Expr *&ChunkExpr) const {
- ScheduleKind = OMPC_SCHEDULE_static;
- // Chunk size is 1 in this case.
- llvm::APInt ChunkSize(32, 1);
- ChunkExpr = IntegerLiteral::Create(CGF.getContext(), ChunkSize,
- CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
- SourceLocation());
-}
-
-void CGOpenMPRuntimeNVPTX::adjustTargetSpecificDataForLambdas(
- CodeGenFunction &CGF, const OMPExecutableDirective &D) const {
- assert(isOpenMPTargetExecutionDirective(D.getDirectiveKind()) &&
- " Expected target-based directive.");
- const CapturedStmt *CS = D.getCapturedStmt(OMPD_target);
- for (const CapturedStmt::Capture &C : CS->captures()) {
- // Capture variables captured by reference in lambdas for target-based
- // directives.
- if (!C.capturesVariable())
- continue;
- const VarDecl *VD = C.getCapturedVar();
- const auto *RD = VD->getType()
- .getCanonicalType()
- .getNonReferenceType()
- ->getAsCXXRecordDecl();
- if (!RD || !RD->isLambda())
- continue;
- Address VDAddr = CGF.GetAddrOfLocalVar(VD);
- LValue VDLVal;
- if (VD->getType().getCanonicalType()->isReferenceType())
- VDLVal = CGF.EmitLoadOfReferenceLValue(VDAddr, VD->getType());
- else
- VDLVal = CGF.MakeAddrLValue(
- VDAddr, VD->getType().getCanonicalType().getNonReferenceType());
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
- FieldDecl *ThisCapture = nullptr;
- RD->getCaptureFields(Captures, ThisCapture);
- if (ThisCapture && CGF.CapturedStmtInfo->isCXXThisExprCaptured()) {
- LValue ThisLVal =
- CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture);
- llvm::Value *CXXThis = CGF.LoadCXXThis();
- CGF.EmitStoreOfScalar(CXXThis, ThisLVal);
- }
- for (const LambdaCapture &LC : RD->captures()) {
- if (LC.getCaptureKind() != LCK_ByRef)
- continue;
- const VarDecl *VD = LC.getCapturedVar();
- if (!CS->capturesVariable(VD))
- continue;
- auto It = Captures.find(VD);
- assert(It != Captures.end() && "Found lambda capture without field.");
- LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
- Address VDAddr = CGF.GetAddrOfLocalVar(VD);
- if (VD->getType().getCanonicalType()->isReferenceType())
- VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr,
- VD->getType().getCanonicalType())
- .getAddress();
- CGF.EmitStoreOfScalar(VDAddr.getPointer(), VarLVal);
- }
- }
-}
-
-// Get current CudaArch and ignore any unknown values
-static CudaArch getCudaArch(CodeGenModule &CGM) {
- if (!CGM.getTarget().hasFeature("ptx"))
- return CudaArch::UNKNOWN;
- llvm::StringMap<bool> Features;
- CGM.getTarget().initFeatureMap(Features, CGM.getDiags(),
- CGM.getTarget().getTargetOpts().CPU,
- CGM.getTarget().getTargetOpts().Features);
- for (const auto &Feature : Features) {
- if (Feature.getValue()) {
- CudaArch Arch = StringToCudaArch(Feature.getKey());
- if (Arch != CudaArch::UNKNOWN)
- return Arch;
- }
- }
- return CudaArch::UNKNOWN;
-}
-
-/// Check to see if target architecture supports unified addressing which is
-/// a restriction for OpenMP requires clause "unified_shared_memory".
-void CGOpenMPRuntimeNVPTX::checkArchForUnifiedAddressing(
- CodeGenModule &CGM, const OMPRequiresDecl *D) const {
- for (const OMPClause *Clause : D->clauselists()) {
- if (Clause->getClauseKind() == OMPC_unified_shared_memory) {
- switch (getCudaArch(CGM)) {
- case CudaArch::SM_20:
- case CudaArch::SM_21:
- case CudaArch::SM_30:
- case CudaArch::SM_32:
- case CudaArch::SM_35:
- case CudaArch::SM_37:
- case CudaArch::SM_50:
- case CudaArch::SM_52:
- case CudaArch::SM_53:
- case CudaArch::SM_60:
- case CudaArch::SM_61:
- case CudaArch::SM_62:
- CGM.Error(Clause->getBeginLoc(),
- "Target architecture does not support unified addressing");
- return;
- case CudaArch::SM_70:
- case CudaArch::SM_72:
- case CudaArch::SM_75:
- case CudaArch::GFX600:
- case CudaArch::GFX601:
- case CudaArch::GFX700:
- case CudaArch::GFX701:
- case CudaArch::GFX702:
- case CudaArch::GFX703:
- case CudaArch::GFX704:
- case CudaArch::GFX801:
- case CudaArch::GFX802:
- case CudaArch::GFX803:
- case CudaArch::GFX810:
- case CudaArch::GFX900:
- case CudaArch::GFX902:
- case CudaArch::GFX904:
- case CudaArch::GFX906:
- case CudaArch::GFX909:
- case CudaArch::UNKNOWN:
- break;
- case CudaArch::LAST:
- llvm_unreachable("Unexpected Cuda arch.");
- }
- }
- }
-}
-
-/// Get number of SMs and number of blocks per SM.
-static std::pair<unsigned, unsigned> getSMsBlocksPerSM(CodeGenModule &CGM) {
- std::pair<unsigned, unsigned> Data;
- if (CGM.getLangOpts().OpenMPCUDANumSMs)
- Data.first = CGM.getLangOpts().OpenMPCUDANumSMs;
- if (CGM.getLangOpts().OpenMPCUDABlocksPerSM)
- Data.second = CGM.getLangOpts().OpenMPCUDABlocksPerSM;
- if (Data.first && Data.second)
- return Data;
- switch (getCudaArch(CGM)) {
- case CudaArch::SM_20:
- case CudaArch::SM_21:
- case CudaArch::SM_30:
- case CudaArch::SM_32:
- case CudaArch::SM_35:
- case CudaArch::SM_37:
- case CudaArch::SM_50:
- case CudaArch::SM_52:
- case CudaArch::SM_53:
- return {16, 16};
- case CudaArch::SM_60:
- case CudaArch::SM_61:
- case CudaArch::SM_62:
- return {56, 32};
- case CudaArch::SM_70:
- case CudaArch::SM_72:
- case CudaArch::SM_75:
- return {84, 32};
- case CudaArch::GFX600:
- case CudaArch::GFX601:
- case CudaArch::GFX700:
- case CudaArch::GFX701:
- case CudaArch::GFX702:
- case CudaArch::GFX703:
- case CudaArch::GFX704:
- case CudaArch::GFX801:
- case CudaArch::GFX802:
- case CudaArch::GFX803:
- case CudaArch::GFX810:
- case CudaArch::GFX900:
- case CudaArch::GFX902:
- case CudaArch::GFX904:
- case CudaArch::GFX906:
- case CudaArch::GFX909:
- case CudaArch::UNKNOWN:
- break;
- case CudaArch::LAST:
- llvm_unreachable("Unexpected Cuda arch.");
- }
- llvm_unreachable("Unexpected NVPTX target without ptx feature.");
-}
-
-void CGOpenMPRuntimeNVPTX::clear() {
- if (!GlobalizedRecords.empty()) {
- ASTContext &C = CGM.getContext();
- llvm::SmallVector<const GlobalPtrSizeRecsTy *, 4> GlobalRecs;
- llvm::SmallVector<const GlobalPtrSizeRecsTy *, 4> SharedRecs;
- RecordDecl *StaticRD = C.buildImplicitRecord(
- "_openmp_static_memory_type_$_", RecordDecl::TagKind::TTK_Union);
- StaticRD->startDefinition();
- RecordDecl *SharedStaticRD = C.buildImplicitRecord(
- "_shared_openmp_static_memory_type_$_", RecordDecl::TagKind::TTK_Union);
- SharedStaticRD->startDefinition();
- for (const GlobalPtrSizeRecsTy &Records : GlobalizedRecords) {
- if (Records.Records.empty())
- continue;
- unsigned Size = 0;
- unsigned RecAlignment = 0;
- for (const RecordDecl *RD : Records.Records) {
- QualType RDTy = C.getRecordType(RD);
- unsigned Alignment = C.getTypeAlignInChars(RDTy).getQuantity();
- RecAlignment = std::max(RecAlignment, Alignment);
- unsigned RecSize = C.getTypeSizeInChars(RDTy).getQuantity();
- Size =
- llvm::alignTo(llvm::alignTo(Size, Alignment) + RecSize, Alignment);
- }
- Size = llvm::alignTo(Size, RecAlignment);
- llvm::APInt ArySize(/*numBits=*/64, Size);
- QualType SubTy = C.getConstantArrayType(
- C.CharTy, ArySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
- const bool UseSharedMemory = Size <= SharedMemorySize;
- auto *Field =
- FieldDecl::Create(C, UseSharedMemory ? SharedStaticRD : StaticRD,
- SourceLocation(), SourceLocation(), nullptr, SubTy,
- C.getTrivialTypeSourceInfo(SubTy, SourceLocation()),
- /*BW=*/nullptr, /*Mutable=*/false,
- /*InitStyle=*/ICIS_NoInit);
- Field->setAccess(AS_public);
- if (UseSharedMemory) {
- SharedStaticRD->addDecl(Field);
- SharedRecs.push_back(&Records);
- } else {
- StaticRD->addDecl(Field);
- GlobalRecs.push_back(&Records);
- }
- Records.RecSize->setInitializer(llvm::ConstantInt::get(CGM.SizeTy, Size));
- Records.UseSharedMemory->setInitializer(
- llvm::ConstantInt::get(CGM.Int16Ty, UseSharedMemory ? 1 : 0));
- }
- // Allocate SharedMemorySize buffer for the shared memory.
- // FIXME: nvlink does not handle weak linkage correctly (object with the
- // different size are reported as erroneous).
- // Restore this code as sson as nvlink is fixed.
- if (!SharedStaticRD->field_empty()) {
- llvm::APInt ArySize(/*numBits=*/64, SharedMemorySize);
- QualType SubTy = C.getConstantArrayType(
- C.CharTy, ArySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
- auto *Field = FieldDecl::Create(
- C, SharedStaticRD, SourceLocation(), SourceLocation(), nullptr, SubTy,
- C.getTrivialTypeSourceInfo(SubTy, SourceLocation()),
- /*BW=*/nullptr, /*Mutable=*/false,
- /*InitStyle=*/ICIS_NoInit);
- Field->setAccess(AS_public);
- SharedStaticRD->addDecl(Field);
- }
- SharedStaticRD->completeDefinition();
- if (!SharedStaticRD->field_empty()) {
- QualType StaticTy = C.getRecordType(SharedStaticRD);
- llvm::Type *LLVMStaticTy = CGM.getTypes().ConvertTypeForMem(StaticTy);
- auto *GV = new llvm::GlobalVariable(
- CGM.getModule(), LLVMStaticTy,
- /*isConstant=*/false, llvm::GlobalValue::CommonLinkage,
- llvm::Constant::getNullValue(LLVMStaticTy),
- "_openmp_shared_static_glob_rd_$_", /*InsertBefore=*/nullptr,
- llvm::GlobalValue::NotThreadLocal,
- C.getTargetAddressSpace(LangAS::cuda_shared));
- auto *Replacement = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
- GV, CGM.VoidPtrTy);
- for (const GlobalPtrSizeRecsTy *Rec : SharedRecs) {
- Rec->Buffer->replaceAllUsesWith(Replacement);
- Rec->Buffer->eraseFromParent();
- }
- }
- StaticRD->completeDefinition();
- if (!StaticRD->field_empty()) {
- QualType StaticTy = C.getRecordType(StaticRD);
- std::pair<unsigned, unsigned> SMsBlockPerSM = getSMsBlocksPerSM(CGM);
- llvm::APInt Size1(32, SMsBlockPerSM.second);
- QualType Arr1Ty =
- C.getConstantArrayType(StaticTy, Size1, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- llvm::APInt Size2(32, SMsBlockPerSM.first);
- QualType Arr2Ty = C.getConstantArrayType(Arr1Ty, Size2, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- llvm::Type *LLVMArr2Ty = CGM.getTypes().ConvertTypeForMem(Arr2Ty);
- auto *GV = new llvm::GlobalVariable(
- CGM.getModule(), LLVMArr2Ty,
- /*isConstant=*/false, llvm::GlobalValue::CommonLinkage,
- llvm::Constant::getNullValue(LLVMArr2Ty),
- "_openmp_static_glob_rd_$_");
- auto *Replacement = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
- GV, CGM.VoidPtrTy);
- for (const GlobalPtrSizeRecsTy *Rec : GlobalRecs) {
- Rec->Buffer->replaceAllUsesWith(Replacement);
- Rec->Buffer->eraseFromParent();
- }
- }
- }
- CGOpenMPRuntime::clear();
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
deleted file mode 100644
index 6091610c37e..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
+++ /dev/null
@@ -1,478 +0,0 @@
-//===----- CGOpenMPRuntimeNVPTX.h - Interface to OpenMP NVPTX Runtimes ----===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides a class for OpenMP runtime code generation specialized to NVPTX
-// targets.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMENVPTX_H
-#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMENVPTX_H
-
-#include "CGOpenMPRuntime.h"
-#include "CodeGenFunction.h"
-#include "clang/AST/StmtOpenMP.h"
-#include "llvm/IR/CallSite.h"
-
-namespace clang {
-namespace CodeGen {
-
-class CGOpenMPRuntimeNVPTX : public CGOpenMPRuntime {
-public:
- /// Defines the execution mode.
- enum ExecutionMode {
- /// SPMD execution mode (all threads are worker threads).
- EM_SPMD,
- /// Non-SPMD execution mode (1 master thread, others are workers).
- EM_NonSPMD,
- /// Unknown execution mode (orphaned directive).
- EM_Unknown,
- };
-private:
- /// Parallel outlined function work for workers to execute.
- llvm::SmallVector<llvm::Function *, 16> Work;
-
- struct EntryFunctionState {
- llvm::BasicBlock *ExitBB = nullptr;
- };
-
- class WorkerFunctionState {
- public:
- llvm::Function *WorkerFn;
- const CGFunctionInfo &CGFI;
- SourceLocation Loc;
-
- WorkerFunctionState(CodeGenModule &CGM, SourceLocation Loc);
-
- private:
- void createWorkerFunction(CodeGenModule &CGM);
- };
-
- ExecutionMode getExecutionMode() const;
-
- bool requiresFullRuntime() const { return RequiresFullRuntime; }
-
- /// Get barrier to synchronize all threads in a block.
- void syncCTAThreads(CodeGenFunction &CGF);
-
- /// Emit the worker function for the current target region.
- void emitWorkerFunction(WorkerFunctionState &WST);
-
- /// Helper for worker function. Emit body of worker loop.
- void emitWorkerLoop(CodeGenFunction &CGF, WorkerFunctionState &WST);
-
- /// Helper for non-SPMD target entry function. Guide the master and
- /// worker threads to their respective locations.
- void emitNonSPMDEntryHeader(CodeGenFunction &CGF, EntryFunctionState &EST,
- WorkerFunctionState &WST);
-
- /// Signal termination of OMP execution for non-SPMD target entry
- /// function.
- void emitNonSPMDEntryFooter(CodeGenFunction &CGF, EntryFunctionState &EST);
-
- /// Helper for generic variables globalization prolog.
- void emitGenericVarsProlog(CodeGenFunction &CGF, SourceLocation Loc,
- bool WithSPMDCheck = false);
-
- /// Helper for generic variables globalization epilog.
- void emitGenericVarsEpilog(CodeGenFunction &CGF, bool WithSPMDCheck = false);
-
- /// Helper for SPMD mode target directive's entry function.
- void emitSPMDEntryHeader(CodeGenFunction &CGF, EntryFunctionState &EST,
- const OMPExecutableDirective &D);
-
- /// Signal termination of SPMD mode execution.
- void emitSPMDEntryFooter(CodeGenFunction &CGF, EntryFunctionState &EST);
-
- //
- // Base class overrides.
- //
-
- /// Creates offloading entry for the provided entry ID \a ID,
- /// address \a Addr, size \a Size, and flags \a Flags.
- void createOffloadEntry(llvm::Constant *ID, llvm::Constant *Addr,
- uint64_t Size, int32_t Flags,
- llvm::GlobalValue::LinkageTypes Linkage) override;
-
- /// Emit outlined function specialized for the Fork-Join
- /// programming model for applicable target directives on the NVPTX device.
- /// \param D Directive to emit.
- /// \param ParentName Name of the function that encloses the target region.
- /// \param OutlinedFn Outlined function value to be defined by this call.
- /// \param OutlinedFnID Outlined function ID value to be defined by this call.
- /// \param IsOffloadEntry True if the outlined function is an offload entry.
- /// An outlined function may not be an entry if, e.g. the if clause always
- /// evaluates to false.
- void emitNonSPMDKernel(const OMPExecutableDirective &D, StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID, bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen);
-
- /// Emit outlined function specialized for the Single Program
- /// Multiple Data programming model for applicable target directives on the
- /// NVPTX device.
- /// \param D Directive to emit.
- /// \param ParentName Name of the function that encloses the target region.
- /// \param OutlinedFn Outlined function value to be defined by this call.
- /// \param OutlinedFnID Outlined function ID value to be defined by this call.
- /// \param IsOffloadEntry True if the outlined function is an offload entry.
- /// \param CodeGen Object containing the target statements.
- /// An outlined function may not be an entry if, e.g. the if clause always
- /// evaluates to false.
- void emitSPMDKernel(const OMPExecutableDirective &D, StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID, bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen);
-
- /// Emit outlined function for 'target' directive on the NVPTX
- /// device.
- /// \param D Directive to emit.
- /// \param ParentName Name of the function that encloses the target region.
- /// \param OutlinedFn Outlined function value to be defined by this call.
- /// \param OutlinedFnID Outlined function ID value to be defined by this call.
- /// \param IsOffloadEntry True if the outlined function is an offload entry.
- /// An outlined function may not be an entry if, e.g. the if clause always
- /// evaluates to false.
- void emitTargetOutlinedFunction(const OMPExecutableDirective &D,
- StringRef ParentName,
- llvm::Function *&OutlinedFn,
- llvm::Constant *&OutlinedFnID,
- bool IsOffloadEntry,
- const RegionCodeGenTy &CodeGen) override;
-
- /// Emits code for parallel or serial call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// This call is for the Non-SPMD Execution Mode.
- /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- /// \param IfCond Condition in the associated 'if' clause, if it was
- /// specified, nullptr otherwise.
- void emitNonSPMDParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars,
- const Expr *IfCond);
-
- /// Emits code for parallel or serial call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// This call is for a parallel directive within an SPMD target directive.
- /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- /// \param IfCond Condition in the associated 'if' clause, if it was
- /// specified, nullptr otherwise.
- ///
- void emitSPMDParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars,
- const Expr *IfCond);
-
-protected:
- /// Get the function name of an outlined region.
- // The name can be customized depending on the target.
- //
- StringRef getOutlinedHelperName() const override {
- return "__omp_outlined__";
- }
-
- /// Check if the default location must be constant.
- /// Constant for NVPTX for better optimization.
- bool isDefaultLocationConstant() const override { return true; }
-
- /// Returns additional flags that can be stored in reserved_2 field of the
- /// default location.
- /// For NVPTX target contains data about SPMD/Non-SPMD execution mode +
- /// Full/Lightweight runtime mode. Used for better optimization.
- unsigned getDefaultLocationReserved2Flags() const override;
-
-public:
- explicit CGOpenMPRuntimeNVPTX(CodeGenModule &CGM);
- void clear() override;
-
- /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
- /// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
- virtual void emitProcBindClause(CodeGenFunction &CGF,
- OpenMPProcBindClauseKind ProcBind,
- SourceLocation Loc) override;
-
- /// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
- /// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
- /// clause.
- /// \param NumThreads An integer value of threads.
- virtual void emitNumThreadsClause(CodeGenFunction &CGF,
- llvm::Value *NumThreads,
- SourceLocation Loc) override;
-
- /// This function ought to emit, in the general case, a call to
- // the openmp runtime kmpc_push_num_teams. In NVPTX backend it is not needed
- // as these numbers are obtained through the PTX grid and block configuration.
- /// \param NumTeams An integer expression of teams.
- /// \param ThreadLimit An integer expression of threads.
- void emitNumTeamsClause(CodeGenFunction &CGF, const Expr *NumTeams,
- const Expr *ThreadLimit, SourceLocation Loc) override;
-
- /// Emits inlined function for the specified OpenMP parallel
- // directive.
- /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
- /// kmp_int32 BoundID, struct context_vars*).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- llvm::Value *
- emitParallelOutlinedFunction(const OMPExecutableDirective &D,
- const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) override;
-
- /// Emits inlined function for the specified OpenMP teams
- // directive.
- /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
- /// kmp_int32 BoundID, struct context_vars*).
- /// \param D OpenMP directive.
- /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param InnermostKind Kind of innermost directive (for simple directives it
- /// is a directive itself, for combined - its innermost directive).
- /// \param CodeGen Code generation sequence for the \a D directive.
- llvm::Value *
- emitTeamsOutlinedFunction(const OMPExecutableDirective &D,
- const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) override;
-
- /// Emits code for teams call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// \param OutlinedFn Outlined function to be run by team masters. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- ///
- void emitTeamsCall(CodeGenFunction &CGF, const OMPExecutableDirective &D,
- SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars) override;
-
- /// Emits code for parallel or serial call of the \a OutlinedFn with
- /// variables captured in a record which address is stored in \a
- /// CapturedStruct.
- /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
- /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
- /// \param CapturedVars A pointer to the record with the references to
- /// variables used in \a OutlinedFn function.
- /// \param IfCond Condition in the associated 'if' clause, if it was
- /// specified, nullptr otherwise.
- void emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
- llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> CapturedVars,
- const Expr *IfCond) override;
-
- /// Emit an implicit/explicit barrier for OpenMP threads.
- /// \param Kind Directive for which this implicit barrier call must be
- /// generated. Must be OMPD_barrier for explicit barrier generation.
- /// \param EmitChecks true if need to emit checks for cancellation barriers.
- /// \param ForceSimpleCall true simple barrier call must be emitted, false if
- /// runtime class decides which one to emit (simple or with cancellation
- /// checks).
- ///
- void emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDirectiveKind Kind, bool EmitChecks = true,
- bool ForceSimpleCall = false) override;
-
- /// Emits a critical region.
- /// \param CriticalName Name of the critical region.
- /// \param CriticalOpGen Generator for the statement associated with the given
- /// critical region.
- /// \param Hint Value of the 'hint' clause (optional).
- void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName,
- const RegionCodeGenTy &CriticalOpGen,
- SourceLocation Loc,
- const Expr *Hint = nullptr) override;
-
- /// Emit a code for reduction clause.
- ///
- /// \param Privates List of private copies for original reduction arguments.
- /// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
- /// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
- /// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
- /// or 'operator binop(LHS, RHS)'.
- /// \param Options List of options for reduction codegen:
- /// WithNowait true if parent directive has also nowait clause, false
- /// otherwise.
- /// SimpleReduction Emit reduction operation only. Used for omp simd
- /// directive on the host.
- /// ReductionKind The kind of reduction to perform.
- virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps,
- ReductionOptionsTy Options) override;
-
- /// Returns specified OpenMP runtime function for the current OpenMP
- /// implementation. Specialized for the NVPTX device.
- /// \param Function OpenMP runtime function.
- /// \return Specified function.
- llvm::Constant *createNVPTXRuntimeFunction(unsigned Function);
-
- /// Translates the native parameter of outlined function if this is required
- /// for target.
- /// \param FD Field decl from captured record for the parameter.
- /// \param NativeParam Parameter itself.
- const VarDecl *translateParameter(const FieldDecl *FD,
- const VarDecl *NativeParam) const override;
-
- /// Gets the address of the native argument basing on the address of the
- /// target-specific parameter.
- /// \param NativeParam Parameter itself.
- /// \param TargetParam Corresponding target-specific parameter.
- Address getParameterAddress(CodeGenFunction &CGF, const VarDecl *NativeParam,
- const VarDecl *TargetParam) const override;
-
- /// Emits call of the outlined function with the provided arguments,
- /// translating these arguments to correct target-specific arguments.
- void emitOutlinedFunctionCall(
- CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
- ArrayRef<llvm::Value *> Args = llvm::None) const override;
-
- /// Emits OpenMP-specific function prolog.
- /// Required for device constructs.
- void emitFunctionProlog(CodeGenFunction &CGF, const Decl *D) override;
-
- /// Gets the OpenMP-specific address of the local variable.
- Address getAddressOfLocalVariable(CodeGenFunction &CGF,
- const VarDecl *VD) override;
-
- /// Target codegen is specialized based on two data-sharing modes: CUDA, in
- /// which the local variables are actually global threadlocal, and Generic, in
- /// which the local variables are placed in global memory if they may escape
- /// their declaration context.
- enum DataSharingMode {
- /// CUDA data sharing mode.
- CUDA,
- /// Generic data-sharing mode.
- Generic,
- };
-
- /// Cleans up references to the objects in finished function.
- ///
- void functionFinished(CodeGenFunction &CGF) override;
-
- /// Choose a default value for the dist_schedule clause.
- void getDefaultDistScheduleAndChunk(CodeGenFunction &CGF,
- const OMPLoopDirective &S, OpenMPDistScheduleClauseKind &ScheduleKind,
- llvm::Value *&Chunk) const override;
-
- /// Choose a default value for the schedule clause.
- void getDefaultScheduleAndChunk(CodeGenFunction &CGF,
- const OMPLoopDirective &S, OpenMPScheduleClauseKind &ScheduleKind,
- const Expr *&ChunkExpr) const override;
-
- /// Adjust some parameters for the target-based directives, like addresses of
- /// the variables captured by reference in lambdas.
- void adjustTargetSpecificDataForLambdas(
- CodeGenFunction &CGF, const OMPExecutableDirective &D) const override;
-
- /// Perform check on requires decl to ensure that target architecture
- /// supports unified addressing
- void checkArchForUnifiedAddressing(CodeGenModule &CGM,
- const OMPRequiresDecl *D) const override;
-
-private:
- /// Track the execution mode when codegening directives within a target
- /// region. The appropriate mode (SPMD/NON-SPMD) is set on entry to the
- /// target region and used by containing directives such as 'parallel'
- /// to emit optimized code.
- ExecutionMode CurrentExecutionMode = EM_Unknown;
-
- /// Check if the full runtime is required (default - yes).
- bool RequiresFullRuntime = true;
-
- /// true if we're emitting the code for the target region and next parallel
- /// region is L0 for sure.
- bool IsInTargetMasterThreadRegion = false;
- /// true if currently emitting code for target/teams/distribute region, false
- /// - otherwise.
- bool IsInTTDRegion = false;
- /// true if we're definitely in the parallel region.
- bool IsInParallelRegion = false;
-
- /// Map between an outlined function and its wrapper.
- llvm::DenseMap<llvm::Function *, llvm::Function *> WrapperFunctionsMap;
-
- /// Emit function which wraps the outline parallel region
- /// and controls the parameters which are passed to this function.
- /// The wrapper ensures that the outlined function is called
- /// with the correct arguments when data is shared.
- llvm::Function *createParallelDataSharingWrapper(
- llvm::Function *OutlinedParallelFn, const OMPExecutableDirective &D);
-
- /// The data for the single globalized variable.
- struct MappedVarData {
- /// Corresponding field in the global record.
- const FieldDecl *FD = nullptr;
- /// Corresponding address.
- Address PrivateAddr = Address::invalid();
- /// true, if only one element is required (for latprivates in SPMD mode),
- /// false, if need to create based on the warp-size.
- bool IsOnePerTeam = false;
- MappedVarData() = delete;
- MappedVarData(const FieldDecl *FD, bool IsOnePerTeam = false)
- : FD(FD), IsOnePerTeam(IsOnePerTeam) {}
- };
- /// The map of local variables to their addresses in the global memory.
- using DeclToAddrMapTy = llvm::MapVector<const Decl *, MappedVarData>;
- /// Set of the parameters passed by value escaping OpenMP context.
- using EscapedParamsTy = llvm::SmallPtrSet<const Decl *, 4>;
- struct FunctionData {
- DeclToAddrMapTy LocalVarData;
- llvm::Optional<DeclToAddrMapTy> SecondaryLocalVarData = llvm::None;
- EscapedParamsTy EscapedParameters;
- llvm::SmallVector<const ValueDecl*, 4> EscapedVariableLengthDecls;
- llvm::SmallVector<llvm::Value *, 4> EscapedVariableLengthDeclsAddrs;
- const RecordDecl *GlobalRecord = nullptr;
- llvm::Optional<const RecordDecl *> SecondaryGlobalRecord = llvm::None;
- llvm::Value *GlobalRecordAddr = nullptr;
- llvm::Value *IsInSPMDModeFlag = nullptr;
- std::unique_ptr<CodeGenFunction::OMPMapVars> MappedParams;
- };
- /// Maps the function to the list of the globalized variables with their
- /// addresses.
- llvm::SmallDenseMap<llvm::Function *, FunctionData> FunctionGlobalizedDecls;
- /// List of records for the globalized variables in target/teams/distribute
- /// contexts. Inner records are going to be joined into the single record,
- /// while those resulting records are going to be joined into the single
- /// union. This resulting union (one per CU) is the entry point for the static
- /// memory management runtime functions.
- struct GlobalPtrSizeRecsTy {
- llvm::GlobalVariable *UseSharedMemory = nullptr;
- llvm::GlobalVariable *RecSize = nullptr;
- llvm::GlobalVariable *Buffer = nullptr;
- SourceLocation Loc;
- llvm::SmallVector<const RecordDecl *, 2> Records;
- unsigned RegionCounter = 0;
- };
- llvm::SmallVector<GlobalPtrSizeRecsTy, 8> GlobalizedRecords;
- /// Shared pointer for the global memory in the global memory buffer used for
- /// the given kernel.
- llvm::GlobalVariable *KernelStaticGlobalized = nullptr;
- /// Pair of the Non-SPMD team and all reductions variables in this team
- /// region.
- std::pair<const Decl *, llvm::SmallVector<const ValueDecl *, 4>>
- TeamAndReductions;
-};
-
-} // CodeGen namespace.
-} // clang namespace.
-
-#endif // LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMENVPTX_H
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h b/gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h
deleted file mode 100644
index 41084294ab9..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h
+++ /dev/null
@@ -1,220 +0,0 @@
-//===--- CGRecordLayout.h - LLVM Record Layout Information ------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGRECORDLAYOUT_H
-#define LLVM_CLANG_LIB_CODEGEN_CGRECORDLAYOUT_H
-
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/DerivedTypes.h"
-
-namespace llvm {
- class StructType;
-}
-
-namespace clang {
-namespace CodeGen {
-
-/// Structure with information about how a bitfield should be accessed.
-///
-/// Often we layout a sequence of bitfields as a contiguous sequence of bits.
-/// When the AST record layout does this, we represent it in the LLVM IR's type
-/// as either a sequence of i8 members or a byte array to reserve the number of
-/// bytes touched without forcing any particular alignment beyond the basic
-/// character alignment.
-///
-/// Then accessing a particular bitfield involves converting this byte array
-/// into a single integer of that size (i24 or i40 -- may not be power-of-two
-/// size), loading it, and shifting and masking to extract the particular
-/// subsequence of bits which make up that particular bitfield. This structure
-/// encodes the information used to construct the extraction code sequences.
-/// The CGRecordLayout also has a field index which encodes which byte-sequence
-/// this bitfield falls within. Let's assume the following C struct:
-///
-/// struct S {
-/// char a, b, c;
-/// unsigned bits : 3;
-/// unsigned more_bits : 4;
-/// unsigned still_more_bits : 7;
-/// };
-///
-/// This will end up as the following LLVM type. The first array is the
-/// bitfield, and the second is the padding out to a 4-byte alignmnet.
-///
-/// %t = type { i8, i8, i8, i8, i8, [3 x i8] }
-///
-/// When generating code to access more_bits, we'll generate something
-/// essentially like this:
-///
-/// define i32 @foo(%t* %base) {
-/// %0 = gep %t* %base, i32 0, i32 3
-/// %2 = load i8* %1
-/// %3 = lshr i8 %2, 3
-/// %4 = and i8 %3, 15
-/// %5 = zext i8 %4 to i32
-/// ret i32 %i
-/// }
-///
-struct CGBitFieldInfo {
- /// The offset within a contiguous run of bitfields that are represented as
- /// a single "field" within the LLVM struct type. This offset is in bits.
- unsigned Offset : 16;
-
- /// The total size of the bit-field, in bits.
- unsigned Size : 15;
-
- /// Whether the bit-field is signed.
- unsigned IsSigned : 1;
-
- /// The storage size in bits which should be used when accessing this
- /// bitfield.
- unsigned StorageSize;
-
- /// The offset of the bitfield storage from the start of the struct.
- CharUnits StorageOffset;
-
- CGBitFieldInfo()
- : Offset(), Size(), IsSigned(), StorageSize(), StorageOffset() {}
-
- CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned,
- unsigned StorageSize, CharUnits StorageOffset)
- : Offset(Offset), Size(Size), IsSigned(IsSigned),
- StorageSize(StorageSize), StorageOffset(StorageOffset) {}
-
- void print(raw_ostream &OS) const;
- void dump() const;
-
- /// Given a bit-field decl, build an appropriate helper object for
- /// accessing that field (which is expected to have the given offset and
- /// size).
- static CGBitFieldInfo MakeInfo(class CodeGenTypes &Types,
- const FieldDecl *FD,
- uint64_t Offset, uint64_t Size,
- uint64_t StorageSize,
- CharUnits StorageOffset);
-};
-
-/// CGRecordLayout - This class handles struct and union layout info while
-/// lowering AST types to LLVM types.
-///
-/// These layout objects are only created on demand as IR generation requires.
-class CGRecordLayout {
- friend class CodeGenTypes;
-
- CGRecordLayout(const CGRecordLayout &) = delete;
- void operator=(const CGRecordLayout &) = delete;
-
-private:
- /// The LLVM type corresponding to this record layout; used when
- /// laying it out as a complete object.
- llvm::StructType *CompleteObjectType;
-
- /// The LLVM type for the non-virtual part of this record layout;
- /// used when laying it out as a base subobject.
- llvm::StructType *BaseSubobjectType;
-
- /// Map from (non-bit-field) struct field to the corresponding llvm struct
- /// type field no. This info is populated by record builder.
- llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo;
-
- /// Map from (bit-field) struct field to the corresponding llvm struct type
- /// field no. This info is populated by record builder.
- llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
-
- // FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single
- // map for both virtual and non-virtual bases.
- llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
-
- /// Map from virtual bases to their field index in the complete object.
- llvm::DenseMap<const CXXRecordDecl *, unsigned> CompleteObjectVirtualBases;
-
- /// False if any direct or indirect subobject of this class, when
- /// considered as a complete object, requires a non-zero bitpattern
- /// when zero-initialized.
- bool IsZeroInitializable : 1;
-
- /// False if any direct or indirect subobject of this class, when
- /// considered as a base subobject, requires a non-zero bitpattern
- /// when zero-initialized.
- bool IsZeroInitializableAsBase : 1;
-
-public:
- CGRecordLayout(llvm::StructType *CompleteObjectType,
- llvm::StructType *BaseSubobjectType,
- bool IsZeroInitializable,
- bool IsZeroInitializableAsBase)
- : CompleteObjectType(CompleteObjectType),
- BaseSubobjectType(BaseSubobjectType),
- IsZeroInitializable(IsZeroInitializable),
- IsZeroInitializableAsBase(IsZeroInitializableAsBase) {}
-
- /// Return the "complete object" LLVM type associated with
- /// this record.
- llvm::StructType *getLLVMType() const {
- return CompleteObjectType;
- }
-
- /// Return the "base subobject" LLVM type associated with
- /// this record.
- llvm::StructType *getBaseSubobjectLLVMType() const {
- return BaseSubobjectType;
- }
-
- /// Check whether this struct can be C++ zero-initialized
- /// with a zeroinitializer.
- bool isZeroInitializable() const {
- return IsZeroInitializable;
- }
-
- /// Check whether this struct can be C++ zero-initialized
- /// with a zeroinitializer when considered as a base subobject.
- bool isZeroInitializableAsBase() const {
- return IsZeroInitializableAsBase;
- }
-
- /// Return llvm::StructType element number that corresponds to the
- /// field FD.
- unsigned getLLVMFieldNo(const FieldDecl *FD) const {
- FD = FD->getCanonicalDecl();
- assert(FieldInfo.count(FD) && "Invalid field for record!");
- return FieldInfo.lookup(FD);
- }
-
- unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const {
- assert(NonVirtualBases.count(RD) && "Invalid non-virtual base!");
- return NonVirtualBases.lookup(RD);
- }
-
- /// Return the LLVM field index corresponding to the given
- /// virtual base. Only valid when operating on the complete object.
- unsigned getVirtualBaseIndex(const CXXRecordDecl *base) const {
- assert(CompleteObjectVirtualBases.count(base) && "Invalid virtual base!");
- return CompleteObjectVirtualBases.lookup(base);
- }
-
- /// Return the BitFieldInfo that corresponds to the field FD.
- const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
- FD = FD->getCanonicalDecl();
- assert(FD->isBitField() && "Invalid call for non-bit-field decl!");
- llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator
- it = BitFields.find(FD);
- assert(it != BitFields.end() && "Unable to find bitfield info");
- return it->second;
- }
-
- void print(raw_ostream &OS) const;
- void dump() const;
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
deleted file mode 100644
index c754541ac12..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ /dev/null
@@ -1,897 +0,0 @@
-//===--- CGRecordLayoutBuilder.cpp - CGRecordLayout builder ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Builder implementation for CGRecordLayout objects.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGRecordLayout.h"
-#include "CGCXXABI.h"
-#include "CodeGenTypes.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/CXXInheritance.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Type.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-/// The CGRecordLowering is responsible for lowering an ASTRecordLayout to an
-/// llvm::Type. Some of the lowering is straightforward, some is not. Here we
-/// detail some of the complexities and weirdnesses here.
-/// * LLVM does not have unions - Unions can, in theory be represented by any
-/// llvm::Type with correct size. We choose a field via a specific heuristic
-/// and add padding if necessary.
-/// * LLVM does not have bitfields - Bitfields are collected into contiguous
-/// runs and allocated as a single storage type for the run. ASTRecordLayout
-/// contains enough information to determine where the runs break. Microsoft
-/// and Itanium follow different rules and use different codepaths.
-/// * It is desired that, when possible, bitfields use the appropriate iN type
-/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
-/// i24. This isn't always possible because i24 has storage size of 32 bit
-/// and if it is possible to use that extra byte of padding we must use
-/// [i8 x 3] instead of i24. The function clipTailPadding does this.
-/// C++ examples that require clipping:
-/// struct { int a : 24; char b; }; // a must be clipped, b goes at offset 3
-/// struct A { int a : 24; }; // a must be clipped because a struct like B
-// could exist: struct B : A { char b; }; // b goes at offset 3
-/// * Clang ignores 0 sized bitfields and 0 sized bases but *not* zero sized
-/// fields. The existing asserts suggest that LLVM assumes that *every* field
-/// has an underlying storage type. Therefore empty structures containing
-/// zero sized subobjects such as empty records or zero sized arrays still get
-/// a zero sized (empty struct) storage type.
-/// * Clang reads the complete type rather than the base type when generating
-/// code to access fields. Bitfields in tail position with tail padding may
-/// be clipped in the base class but not the complete class (we may discover
-/// that the tail padding is not used in the complete class.) However,
-/// because LLVM reads from the complete type it can generate incorrect code
-/// if we do not clip the tail padding off of the bitfield in the complete
-/// layout. This introduces a somewhat awkward extra unnecessary clip stage.
-/// The location of the clip is stored internally as a sentinel of type
-/// SCISSOR. If LLVM were updated to read base types (which it probably
-/// should because locations of things such as VBases are bogus in the llvm
-/// type anyway) then we could eliminate the SCISSOR.
-/// * Itanium allows nearly empty primary virtual bases. These bases don't get
-/// get their own storage because they're laid out as part of another base
-/// or at the beginning of the structure. Determining if a VBase actually
-/// gets storage awkwardly involves a walk of all bases.
-/// * VFPtrs and VBPtrs do *not* make a record NotZeroInitializable.
-struct CGRecordLowering {
- // MemberInfo is a helper structure that contains information about a record
- // member. In additional to the standard member types, there exists a
- // sentinel member type that ensures correct rounding.
- struct MemberInfo {
- CharUnits Offset;
- enum InfoKind { VFPtr, VBPtr, Field, Base, VBase, Scissor } Kind;
- llvm::Type *Data;
- union {
- const FieldDecl *FD;
- const CXXRecordDecl *RD;
- };
- MemberInfo(CharUnits Offset, InfoKind Kind, llvm::Type *Data,
- const FieldDecl *FD = nullptr)
- : Offset(Offset), Kind(Kind), Data(Data), FD(FD) {}
- MemberInfo(CharUnits Offset, InfoKind Kind, llvm::Type *Data,
- const CXXRecordDecl *RD)
- : Offset(Offset), Kind(Kind), Data(Data), RD(RD) {}
- // MemberInfos are sorted so we define a < operator.
- bool operator <(const MemberInfo& a) const { return Offset < a.Offset; }
- };
- // The constructor.
- CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed);
- // Short helper routines.
- /// Constructs a MemberInfo instance from an offset and llvm::Type *.
- MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
- return MemberInfo(Offset, MemberInfo::Field, Data);
- }
-
- /// The Microsoft bitfield layout rule allocates discrete storage
- /// units of the field's formal type and only combines adjacent
- /// fields of the same formal type. We want to emit a layout with
- /// these discrete storage units instead of combining them into a
- /// continuous run.
- bool isDiscreteBitFieldABI() {
- return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
- D->isMsStruct(Context);
- }
-
- /// The Itanium base layout rule allows virtual bases to overlap
- /// other bases, which complicates layout in specific ways.
- ///
- /// Note specifically that the ms_struct attribute doesn't change this.
- bool isOverlappingVBaseABI() {
- return !Context.getTargetInfo().getCXXABI().isMicrosoft();
- }
-
- /// Wraps llvm::Type::getIntNTy with some implicit arguments.
- llvm::Type *getIntNType(uint64_t NumBits) {
- return llvm::Type::getIntNTy(Types.getLLVMContext(),
- (unsigned)llvm::alignTo(NumBits, 8));
- }
- /// Gets an llvm type of size NumBytes and alignment 1.
- llvm::Type *getByteArrayType(CharUnits NumBytes) {
- assert(!NumBytes.isZero() && "Empty byte arrays aren't allowed.");
- llvm::Type *Type = llvm::Type::getInt8Ty(Types.getLLVMContext());
- return NumBytes == CharUnits::One() ? Type :
- (llvm::Type *)llvm::ArrayType::get(Type, NumBytes.getQuantity());
- }
- /// Gets the storage type for a field decl and handles storage
- /// for itanium bitfields that are smaller than their declared type.
- llvm::Type *getStorageType(const FieldDecl *FD) {
- llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
- if (!FD->isBitField()) return Type;
- if (isDiscreteBitFieldABI()) return Type;
- return getIntNType(std::min(FD->getBitWidthValue(Context),
- (unsigned)Context.toBits(getSize(Type))));
- }
- /// Gets the llvm Basesubobject type from a CXXRecordDecl.
- llvm::Type *getStorageType(const CXXRecordDecl *RD) {
- return Types.getCGRecordLayout(RD).getBaseSubobjectLLVMType();
- }
- CharUnits bitsToCharUnits(uint64_t BitOffset) {
- return Context.toCharUnitsFromBits(BitOffset);
- }
- CharUnits getSize(llvm::Type *Type) {
- return CharUnits::fromQuantity(DataLayout.getTypeAllocSize(Type));
- }
- CharUnits getAlignment(llvm::Type *Type) {
- return CharUnits::fromQuantity(DataLayout.getABITypeAlignment(Type));
- }
- bool isZeroInitializable(const FieldDecl *FD) {
- return Types.isZeroInitializable(FD->getType());
- }
- bool isZeroInitializable(const RecordDecl *RD) {
- return Types.isZeroInitializable(RD);
- }
- void appendPaddingBytes(CharUnits Size) {
- if (!Size.isZero())
- FieldTypes.push_back(getByteArrayType(Size));
- }
- uint64_t getFieldBitOffset(const FieldDecl *FD) {
- return Layout.getFieldOffset(FD->getFieldIndex());
- }
- // Layout routines.
- void setBitFieldInfo(const FieldDecl *FD, CharUnits StartOffset,
- llvm::Type *StorageType);
- /// Lowers an ASTRecordLayout to a llvm type.
- void lower(bool NonVirtualBaseType);
- void lowerUnion();
- void accumulateFields();
- void accumulateBitFields(RecordDecl::field_iterator Field,
- RecordDecl::field_iterator FieldEnd);
- void accumulateBases();
- void accumulateVPtrs();
- void accumulateVBases();
- /// Recursively searches all of the bases to find out if a vbase is
- /// not the primary vbase of some base class.
- bool hasOwnStorage(const CXXRecordDecl *Decl, const CXXRecordDecl *Query);
- void calculateZeroInit();
- /// Lowers bitfield storage types to I8 arrays for bitfields with tail
- /// padding that is or can potentially be used.
- void clipTailPadding();
- /// Determines if we need a packed llvm struct.
- void determinePacked(bool NVBaseType);
- /// Inserts padding everywhere it's needed.
- void insertPadding();
- /// Fills out the structures that are ultimately consumed.
- void fillOutputFields();
- // Input memoization fields.
- CodeGenTypes &Types;
- const ASTContext &Context;
- const RecordDecl *D;
- const CXXRecordDecl *RD;
- const ASTRecordLayout &Layout;
- const llvm::DataLayout &DataLayout;
- // Helpful intermediate data-structures.
- std::vector<MemberInfo> Members;
- // Output fields, consumed by CodeGenTypes::ComputeRecordLayout.
- SmallVector<llvm::Type *, 16> FieldTypes;
- llvm::DenseMap<const FieldDecl *, unsigned> Fields;
- llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
- llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
- llvm::DenseMap<const CXXRecordDecl *, unsigned> VirtualBases;
- bool IsZeroInitializable : 1;
- bool IsZeroInitializableAsBase : 1;
- bool Packed : 1;
-private:
- CGRecordLowering(const CGRecordLowering &) = delete;
- void operator =(const CGRecordLowering &) = delete;
-};
-} // namespace {
-
-CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D,
- bool Packed)
- : Types(Types), Context(Types.getContext()), D(D),
- RD(dyn_cast<CXXRecordDecl>(D)),
- Layout(Types.getContext().getASTRecordLayout(D)),
- DataLayout(Types.getDataLayout()), IsZeroInitializable(true),
- IsZeroInitializableAsBase(true), Packed(Packed) {}
-
-void CGRecordLowering::setBitFieldInfo(
- const FieldDecl *FD, CharUnits StartOffset, llvm::Type *StorageType) {
- CGBitFieldInfo &Info = BitFields[FD->getCanonicalDecl()];
- Info.IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
- Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset));
- Info.Size = FD->getBitWidthValue(Context);
- Info.StorageSize = (unsigned)DataLayout.getTypeAllocSizeInBits(StorageType);
- Info.StorageOffset = StartOffset;
- if (Info.Size > Info.StorageSize)
- Info.Size = Info.StorageSize;
- // Reverse the bit offsets for big endian machines. Because we represent
- // a bitfield as a single large integer load, we can imagine the bits
- // counting from the most-significant-bit instead of the
- // least-significant-bit.
- if (DataLayout.isBigEndian())
- Info.Offset = Info.StorageSize - (Info.Offset + Info.Size);
-}
-
-void CGRecordLowering::lower(bool NVBaseType) {
- // The lowering process implemented in this function takes a variety of
- // carefully ordered phases.
- // 1) Store all members (fields and bases) in a list and sort them by offset.
- // 2) Add a 1-byte capstone member at the Size of the structure.
- // 3) Clip bitfield storages members if their tail padding is or might be
- // used by another field or base. The clipping process uses the capstone
- // by treating it as another object that occurs after the record.
- // 4) Determine if the llvm-struct requires packing. It's important that this
- // phase occur after clipping, because clipping changes the llvm type.
- // This phase reads the offset of the capstone when determining packedness
- // and updates the alignment of the capstone to be equal of the alignment
- // of the record after doing so.
- // 5) Insert padding everywhere it is needed. This phase requires 'Packed' to
- // have been computed and needs to know the alignment of the record in
- // order to understand if explicit tail padding is needed.
- // 6) Remove the capstone, we don't need it anymore.
- // 7) Determine if this record can be zero-initialized. This phase could have
- // been placed anywhere after phase 1.
- // 8) Format the complete list of members in a way that can be consumed by
- // CodeGenTypes::ComputeRecordLayout.
- CharUnits Size = NVBaseType ? Layout.getNonVirtualSize() : Layout.getSize();
- if (D->isUnion())
- return lowerUnion();
- accumulateFields();
- // RD implies C++.
- if (RD) {
- accumulateVPtrs();
- accumulateBases();
- if (Members.empty())
- return appendPaddingBytes(Size);
- if (!NVBaseType)
- accumulateVBases();
- }
- std::stable_sort(Members.begin(), Members.end());
- Members.push_back(StorageInfo(Size, getIntNType(8)));
- clipTailPadding();
- determinePacked(NVBaseType);
- insertPadding();
- Members.pop_back();
- calculateZeroInit();
- fillOutputFields();
-}
-
-void CGRecordLowering::lowerUnion() {
- CharUnits LayoutSize = Layout.getSize();
- llvm::Type *StorageType = nullptr;
- bool SeenNamedMember = false;
- // Iterate through the fields setting bitFieldInfo and the Fields array. Also
- // locate the "most appropriate" storage type. The heuristic for finding the
- // storage type isn't necessary, the first (non-0-length-bitfield) field's
- // type would work fine and be simpler but would be different than what we've
- // been doing and cause lit tests to change.
- for (const auto *Field : D->fields()) {
- if (Field->isBitField()) {
- if (Field->isZeroLengthBitField(Context))
- continue;
- llvm::Type *FieldType = getStorageType(Field);
- if (LayoutSize < getSize(FieldType))
- FieldType = getByteArrayType(LayoutSize);
- setBitFieldInfo(Field, CharUnits::Zero(), FieldType);
- }
- Fields[Field->getCanonicalDecl()] = 0;
- llvm::Type *FieldType = getStorageType(Field);
- // Compute zero-initializable status.
- // This union might not be zero initialized: it may contain a pointer to
- // data member which might have some exotic initialization sequence.
- // If this is the case, then we aught not to try and come up with a "better"
- // type, it might not be very easy to come up with a Constant which
- // correctly initializes it.
- if (!SeenNamedMember) {
- SeenNamedMember = Field->getIdentifier();
- if (!SeenNamedMember)
- if (const auto *FieldRD = Field->getType()->getAsRecordDecl())
- SeenNamedMember = FieldRD->findFirstNamedDataMember();
- if (SeenNamedMember && !isZeroInitializable(Field)) {
- IsZeroInitializable = IsZeroInitializableAsBase = false;
- StorageType = FieldType;
- }
- }
- // Because our union isn't zero initializable, we won't be getting a better
- // storage type.
- if (!IsZeroInitializable)
- continue;
- // Conditionally update our storage type if we've got a new "better" one.
- if (!StorageType ||
- getAlignment(FieldType) > getAlignment(StorageType) ||
- (getAlignment(FieldType) == getAlignment(StorageType) &&
- getSize(FieldType) > getSize(StorageType)))
- StorageType = FieldType;
- }
- // If we have no storage type just pad to the appropriate size and return.
- if (!StorageType)
- return appendPaddingBytes(LayoutSize);
- // If our storage size was bigger than our required size (can happen in the
- // case of packed bitfields on Itanium) then just use an I8 array.
- if (LayoutSize < getSize(StorageType))
- StorageType = getByteArrayType(LayoutSize);
- FieldTypes.push_back(StorageType);
- appendPaddingBytes(LayoutSize - getSize(StorageType));
- // Set packed if we need it.
- if (LayoutSize % getAlignment(StorageType))
- Packed = true;
-}
-
-void CGRecordLowering::accumulateFields() {
- for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end();
- Field != FieldEnd;)
- if (Field->isBitField()) {
- RecordDecl::field_iterator Start = Field;
- // Iterate to gather the list of bitfields.
- for (++Field; Field != FieldEnd && Field->isBitField(); ++Field);
- accumulateBitFields(Start, Field);
- } else {
- Members.push_back(MemberInfo(
- bitsToCharUnits(getFieldBitOffset(*Field)), MemberInfo::Field,
- getStorageType(*Field), *Field));
- ++Field;
- }
-}
-
-void
-CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
- RecordDecl::field_iterator FieldEnd) {
- // Run stores the first element of the current run of bitfields. FieldEnd is
- // used as a special value to note that we don't have a current run. A
- // bitfield run is a contiguous collection of bitfields that can be stored in
- // the same storage block. Zero-sized bitfields and bitfields that would
- // cross an alignment boundary break a run and start a new one.
- RecordDecl::field_iterator Run = FieldEnd;
- // Tail is the offset of the first bit off the end of the current run. It's
- // used to determine if the ASTRecordLayout is treating these two bitfields as
- // contiguous. StartBitOffset is offset of the beginning of the Run.
- uint64_t StartBitOffset, Tail = 0;
- if (isDiscreteBitFieldABI()) {
- for (; Field != FieldEnd; ++Field) {
- uint64_t BitOffset = getFieldBitOffset(*Field);
- // Zero-width bitfields end runs.
- if (Field->isZeroLengthBitField(Context)) {
- Run = FieldEnd;
- continue;
- }
- llvm::Type *Type = Types.ConvertTypeForMem(Field->getType());
- // If we don't have a run yet, or don't live within the previous run's
- // allocated storage then we allocate some storage and start a new run.
- if (Run == FieldEnd || BitOffset >= Tail) {
- Run = Field;
- StartBitOffset = BitOffset;
- Tail = StartBitOffset + DataLayout.getTypeAllocSizeInBits(Type);
- // Add the storage member to the record. This must be added to the
- // record before the bitfield members so that it gets laid out before
- // the bitfields it contains get laid out.
- Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type));
- }
- // Bitfields get the offset of their storage but come afterward and remain
- // there after a stable sort.
- Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset),
- MemberInfo::Field, nullptr, *Field));
- }
- return;
- }
-
- // Check if OffsetInRecord is better as a single field run. When OffsetInRecord
- // has legal integer width, and its bitfield offset is naturally aligned, it
- // is better to make the bitfield a separate storage component so as it can be
- // accessed directly with lower cost.
- auto IsBetterAsSingleFieldRun = [&](uint64_t OffsetInRecord,
- uint64_t StartBitOffset) {
- if (!Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
- return false;
- if (!DataLayout.isLegalInteger(OffsetInRecord))
- return false;
- // Make sure StartBitOffset is natually aligned if it is treated as an
- // IType integer.
- if (StartBitOffset %
- Context.toBits(getAlignment(getIntNType(OffsetInRecord))) !=
- 0)
- return false;
- return true;
- };
-
- // The start field is better as a single field run.
- bool StartFieldAsSingleRun = false;
- for (;;) {
- // Check to see if we need to start a new run.
- if (Run == FieldEnd) {
- // If we're out of fields, return.
- if (Field == FieldEnd)
- break;
- // Any non-zero-length bitfield can start a new run.
- if (!Field->isZeroLengthBitField(Context)) {
- Run = Field;
- StartBitOffset = getFieldBitOffset(*Field);
- Tail = StartBitOffset + Field->getBitWidthValue(Context);
- StartFieldAsSingleRun = IsBetterAsSingleFieldRun(Tail - StartBitOffset,
- StartBitOffset);
- }
- ++Field;
- continue;
- }
-
- // If the start field of a new run is better as a single run, or
- // if current field (or consecutive fields) is better as a single run, or
- // if current field has zero width bitfield and either
- // UseZeroLengthBitfieldAlignment or UseBitFieldTypeAlignment is set to
- // true, or
- // if the offset of current field is inconsistent with the offset of
- // previous field plus its offset,
- // skip the block below and go ahead to emit the storage.
- // Otherwise, try to add bitfields to the run.
- if (!StartFieldAsSingleRun && Field != FieldEnd &&
- !IsBetterAsSingleFieldRun(Tail - StartBitOffset, StartBitOffset) &&
- (!Field->isZeroLengthBitField(Context) ||
- (!Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
- !Context.getTargetInfo().useBitFieldTypeAlignment())) &&
- Tail == getFieldBitOffset(*Field)) {
- Tail += Field->getBitWidthValue(Context);
- ++Field;
- continue;
- }
-
- // We've hit a break-point in the run and need to emit a storage field.
- llvm::Type *Type = getIntNType(Tail - StartBitOffset);
- // Add the storage member to the record and set the bitfield info for all of
- // the bitfields in the run. Bitfields get the offset of their storage but
- // come afterward and remain there after a stable sort.
- Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type));
- for (; Run != Field; ++Run)
- Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset),
- MemberInfo::Field, nullptr, *Run));
- Run = FieldEnd;
- StartFieldAsSingleRun = false;
- }
-}
-
-void CGRecordLowering::accumulateBases() {
- // If we've got a primary virtual base, we need to add it with the bases.
- if (Layout.isPrimaryBaseVirtual()) {
- const CXXRecordDecl *BaseDecl = Layout.getPrimaryBase();
- Members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::Base,
- getStorageType(BaseDecl), BaseDecl));
- }
- // Accumulate the non-virtual bases.
- for (const auto &Base : RD->bases()) {
- if (Base.isVirtual())
- continue;
-
- // Bases can be zero-sized even if not technically empty if they
- // contain only a trailing array member.
- const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (!BaseDecl->isEmpty() &&
- !Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
- Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl),
- MemberInfo::Base, getStorageType(BaseDecl), BaseDecl));
- }
-}
-
-void CGRecordLowering::accumulateVPtrs() {
- if (Layout.hasOwnVFPtr())
- Members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::VFPtr,
- llvm::FunctionType::get(getIntNType(32), /*isVarArg=*/true)->
- getPointerTo()->getPointerTo()));
- if (Layout.hasOwnVBPtr())
- Members.push_back(MemberInfo(Layout.getVBPtrOffset(), MemberInfo::VBPtr,
- llvm::Type::getInt32PtrTy(Types.getLLVMContext())));
-}
-
-void CGRecordLowering::accumulateVBases() {
- CharUnits ScissorOffset = Layout.getNonVirtualSize();
- // In the itanium ABI, it's possible to place a vbase at a dsize that is
- // smaller than the nvsize. Here we check to see if such a base is placed
- // before the nvsize and set the scissor offset to that, instead of the
- // nvsize.
- if (isOverlappingVBaseABI())
- for (const auto &Base : RD->vbases()) {
- const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (BaseDecl->isEmpty())
- continue;
- // If the vbase is a primary virtual base of some base, then it doesn't
- // get its own storage location but instead lives inside of that base.
- if (Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl))
- continue;
- ScissorOffset = std::min(ScissorOffset,
- Layout.getVBaseClassOffset(BaseDecl));
- }
- Members.push_back(MemberInfo(ScissorOffset, MemberInfo::Scissor, nullptr,
- RD));
- for (const auto &Base : RD->vbases()) {
- const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (BaseDecl->isEmpty())
- continue;
- CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
- // If the vbase is a primary virtual base of some base, then it doesn't
- // get its own storage location but instead lives inside of that base.
- if (isOverlappingVBaseABI() &&
- Context.isNearlyEmpty(BaseDecl) &&
- !hasOwnStorage(RD, BaseDecl)) {
- Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr,
- BaseDecl));
- continue;
- }
- // If we've got a vtordisp, add it as a storage type.
- if (Layout.getVBaseOffsetsMap().find(BaseDecl)->second.hasVtorDisp())
- Members.push_back(StorageInfo(Offset - CharUnits::fromQuantity(4),
- getIntNType(32)));
- Members.push_back(MemberInfo(Offset, MemberInfo::VBase,
- getStorageType(BaseDecl), BaseDecl));
- }
-}
-
-bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl,
- const CXXRecordDecl *Query) {
- const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl);
- if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query)
- return false;
- for (const auto &Base : Decl->bases())
- if (!hasOwnStorage(Base.getType()->getAsCXXRecordDecl(), Query))
- return false;
- return true;
-}
-
-void CGRecordLowering::calculateZeroInit() {
- for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
- MemberEnd = Members.end();
- IsZeroInitializableAsBase && Member != MemberEnd; ++Member) {
- if (Member->Kind == MemberInfo::Field) {
- if (!Member->FD || isZeroInitializable(Member->FD))
- continue;
- IsZeroInitializable = IsZeroInitializableAsBase = false;
- } else if (Member->Kind == MemberInfo::Base ||
- Member->Kind == MemberInfo::VBase) {
- if (isZeroInitializable(Member->RD))
- continue;
- IsZeroInitializable = false;
- if (Member->Kind == MemberInfo::Base)
- IsZeroInitializableAsBase = false;
- }
- }
-}
-
-void CGRecordLowering::clipTailPadding() {
- std::vector<MemberInfo>::iterator Prior = Members.begin();
- CharUnits Tail = getSize(Prior->Data);
- for (std::vector<MemberInfo>::iterator Member = Prior + 1,
- MemberEnd = Members.end();
- Member != MemberEnd; ++Member) {
- // Only members with data and the scissor can cut into tail padding.
- if (!Member->Data && Member->Kind != MemberInfo::Scissor)
- continue;
- if (Member->Offset < Tail) {
- assert(Prior->Kind == MemberInfo::Field && !Prior->FD &&
- "Only storage fields have tail padding!");
- Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
- cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
- }
- if (Member->Data)
- Prior = Member;
- Tail = Prior->Offset + getSize(Prior->Data);
- }
-}
-
-void CGRecordLowering::determinePacked(bool NVBaseType) {
- if (Packed)
- return;
- CharUnits Alignment = CharUnits::One();
- CharUnits NVAlignment = CharUnits::One();
- CharUnits NVSize =
- !NVBaseType && RD ? Layout.getNonVirtualSize() : CharUnits::Zero();
- for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
- MemberEnd = Members.end();
- Member != MemberEnd; ++Member) {
- if (!Member->Data)
- continue;
- // If any member falls at an offset that it not a multiple of its alignment,
- // then the entire record must be packed.
- if (Member->Offset % getAlignment(Member->Data))
- Packed = true;
- if (Member->Offset < NVSize)
- NVAlignment = std::max(NVAlignment, getAlignment(Member->Data));
- Alignment = std::max(Alignment, getAlignment(Member->Data));
- }
- // If the size of the record (the capstone's offset) is not a multiple of the
- // record's alignment, it must be packed.
- if (Members.back().Offset % Alignment)
- Packed = true;
- // If the non-virtual sub-object is not a multiple of the non-virtual
- // sub-object's alignment, it must be packed. We cannot have a packed
- // non-virtual sub-object and an unpacked complete object or vise versa.
- if (NVSize % NVAlignment)
- Packed = true;
- // Update the alignment of the sentinel.
- if (!Packed)
- Members.back().Data = getIntNType(Context.toBits(Alignment));
-}
-
-void CGRecordLowering::insertPadding() {
- std::vector<std::pair<CharUnits, CharUnits> > Padding;
- CharUnits Size = CharUnits::Zero();
- for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
- MemberEnd = Members.end();
- Member != MemberEnd; ++Member) {
- if (!Member->Data)
- continue;
- CharUnits Offset = Member->Offset;
- assert(Offset >= Size);
- // Insert padding if we need to.
- if (Offset !=
- Size.alignTo(Packed ? CharUnits::One() : getAlignment(Member->Data)))
- Padding.push_back(std::make_pair(Size, Offset - Size));
- Size = Offset + getSize(Member->Data);
- }
- if (Padding.empty())
- return;
- // Add the padding to the Members list and sort it.
- for (std::vector<std::pair<CharUnits, CharUnits> >::const_iterator
- Pad = Padding.begin(), PadEnd = Padding.end();
- Pad != PadEnd; ++Pad)
- Members.push_back(StorageInfo(Pad->first, getByteArrayType(Pad->second)));
- std::stable_sort(Members.begin(), Members.end());
-}
-
-void CGRecordLowering::fillOutputFields() {
- for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
- MemberEnd = Members.end();
- Member != MemberEnd; ++Member) {
- if (Member->Data)
- FieldTypes.push_back(Member->Data);
- if (Member->Kind == MemberInfo::Field) {
- if (Member->FD)
- Fields[Member->FD->getCanonicalDecl()] = FieldTypes.size() - 1;
- // A field without storage must be a bitfield.
- if (!Member->Data)
- setBitFieldInfo(Member->FD, Member->Offset, FieldTypes.back());
- } else if (Member->Kind == MemberInfo::Base)
- NonVirtualBases[Member->RD] = FieldTypes.size() - 1;
- else if (Member->Kind == MemberInfo::VBase)
- VirtualBases[Member->RD] = FieldTypes.size() - 1;
- }
-}
-
-CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
- const FieldDecl *FD,
- uint64_t Offset, uint64_t Size,
- uint64_t StorageSize,
- CharUnits StorageOffset) {
- // This function is vestigial from CGRecordLayoutBuilder days but is still
- // used in GCObjCRuntime.cpp. That usage has a "fixme" attached to it that
- // when addressed will allow for the removal of this function.
- llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
- CharUnits TypeSizeInBytes =
- CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty));
- uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
-
- bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
-
- if (Size > TypeSizeInBits) {
- // We have a wide bit-field. The extra bits are only used for padding, so
- // if we have a bitfield of type T, with size N:
- //
- // T t : N;
- //
- // We can just assume that it's:
- //
- // T t : sizeof(T);
- //
- Size = TypeSizeInBits;
- }
-
- // Reverse the bit offsets for big endian machines. Because we represent
- // a bitfield as a single large integer load, we can imagine the bits
- // counting from the most-significant-bit instead of the
- // least-significant-bit.
- if (Types.getDataLayout().isBigEndian()) {
- Offset = StorageSize - (Offset + Size);
- }
-
- return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageOffset);
-}
-
-CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
- llvm::StructType *Ty) {
- CGRecordLowering Builder(*this, D, /*Packed=*/false);
-
- Builder.lower(/*NonVirtualBaseType=*/false);
-
- // If we're in C++, compute the base subobject type.
- llvm::StructType *BaseTy = nullptr;
- if (isa<CXXRecordDecl>(D) && !D->isUnion() && !D->hasAttr<FinalAttr>()) {
- BaseTy = Ty;
- if (Builder.Layout.getNonVirtualSize() != Builder.Layout.getSize()) {
- CGRecordLowering BaseBuilder(*this, D, /*Packed=*/Builder.Packed);
- BaseBuilder.lower(/*NonVirtualBaseType=*/true);
- BaseTy = llvm::StructType::create(
- getLLVMContext(), BaseBuilder.FieldTypes, "", BaseBuilder.Packed);
- addRecordTypeName(D, BaseTy, ".base");
- // BaseTy and Ty must agree on their packedness for getLLVMFieldNo to work
- // on both of them with the same index.
- assert(Builder.Packed == BaseBuilder.Packed &&
- "Non-virtual and complete types must agree on packedness");
- }
- }
-
- // Fill in the struct *after* computing the base type. Filling in the body
- // signifies that the type is no longer opaque and record layout is complete,
- // but we may need to recursively layout D while laying D out as a base type.
- Ty->setBody(Builder.FieldTypes, Builder.Packed);
-
- CGRecordLayout *RL =
- new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable,
- Builder.IsZeroInitializableAsBase);
-
- RL->NonVirtualBases.swap(Builder.NonVirtualBases);
- RL->CompleteObjectVirtualBases.swap(Builder.VirtualBases);
-
- // Add all the field numbers.
- RL->FieldInfo.swap(Builder.Fields);
-
- // Add bitfield info.
- RL->BitFields.swap(Builder.BitFields);
-
- // Dump the layout, if requested.
- if (getContext().getLangOpts().DumpRecordLayouts) {
- llvm::outs() << "\n*** Dumping IRgen Record Layout\n";
- llvm::outs() << "Record: ";
- D->dump(llvm::outs());
- llvm::outs() << "\nLayout: ";
- RL->print(llvm::outs());
- }
-
-#ifndef NDEBUG
- // Verify that the computed LLVM struct size matches the AST layout size.
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D);
-
- uint64_t TypeSizeInBits = getContext().toBits(Layout.getSize());
- assert(TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) &&
- "Type size mismatch!");
-
- if (BaseTy) {
- CharUnits NonVirtualSize = Layout.getNonVirtualSize();
-
- uint64_t AlignedNonVirtualTypeSizeInBits =
- getContext().toBits(NonVirtualSize);
-
- assert(AlignedNonVirtualTypeSizeInBits ==
- getDataLayout().getTypeAllocSizeInBits(BaseTy) &&
- "Type size mismatch!");
- }
-
- // Verify that the LLVM and AST field offsets agree.
- llvm::StructType *ST = RL->getLLVMType();
- const llvm::StructLayout *SL = getDataLayout().getStructLayout(ST);
-
- const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D);
- RecordDecl::field_iterator it = D->field_begin();
- for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
- const FieldDecl *FD = *it;
-
- // For non-bit-fields, just check that the LLVM struct offset matches the
- // AST offset.
- if (!FD->isBitField()) {
- unsigned FieldNo = RL->getLLVMFieldNo(FD);
- assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) &&
- "Invalid field offset!");
- continue;
- }
-
- // Ignore unnamed bit-fields.
- if (!FD->getDeclName())
- continue;
-
- // Don't inspect zero-length bitfields.
- if (FD->isZeroLengthBitField(getContext()))
- continue;
-
- const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD);
- llvm::Type *ElementTy = ST->getTypeAtIndex(RL->getLLVMFieldNo(FD));
-
- // Unions have overlapping elements dictating their layout, but for
- // non-unions we can verify that this section of the layout is the exact
- // expected size.
- if (D->isUnion()) {
- // For unions we verify that the start is zero and the size
- // is in-bounds. However, on BE systems, the offset may be non-zero, but
- // the size + offset should match the storage size in that case as it
- // "starts" at the back.
- if (getDataLayout().isBigEndian())
- assert(static_cast<unsigned>(Info.Offset + Info.Size) ==
- Info.StorageSize &&
- "Big endian union bitfield does not end at the back");
- else
- assert(Info.Offset == 0 &&
- "Little endian union bitfield with a non-zero offset");
- assert(Info.StorageSize <= SL->getSizeInBits() &&
- "Union not large enough for bitfield storage");
- } else {
- assert(Info.StorageSize ==
- getDataLayout().getTypeAllocSizeInBits(ElementTy) &&
- "Storage size does not match the element type size");
- }
- assert(Info.Size > 0 && "Empty bitfield!");
- assert(static_cast<unsigned>(Info.Offset) + Info.Size <= Info.StorageSize &&
- "Bitfield outside of its allocated storage");
- }
-#endif
-
- return RL;
-}
-
-void CGRecordLayout::print(raw_ostream &OS) const {
- OS << "<CGRecordLayout\n";
- OS << " LLVMType:" << *CompleteObjectType << "\n";
- if (BaseSubobjectType)
- OS << " NonVirtualBaseLLVMType:" << *BaseSubobjectType << "\n";
- OS << " IsZeroInitializable:" << IsZeroInitializable << "\n";
- OS << " BitFields:[\n";
-
- // Print bit-field infos in declaration order.
- std::vector<std::pair<unsigned, const CGBitFieldInfo*> > BFIs;
- for (llvm::DenseMap<const FieldDecl*, CGBitFieldInfo>::const_iterator
- it = BitFields.begin(), ie = BitFields.end();
- it != ie; ++it) {
- const RecordDecl *RD = it->first->getParent();
- unsigned Index = 0;
- for (RecordDecl::field_iterator
- it2 = RD->field_begin(); *it2 != it->first; ++it2)
- ++Index;
- BFIs.push_back(std::make_pair(Index, &it->second));
- }
- llvm::array_pod_sort(BFIs.begin(), BFIs.end());
- for (unsigned i = 0, e = BFIs.size(); i != e; ++i) {
- OS.indent(4);
- BFIs[i].second->print(OS);
- OS << "\n";
- }
-
- OS << "]>\n";
-}
-
-LLVM_DUMP_METHOD void CGRecordLayout::dump() const {
- print(llvm::errs());
-}
-
-void CGBitFieldInfo::print(raw_ostream &OS) const {
- OS << "<CGBitFieldInfo"
- << " Offset:" << Offset
- << " Size:" << Size
- << " IsSigned:" << IsSigned
- << " StorageSize:" << StorageSize
- << " StorageOffset:" << StorageOffset.getQuantity() << ">";
-}
-
-LLVM_DUMP_METHOD void CGBitFieldInfo::dump() const {
- print(llvm::errs());
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGStmt.cpp
deleted file mode 100644
index b2b32759b6f..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGStmt.cpp
+++ /dev/null
@@ -1,2350 +0,0 @@
-//===--- CGStmt.cpp - Emit LLVM Code from Statements ----------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit Stmt nodes as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CGDebugInfo.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/PrettyStackTrace.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/MDBuilder.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-//===----------------------------------------------------------------------===//
-// Statement Emission
-//===----------------------------------------------------------------------===//
-
-void CodeGenFunction::EmitStopPoint(const Stmt *S) {
- if (CGDebugInfo *DI = getDebugInfo()) {
- SourceLocation Loc;
- Loc = S->getBeginLoc();
- DI->EmitLocation(Builder, Loc);
-
- LastStopPoint = Loc;
- }
-}
-
-void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
- assert(S && "Null statement?");
- PGO.setCurrentStmt(S);
-
- // These statements have their own debug info handling.
- if (EmitSimpleStmt(S))
- return;
-
- // Check if we are generating unreachable code.
- if (!HaveInsertPoint()) {
- // If so, and the statement doesn't contain a label, then we do not need to
- // generate actual code. This is safe because (1) the current point is
- // unreachable, so we don't need to execute the code, and (2) we've already
- // handled the statements which update internal data structures (like the
- // local variable map) which could be used by subsequent statements.
- if (!ContainsLabel(S)) {
- // Verify that any decl statements were handled as simple, they may be in
- // scope of subsequent reachable statements.
- assert(!isa<DeclStmt>(*S) && "Unexpected DeclStmt!");
- return;
- }
-
- // Otherwise, make a new block to hold the code.
- EnsureInsertPoint();
- }
-
- // Generate a stoppoint if we are emitting debug info.
- EmitStopPoint(S);
-
- // Ignore all OpenMP directives except for simd if OpenMP with Simd is
- // enabled.
- if (getLangOpts().OpenMP && getLangOpts().OpenMPSimd) {
- if (const auto *D = dyn_cast<OMPExecutableDirective>(S)) {
- EmitSimpleOMPExecutableDirective(*D);
- return;
- }
- }
-
- switch (S->getStmtClass()) {
- case Stmt::NoStmtClass:
- case Stmt::CXXCatchStmtClass:
- case Stmt::SEHExceptStmtClass:
- case Stmt::SEHFinallyStmtClass:
- case Stmt::MSDependentExistsStmtClass:
- llvm_unreachable("invalid statement class to emit generically");
- case Stmt::NullStmtClass:
- case Stmt::CompoundStmtClass:
- case Stmt::DeclStmtClass:
- case Stmt::LabelStmtClass:
- case Stmt::AttributedStmtClass:
- case Stmt::GotoStmtClass:
- case Stmt::BreakStmtClass:
- case Stmt::ContinueStmtClass:
- case Stmt::DefaultStmtClass:
- case Stmt::CaseStmtClass:
- case Stmt::SEHLeaveStmtClass:
- llvm_unreachable("should have emitted these statements as simple");
-
-#define STMT(Type, Base)
-#define ABSTRACT_STMT(Op)
-#define EXPR(Type, Base) \
- case Stmt::Type##Class:
-#include "clang/AST/StmtNodes.inc"
- {
- // Remember the block we came in on.
- llvm::BasicBlock *incoming = Builder.GetInsertBlock();
- assert(incoming && "expression emission must have an insertion point");
-
- EmitIgnoredExpr(cast<Expr>(S));
-
- llvm::BasicBlock *outgoing = Builder.GetInsertBlock();
- assert(outgoing && "expression emission cleared block!");
-
- // The expression emitters assume (reasonably!) that the insertion
- // point is always set. To maintain that, the call-emission code
- // for noreturn functions has to enter a new block with no
- // predecessors. We want to kill that block and mark the current
- // insertion point unreachable in the common case of a call like
- // "exit();". Since expression emission doesn't otherwise create
- // blocks with no predecessors, we can just test for that.
- // However, we must be careful not to do this to our incoming
- // block, because *statement* emission does sometimes create
- // reachable blocks which will have no predecessors until later in
- // the function. This occurs with, e.g., labels that are not
- // reachable by fallthrough.
- if (incoming != outgoing && outgoing->use_empty()) {
- outgoing->eraseFromParent();
- Builder.ClearInsertionPoint();
- }
- break;
- }
-
- case Stmt::IndirectGotoStmtClass:
- EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break;
-
- case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
- case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S), Attrs); break;
- case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S), Attrs); break;
- case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S), Attrs); break;
-
- case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
-
- case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
- case Stmt::GCCAsmStmtClass: // Intentional fall-through.
- case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
- case Stmt::CoroutineBodyStmtClass:
- EmitCoroutineBody(cast<CoroutineBodyStmt>(*S));
- break;
- case Stmt::CoreturnStmtClass:
- EmitCoreturnStmt(cast<CoreturnStmt>(*S));
- break;
- case Stmt::CapturedStmtClass: {
- const CapturedStmt *CS = cast<CapturedStmt>(S);
- EmitCapturedStmt(*CS, CS->getCapturedRegionKind());
- }
- break;
- case Stmt::ObjCAtTryStmtClass:
- EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
- break;
- case Stmt::ObjCAtCatchStmtClass:
- llvm_unreachable(
- "@catch statements should be handled by EmitObjCAtTryStmt");
- case Stmt::ObjCAtFinallyStmtClass:
- llvm_unreachable(
- "@finally statements should be handled by EmitObjCAtTryStmt");
- case Stmt::ObjCAtThrowStmtClass:
- EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S));
- break;
- case Stmt::ObjCAtSynchronizedStmtClass:
- EmitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(*S));
- break;
- case Stmt::ObjCForCollectionStmtClass:
- EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
- break;
- case Stmt::ObjCAutoreleasePoolStmtClass:
- EmitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(*S));
- break;
-
- case Stmt::CXXTryStmtClass:
- EmitCXXTryStmt(cast<CXXTryStmt>(*S));
- break;
- case Stmt::CXXForRangeStmtClass:
- EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S), Attrs);
- break;
- case Stmt::SEHTryStmtClass:
- EmitSEHTryStmt(cast<SEHTryStmt>(*S));
- break;
- case Stmt::OMPParallelDirectiveClass:
- EmitOMPParallelDirective(cast<OMPParallelDirective>(*S));
- break;
- case Stmt::OMPSimdDirectiveClass:
- EmitOMPSimdDirective(cast<OMPSimdDirective>(*S));
- break;
- case Stmt::OMPForDirectiveClass:
- EmitOMPForDirective(cast<OMPForDirective>(*S));
- break;
- case Stmt::OMPForSimdDirectiveClass:
- EmitOMPForSimdDirective(cast<OMPForSimdDirective>(*S));
- break;
- case Stmt::OMPSectionsDirectiveClass:
- EmitOMPSectionsDirective(cast<OMPSectionsDirective>(*S));
- break;
- case Stmt::OMPSectionDirectiveClass:
- EmitOMPSectionDirective(cast<OMPSectionDirective>(*S));
- break;
- case Stmt::OMPSingleDirectiveClass:
- EmitOMPSingleDirective(cast<OMPSingleDirective>(*S));
- break;
- case Stmt::OMPMasterDirectiveClass:
- EmitOMPMasterDirective(cast<OMPMasterDirective>(*S));
- break;
- case Stmt::OMPCriticalDirectiveClass:
- EmitOMPCriticalDirective(cast<OMPCriticalDirective>(*S));
- break;
- case Stmt::OMPParallelForDirectiveClass:
- EmitOMPParallelForDirective(cast<OMPParallelForDirective>(*S));
- break;
- case Stmt::OMPParallelForSimdDirectiveClass:
- EmitOMPParallelForSimdDirective(cast<OMPParallelForSimdDirective>(*S));
- break;
- case Stmt::OMPParallelSectionsDirectiveClass:
- EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S));
- break;
- case Stmt::OMPTaskDirectiveClass:
- EmitOMPTaskDirective(cast<OMPTaskDirective>(*S));
- break;
- case Stmt::OMPTaskyieldDirectiveClass:
- EmitOMPTaskyieldDirective(cast<OMPTaskyieldDirective>(*S));
- break;
- case Stmt::OMPBarrierDirectiveClass:
- EmitOMPBarrierDirective(cast<OMPBarrierDirective>(*S));
- break;
- case Stmt::OMPTaskwaitDirectiveClass:
- EmitOMPTaskwaitDirective(cast<OMPTaskwaitDirective>(*S));
- break;
- case Stmt::OMPTaskgroupDirectiveClass:
- EmitOMPTaskgroupDirective(cast<OMPTaskgroupDirective>(*S));
- break;
- case Stmt::OMPFlushDirectiveClass:
- EmitOMPFlushDirective(cast<OMPFlushDirective>(*S));
- break;
- case Stmt::OMPOrderedDirectiveClass:
- EmitOMPOrderedDirective(cast<OMPOrderedDirective>(*S));
- break;
- case Stmt::OMPAtomicDirectiveClass:
- EmitOMPAtomicDirective(cast<OMPAtomicDirective>(*S));
- break;
- case Stmt::OMPTargetDirectiveClass:
- EmitOMPTargetDirective(cast<OMPTargetDirective>(*S));
- break;
- case Stmt::OMPTeamsDirectiveClass:
- EmitOMPTeamsDirective(cast<OMPTeamsDirective>(*S));
- break;
- case Stmt::OMPCancellationPointDirectiveClass:
- EmitOMPCancellationPointDirective(cast<OMPCancellationPointDirective>(*S));
- break;
- case Stmt::OMPCancelDirectiveClass:
- EmitOMPCancelDirective(cast<OMPCancelDirective>(*S));
- break;
- case Stmt::OMPTargetDataDirectiveClass:
- EmitOMPTargetDataDirective(cast<OMPTargetDataDirective>(*S));
- break;
- case Stmt::OMPTargetEnterDataDirectiveClass:
- EmitOMPTargetEnterDataDirective(cast<OMPTargetEnterDataDirective>(*S));
- break;
- case Stmt::OMPTargetExitDataDirectiveClass:
- EmitOMPTargetExitDataDirective(cast<OMPTargetExitDataDirective>(*S));
- break;
- case Stmt::OMPTargetParallelDirectiveClass:
- EmitOMPTargetParallelDirective(cast<OMPTargetParallelDirective>(*S));
- break;
- case Stmt::OMPTargetParallelForDirectiveClass:
- EmitOMPTargetParallelForDirective(cast<OMPTargetParallelForDirective>(*S));
- break;
- case Stmt::OMPTaskLoopDirectiveClass:
- EmitOMPTaskLoopDirective(cast<OMPTaskLoopDirective>(*S));
- break;
- case Stmt::OMPTaskLoopSimdDirectiveClass:
- EmitOMPTaskLoopSimdDirective(cast<OMPTaskLoopSimdDirective>(*S));
- break;
- case Stmt::OMPDistributeDirectiveClass:
- EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S));
- break;
- case Stmt::OMPTargetUpdateDirectiveClass:
- EmitOMPTargetUpdateDirective(cast<OMPTargetUpdateDirective>(*S));
- break;
- case Stmt::OMPDistributeParallelForDirectiveClass:
- EmitOMPDistributeParallelForDirective(
- cast<OMPDistributeParallelForDirective>(*S));
- break;
- case Stmt::OMPDistributeParallelForSimdDirectiveClass:
- EmitOMPDistributeParallelForSimdDirective(
- cast<OMPDistributeParallelForSimdDirective>(*S));
- break;
- case Stmt::OMPDistributeSimdDirectiveClass:
- EmitOMPDistributeSimdDirective(cast<OMPDistributeSimdDirective>(*S));
- break;
- case Stmt::OMPTargetParallelForSimdDirectiveClass:
- EmitOMPTargetParallelForSimdDirective(
- cast<OMPTargetParallelForSimdDirective>(*S));
- break;
- case Stmt::OMPTargetSimdDirectiveClass:
- EmitOMPTargetSimdDirective(cast<OMPTargetSimdDirective>(*S));
- break;
- case Stmt::OMPTeamsDistributeDirectiveClass:
- EmitOMPTeamsDistributeDirective(cast<OMPTeamsDistributeDirective>(*S));
- break;
- case Stmt::OMPTeamsDistributeSimdDirectiveClass:
- EmitOMPTeamsDistributeSimdDirective(
- cast<OMPTeamsDistributeSimdDirective>(*S));
- break;
- case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
- EmitOMPTeamsDistributeParallelForSimdDirective(
- cast<OMPTeamsDistributeParallelForSimdDirective>(*S));
- break;
- case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
- EmitOMPTeamsDistributeParallelForDirective(
- cast<OMPTeamsDistributeParallelForDirective>(*S));
- break;
- case Stmt::OMPTargetTeamsDirectiveClass:
- EmitOMPTargetTeamsDirective(cast<OMPTargetTeamsDirective>(*S));
- break;
- case Stmt::OMPTargetTeamsDistributeDirectiveClass:
- EmitOMPTargetTeamsDistributeDirective(
- cast<OMPTargetTeamsDistributeDirective>(*S));
- break;
- case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
- EmitOMPTargetTeamsDistributeParallelForDirective(
- cast<OMPTargetTeamsDistributeParallelForDirective>(*S));
- break;
- case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
- EmitOMPTargetTeamsDistributeParallelForSimdDirective(
- cast<OMPTargetTeamsDistributeParallelForSimdDirective>(*S));
- break;
- case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
- EmitOMPTargetTeamsDistributeSimdDirective(
- cast<OMPTargetTeamsDistributeSimdDirective>(*S));
- break;
- }
-}
-
-bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) {
- switch (S->getStmtClass()) {
- default: return false;
- case Stmt::NullStmtClass: break;
- case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
- case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break;
- case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break;
- case Stmt::AttributedStmtClass:
- EmitAttributedStmt(cast<AttributedStmt>(*S)); break;
- case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break;
- case Stmt::BreakStmtClass: EmitBreakStmt(cast<BreakStmt>(*S)); break;
- case Stmt::ContinueStmtClass: EmitContinueStmt(cast<ContinueStmt>(*S)); break;
- case Stmt::DefaultStmtClass: EmitDefaultStmt(cast<DefaultStmt>(*S)); break;
- case Stmt::CaseStmtClass: EmitCaseStmt(cast<CaseStmt>(*S)); break;
- case Stmt::SEHLeaveStmtClass: EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S)); break;
- }
-
- return true;
-}
-
-/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
-/// this captures the expression result of the last sub-statement and returns it
-/// (for use by the statement expression extension).
-Address CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
- AggValueSlot AggSlot) {
- PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(),
- "LLVM IR generation of compound statement ('{}')");
-
- // Keep track of the current cleanup stack depth, including debug scopes.
- LexicalScope Scope(*this, S.getSourceRange());
-
- return EmitCompoundStmtWithoutScope(S, GetLast, AggSlot);
-}
-
-Address
-CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
- bool GetLast,
- AggValueSlot AggSlot) {
-
- for (CompoundStmt::const_body_iterator I = S.body_begin(),
- E = S.body_end()-GetLast; I != E; ++I)
- EmitStmt(*I);
-
- Address RetAlloca = Address::invalid();
- if (GetLast) {
- // We have to special case labels here. They are statements, but when put
- // at the end of a statement expression, they yield the value of their
- // subexpression. Handle this by walking through all labels we encounter,
- // emitting them before we evaluate the subexpr.
- const Stmt *LastStmt = S.body_back();
- while (const LabelStmt *LS = dyn_cast<LabelStmt>(LastStmt)) {
- EmitLabel(LS->getDecl());
- LastStmt = LS->getSubStmt();
- }
-
- EnsureInsertPoint();
-
- QualType ExprTy = cast<Expr>(LastStmt)->getType();
- if (hasAggregateEvaluationKind(ExprTy)) {
- EmitAggExpr(cast<Expr>(LastStmt), AggSlot);
- } else {
- // We can't return an RValue here because there might be cleanups at
- // the end of the StmtExpr. Because of that, we have to emit the result
- // here into a temporary alloca.
- RetAlloca = CreateMemTemp(ExprTy);
- EmitAnyExprToMem(cast<Expr>(LastStmt), RetAlloca, Qualifiers(),
- /*IsInit*/false);
- }
-
- }
-
- return RetAlloca;
-}
-
-void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
- llvm::BranchInst *BI = dyn_cast<llvm::BranchInst>(BB->getTerminator());
-
- // If there is a cleanup stack, then we it isn't worth trying to
- // simplify this block (we would need to remove it from the scope map
- // and cleanup entry).
- if (!EHStack.empty())
- return;
-
- // Can only simplify direct branches.
- if (!BI || !BI->isUnconditional())
- return;
-
- // Can only simplify empty blocks.
- if (BI->getIterator() != BB->begin())
- return;
-
- BB->replaceAllUsesWith(BI->getSuccessor(0));
- BI->eraseFromParent();
- BB->eraseFromParent();
-}
-
-void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
- llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
-
- // Fall out of the current block (if necessary).
- EmitBranch(BB);
-
- if (IsFinished && BB->use_empty()) {
- delete BB;
- return;
- }
-
- // Place the block after the current block, if possible, or else at
- // the end of the function.
- if (CurBB && CurBB->getParent())
- CurFn->getBasicBlockList().insertAfter(CurBB->getIterator(), BB);
- else
- CurFn->getBasicBlockList().push_back(BB);
- Builder.SetInsertPoint(BB);
-}
-
-void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) {
- // Emit a branch from the current block to the target one if this
- // was a real block. If this was just a fall-through block after a
- // terminator, don't emit it.
- llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
-
- if (!CurBB || CurBB->getTerminator()) {
- // If there is no insert point or the previous block is already
- // terminated, don't touch it.
- } else {
- // Otherwise, create a fall-through branch.
- Builder.CreateBr(Target);
- }
-
- Builder.ClearInsertionPoint();
-}
-
-void CodeGenFunction::EmitBlockAfterUses(llvm::BasicBlock *block) {
- bool inserted = false;
- for (llvm::User *u : block->users()) {
- if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(u)) {
- CurFn->getBasicBlockList().insertAfter(insn->getParent()->getIterator(),
- block);
- inserted = true;
- break;
- }
- }
-
- if (!inserted)
- CurFn->getBasicBlockList().push_back(block);
-
- Builder.SetInsertPoint(block);
-}
-
-CodeGenFunction::JumpDest
-CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) {
- JumpDest &Dest = LabelMap[D];
- if (Dest.isValid()) return Dest;
-
- // Create, but don't insert, the new block.
- Dest = JumpDest(createBasicBlock(D->getName()),
- EHScopeStack::stable_iterator::invalid(),
- NextCleanupDestIndex++);
- return Dest;
-}
-
-void CodeGenFunction::EmitLabel(const LabelDecl *D) {
- // Add this label to the current lexical scope if we're within any
- // normal cleanups. Jumps "in" to this label --- when permitted by
- // the language --- may need to be routed around such cleanups.
- if (EHStack.hasNormalCleanups() && CurLexicalScope)
- CurLexicalScope->addLabel(D);
-
- JumpDest &Dest = LabelMap[D];
-
- // If we didn't need a forward reference to this label, just go
- // ahead and create a destination at the current scope.
- if (!Dest.isValid()) {
- Dest = getJumpDestInCurrentScope(D->getName());
-
- // Otherwise, we need to give this label a target depth and remove
- // it from the branch-fixups list.
- } else {
- assert(!Dest.getScopeDepth().isValid() && "already emitted label!");
- Dest.setScopeDepth(EHStack.stable_begin());
- ResolveBranchFixups(Dest.getBlock());
- }
-
- EmitBlock(Dest.getBlock());
- incrementProfileCounter(D->getStmt());
-}
-
-/// Change the cleanup scope of the labels in this lexical scope to
-/// match the scope of the enclosing context.
-void CodeGenFunction::LexicalScope::rescopeLabels() {
- assert(!Labels.empty());
- EHScopeStack::stable_iterator innermostScope
- = CGF.EHStack.getInnermostNormalCleanup();
-
- // Change the scope depth of all the labels.
- for (SmallVectorImpl<const LabelDecl*>::const_iterator
- i = Labels.begin(), e = Labels.end(); i != e; ++i) {
- assert(CGF.LabelMap.count(*i));
- JumpDest &dest = CGF.LabelMap.find(*i)->second;
- assert(dest.getScopeDepth().isValid());
- assert(innermostScope.encloses(dest.getScopeDepth()));
- dest.setScopeDepth(innermostScope);
- }
-
- // Reparent the labels if the new scope also has cleanups.
- if (innermostScope != EHScopeStack::stable_end() && ParentScope) {
- ParentScope->Labels.append(Labels.begin(), Labels.end());
- }
-}
-
-
-void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
- EmitLabel(S.getDecl());
- EmitStmt(S.getSubStmt());
-}
-
-void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
- EmitStmt(S.getSubStmt(), S.getAttrs());
-}
-
-void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
- // If this code is reachable then emit a stop point (if generating
- // debug info). We have to do this ourselves because we are on the
- // "simple" statement path.
- if (HaveInsertPoint())
- EmitStopPoint(&S);
-
- EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel()));
-}
-
-
-void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
- if (const LabelDecl *Target = S.getConstantTarget()) {
- EmitBranchThroughCleanup(getJumpDestForLabel(Target));
- return;
- }
-
- // Ensure that we have an i8* for our PHI node.
- llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()),
- Int8PtrTy, "addr");
- llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
-
- // Get the basic block for the indirect goto.
- llvm::BasicBlock *IndGotoBB = GetIndirectGotoBlock();
-
- // The first instruction in the block has to be the PHI for the switch dest,
- // add an entry for this branch.
- cast<llvm::PHINode>(IndGotoBB->begin())->addIncoming(V, CurBB);
-
- EmitBranch(IndGotoBB);
-}
-
-void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
- // C99 6.8.4.1: The first substatement is executed if the expression compares
- // unequal to 0. The condition must be a scalar type.
- LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
-
- if (S.getInit())
- EmitStmt(S.getInit());
-
- if (S.getConditionVariable())
- EmitDecl(*S.getConditionVariable());
-
- // If the condition constant folds and can be elided, try to avoid emitting
- // the condition and the dead arm of the if/else.
- bool CondConstant;
- if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant,
- S.isConstexpr())) {
- // Figure out which block (then or else) is executed.
- const Stmt *Executed = S.getThen();
- const Stmt *Skipped = S.getElse();
- if (!CondConstant) // Condition false?
- std::swap(Executed, Skipped);
-
- // If the skipped block has no labels in it, just emit the executed block.
- // This avoids emitting dead code and simplifies the CFG substantially.
- if (S.isConstexpr() || !ContainsLabel(Skipped)) {
- if (CondConstant)
- incrementProfileCounter(&S);
- if (Executed) {
- RunCleanupsScope ExecutedScope(*this);
- EmitStmt(Executed);
- }
- return;
- }
- }
-
- // Otherwise, the condition did not fold, or we couldn't elide it. Just emit
- // the conditional branch.
- llvm::BasicBlock *ThenBlock = createBasicBlock("if.then");
- llvm::BasicBlock *ContBlock = createBasicBlock("if.end");
- llvm::BasicBlock *ElseBlock = ContBlock;
- if (S.getElse())
- ElseBlock = createBasicBlock("if.else");
-
- EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock,
- getProfileCount(S.getThen()));
-
- // Emit the 'then' code.
- EmitBlock(ThenBlock);
- incrementProfileCounter(&S);
- {
- RunCleanupsScope ThenScope(*this);
- EmitStmt(S.getThen());
- }
- EmitBranch(ContBlock);
-
- // Emit the 'else' code if present.
- if (const Stmt *Else = S.getElse()) {
- {
- // There is no need to emit line number for an unconditional branch.
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
- EmitBlock(ElseBlock);
- }
- {
- RunCleanupsScope ElseScope(*this);
- EmitStmt(Else);
- }
- {
- // There is no need to emit line number for an unconditional branch.
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
- EmitBranch(ContBlock);
- }
- }
-
- // Emit the continuation block for code after the if.
- EmitBlock(ContBlock, true);
-}
-
-void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
- ArrayRef<const Attr *> WhileAttrs) {
- // Emit the header for the loop, which will also become
- // the continue target.
- JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond");
- EmitBlock(LoopHeader.getBlock());
-
- const SourceRange &R = S.getSourceRange();
- LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), WhileAttrs,
- SourceLocToDebugLoc(R.getBegin()),
- SourceLocToDebugLoc(R.getEnd()));
-
- // Create an exit block for when the condition fails, which will
- // also become the break target.
- JumpDest LoopExit = getJumpDestInCurrentScope("while.end");
-
- // Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, LoopHeader));
-
- // C++ [stmt.while]p2:
- // When the condition of a while statement is a declaration, the
- // scope of the variable that is declared extends from its point
- // of declaration (3.3.2) to the end of the while statement.
- // [...]
- // The object created in a condition is destroyed and created
- // with each iteration of the loop.
- RunCleanupsScope ConditionScope(*this);
-
- if (S.getConditionVariable())
- EmitDecl(*S.getConditionVariable());
-
- // Evaluate the conditional in the while header. C99 6.8.5.1: The
- // evaluation of the controlling expression takes place before each
- // execution of the loop body.
- llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
-
- // while(1) is common, avoid extra exit blocks. Be sure
- // to correctly handle break/continue though.
- bool EmitBoolCondBranch = true;
- if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
- if (C->isOne())
- EmitBoolCondBranch = false;
-
- // As long as the condition is true, go to the loop body.
- llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
- if (EmitBoolCondBranch) {
- llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
- if (ConditionScope.requiresCleanups())
- ExitBlock = createBasicBlock("while.exit");
- Builder.CreateCondBr(
- BoolCondVal, LoopBody, ExitBlock,
- createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
-
- if (ExitBlock != LoopExit.getBlock()) {
- EmitBlock(ExitBlock);
- EmitBranchThroughCleanup(LoopExit);
- }
- }
-
- // Emit the loop body. We have to emit this in a cleanup scope
- // because it might be a singleton DeclStmt.
- {
- RunCleanupsScope BodyScope(*this);
- EmitBlock(LoopBody);
- incrementProfileCounter(&S);
- EmitStmt(S.getBody());
- }
-
- BreakContinueStack.pop_back();
-
- // Immediately force cleanup.
- ConditionScope.ForceCleanup();
-
- EmitStopPoint(&S);
- // Branch to the loop header again.
- EmitBranch(LoopHeader.getBlock());
-
- LoopStack.pop();
-
- // Emit the exit block.
- EmitBlock(LoopExit.getBlock(), true);
-
- // The LoopHeader typically is just a branch if we skipped emitting
- // a branch, try to erase it.
- if (!EmitBoolCondBranch)
- SimplifyForwardingBlocks(LoopHeader.getBlock());
-}
-
-void CodeGenFunction::EmitDoStmt(const DoStmt &S,
- ArrayRef<const Attr *> DoAttrs) {
- JumpDest LoopExit = getJumpDestInCurrentScope("do.end");
- JumpDest LoopCond = getJumpDestInCurrentScope("do.cond");
-
- uint64_t ParentCount = getCurrentProfileCount();
-
- // Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond));
-
- // Emit the body of the loop.
- llvm::BasicBlock *LoopBody = createBasicBlock("do.body");
-
- EmitBlockWithFallThrough(LoopBody, &S);
- {
- RunCleanupsScope BodyScope(*this);
- EmitStmt(S.getBody());
- }
-
- EmitBlock(LoopCond.getBlock());
-
- const SourceRange &R = S.getSourceRange();
- LoopStack.push(LoopBody, CGM.getContext(), DoAttrs,
- SourceLocToDebugLoc(R.getBegin()),
- SourceLocToDebugLoc(R.getEnd()));
-
- // C99 6.8.5.2: "The evaluation of the controlling expression takes place
- // after each execution of the loop body."
-
- // Evaluate the conditional in the while header.
- // C99 6.8.5p2/p4: The first substatement is executed if the expression
- // compares unequal to 0. The condition must be a scalar type.
- llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
-
- BreakContinueStack.pop_back();
-
- // "do {} while (0)" is common in macros, avoid extra blocks. Be sure
- // to correctly handle break/continue though.
- bool EmitBoolCondBranch = true;
- if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
- if (C->isZero())
- EmitBoolCondBranch = false;
-
- // As long as the condition is true, iterate the loop.
- if (EmitBoolCondBranch) {
- uint64_t BackedgeCount = getProfileCount(S.getBody()) - ParentCount;
- Builder.CreateCondBr(
- BoolCondVal, LoopBody, LoopExit.getBlock(),
- createProfileWeightsForLoop(S.getCond(), BackedgeCount));
- }
-
- LoopStack.pop();
-
- // Emit the exit block.
- EmitBlock(LoopExit.getBlock());
-
- // The DoCond block typically is just a branch if we skipped
- // emitting a branch, try to erase it.
- if (!EmitBoolCondBranch)
- SimplifyForwardingBlocks(LoopCond.getBlock());
-}
-
-void CodeGenFunction::EmitForStmt(const ForStmt &S,
- ArrayRef<const Attr *> ForAttrs) {
- JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
-
- LexicalScope ForScope(*this, S.getSourceRange());
-
- // Evaluate the first part before the loop.
- if (S.getInit())
- EmitStmt(S.getInit());
-
- // Start the loop with a block that tests the condition.
- // If there's an increment, the continue scope will be overwritten
- // later.
- JumpDest Continue = getJumpDestInCurrentScope("for.cond");
- llvm::BasicBlock *CondBlock = Continue.getBlock();
- EmitBlock(CondBlock);
-
- const SourceRange &R = S.getSourceRange();
- LoopStack.push(CondBlock, CGM.getContext(), ForAttrs,
- SourceLocToDebugLoc(R.getBegin()),
- SourceLocToDebugLoc(R.getEnd()));
-
- // If the for loop doesn't have an increment we can just use the
- // condition as the continue block. Otherwise we'll need to create
- // a block for it (in the current scope, i.e. in the scope of the
- // condition), and that we will become our continue block.
- if (S.getInc())
- Continue = getJumpDestInCurrentScope("for.inc");
-
- // Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
-
- // Create a cleanup scope for the condition variable cleanups.
- LexicalScope ConditionScope(*this, S.getSourceRange());
-
- if (S.getCond()) {
- // If the for statement has a condition scope, emit the local variable
- // declaration.
- if (S.getConditionVariable()) {
- EmitDecl(*S.getConditionVariable());
- }
-
- llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
- // If there are any cleanups between here and the loop-exit scope,
- // create a block to stage a loop exit along.
- if (ForScope.requiresCleanups())
- ExitBlock = createBasicBlock("for.cond.cleanup");
-
- // As long as the condition is true, iterate the loop.
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-
- // C99 6.8.5p2/p4: The first substatement is executed if the expression
- // compares unequal to 0. The condition must be a scalar type.
- llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
- Builder.CreateCondBr(
- BoolCondVal, ForBody, ExitBlock,
- createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
-
- if (ExitBlock != LoopExit.getBlock()) {
- EmitBlock(ExitBlock);
- EmitBranchThroughCleanup(LoopExit);
- }
-
- EmitBlock(ForBody);
- } else {
- // Treat it as a non-zero constant. Don't even create a new block for the
- // body, just fall into it.
- }
- incrementProfileCounter(&S);
-
- {
- // Create a separate cleanup scope for the body, in case it is not
- // a compound statement.
- RunCleanupsScope BodyScope(*this);
- EmitStmt(S.getBody());
- }
-
- // If there is an increment, emit it next.
- if (S.getInc()) {
- EmitBlock(Continue.getBlock());
- EmitStmt(S.getInc());
- }
-
- BreakContinueStack.pop_back();
-
- ConditionScope.ForceCleanup();
-
- EmitStopPoint(&S);
- EmitBranch(CondBlock);
-
- ForScope.ForceCleanup();
-
- LoopStack.pop();
-
- // Emit the fall-through block.
- EmitBlock(LoopExit.getBlock(), true);
-}
-
-void
-CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
- ArrayRef<const Attr *> ForAttrs) {
- JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
-
- LexicalScope ForScope(*this, S.getSourceRange());
-
- // Evaluate the first pieces before the loop.
- if (S.getInit())
- EmitStmt(S.getInit());
- EmitStmt(S.getRangeStmt());
- EmitStmt(S.getBeginStmt());
- EmitStmt(S.getEndStmt());
-
- // Start the loop with a block that tests the condition.
- // If there's an increment, the continue scope will be overwritten
- // later.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- EmitBlock(CondBlock);
-
- const SourceRange &R = S.getSourceRange();
- LoopStack.push(CondBlock, CGM.getContext(), ForAttrs,
- SourceLocToDebugLoc(R.getBegin()),
- SourceLocToDebugLoc(R.getEnd()));
-
- // If there are any cleanups between here and the loop-exit scope,
- // create a block to stage a loop exit along.
- llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
- if (ForScope.requiresCleanups())
- ExitBlock = createBasicBlock("for.cond.cleanup");
-
- // The loop body, consisting of the specified body and the loop variable.
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-
- // The body is executed if the expression, contextually converted
- // to bool, is true.
- llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
- Builder.CreateCondBr(
- BoolCondVal, ForBody, ExitBlock,
- createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
-
- if (ExitBlock != LoopExit.getBlock()) {
- EmitBlock(ExitBlock);
- EmitBranchThroughCleanup(LoopExit);
- }
-
- EmitBlock(ForBody);
- incrementProfileCounter(&S);
-
- // Create a block for the increment. In case of a 'continue', we jump there.
- JumpDest Continue = getJumpDestInCurrentScope("for.inc");
-
- // Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
-
- {
- // Create a separate cleanup scope for the loop variable and body.
- LexicalScope BodyScope(*this, S.getSourceRange());
- EmitStmt(S.getLoopVarStmt());
- EmitStmt(S.getBody());
- }
-
- EmitStopPoint(&S);
- // If there is an increment, emit it next.
- EmitBlock(Continue.getBlock());
- EmitStmt(S.getInc());
-
- BreakContinueStack.pop_back();
-
- EmitBranch(CondBlock);
-
- ForScope.ForceCleanup();
-
- LoopStack.pop();
-
- // Emit the fall-through block.
- EmitBlock(LoopExit.getBlock(), true);
-}
-
-void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
- if (RV.isScalar()) {
- Builder.CreateStore(RV.getScalarVal(), ReturnValue);
- } else if (RV.isAggregate()) {
- LValue Dest = MakeAddrLValue(ReturnValue, Ty);
- LValue Src = MakeAddrLValue(RV.getAggregateAddress(), Ty);
- EmitAggregateCopy(Dest, Src, Ty, overlapForReturnValue());
- } else {
- EmitStoreOfComplex(RV.getComplexVal(), MakeAddrLValue(ReturnValue, Ty),
- /*init*/ true);
- }
- EmitBranchThroughCleanup(ReturnBlock);
-}
-
-/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand
-/// if the function returns void, or may be missing one if the function returns
-/// non-void. Fun stuff :).
-void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
- if (requiresReturnValueCheck()) {
- llvm::Constant *SLoc = EmitCheckSourceLocation(S.getBeginLoc());
- auto *SLocPtr =
- new llvm::GlobalVariable(CGM.getModule(), SLoc->getType(), false,
- llvm::GlobalVariable::PrivateLinkage, SLoc);
- SLocPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
- assert(ReturnLocation.isValid() && "No valid return location");
- Builder.CreateStore(Builder.CreateBitCast(SLocPtr, Int8PtrTy),
- ReturnLocation);
- }
-
- // Returning from an outlined SEH helper is UB, and we already warn on it.
- if (IsOutlinedSEHHelper) {
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
- }
-
- // Emit the result value, even if unused, to evaluate the side effects.
- const Expr *RV = S.getRetValue();
-
- // Treat block literals in a return expression as if they appeared
- // in their own scope. This permits a small, easily-implemented
- // exception to our over-conservative rules about not jumping to
- // statements following block literals with non-trivial cleanups.
- RunCleanupsScope cleanupScope(*this);
- if (const FullExpr *fe = dyn_cast_or_null<FullExpr>(RV)) {
- enterFullExpression(fe);
- RV = fe->getSubExpr();
- }
-
- // FIXME: Clean this up by using an LValue for ReturnTemp,
- // EmitStoreThroughLValue, and EmitAnyExpr.
- if (getLangOpts().ElideConstructors &&
- S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable()) {
- // Apply the named return value optimization for this return statement,
- // which means doing nothing: the appropriate result has already been
- // constructed into the NRVO variable.
-
- // If there is an NRVO flag for this variable, set it to 1 into indicate
- // that the cleanup code should not destroy the variable.
- if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()])
- Builder.CreateFlagStore(Builder.getTrue(), NRVOFlag);
- } else if (!ReturnValue.isValid() || (RV && RV->getType()->isVoidType())) {
- // Make sure not to return anything, but evaluate the expression
- // for side effects.
- if (RV)
- EmitAnyExpr(RV);
- } else if (!RV) {
- // Do nothing (return value is left uninitialized)
- } else if (FnRetTy->isReferenceType()) {
- // If this function returns a reference, take the address of the expression
- // rather than the value.
- RValue Result = EmitReferenceBindingToExpr(RV);
- Builder.CreateStore(Result.getScalarVal(), ReturnValue);
- } else {
- switch (getEvaluationKind(RV->getType())) {
- case TEK_Scalar:
- Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
- break;
- case TEK_Complex:
- EmitComplexExprIntoLValue(RV, MakeAddrLValue(ReturnValue, RV->getType()),
- /*isInit*/ true);
- break;
- case TEK_Aggregate:
- EmitAggExpr(RV, AggValueSlot::forAddr(
- ReturnValue, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- overlapForReturnValue()));
- break;
- }
- }
-
- ++NumReturnExprs;
- if (!RV || RV->isEvaluatable(getContext()))
- ++NumSimpleReturnExprs;
-
- cleanupScope.ForceCleanup();
- EmitBranchThroughCleanup(ReturnBlock);
-}
-
-void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
- // As long as debug info is modeled with instructions, we have to ensure we
- // have a place to insert here and write the stop point here.
- if (HaveInsertPoint())
- EmitStopPoint(&S);
-
- for (const auto *I : S.decls())
- EmitDecl(*I);
-}
-
-void CodeGenFunction::EmitBreakStmt(const BreakStmt &S) {
- assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!");
-
- // If this code is reachable then emit a stop point (if generating
- // debug info). We have to do this ourselves because we are on the
- // "simple" statement path.
- if (HaveInsertPoint())
- EmitStopPoint(&S);
-
- EmitBranchThroughCleanup(BreakContinueStack.back().BreakBlock);
-}
-
-void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
- assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
-
- // If this code is reachable then emit a stop point (if generating
- // debug info). We have to do this ourselves because we are on the
- // "simple" statement path.
- if (HaveInsertPoint())
- EmitStopPoint(&S);
-
- EmitBranchThroughCleanup(BreakContinueStack.back().ContinueBlock);
-}
-
-/// EmitCaseStmtRange - If case statement range is not too big then
-/// add multiple cases to switch instruction, one for each value within
-/// the range. If range is too big then emit "if" condition check.
-void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
- assert(S.getRHS() && "Expected RHS value in CaseStmt");
-
- llvm::APSInt LHS = S.getLHS()->EvaluateKnownConstInt(getContext());
- llvm::APSInt RHS = S.getRHS()->EvaluateKnownConstInt(getContext());
-
- // Emit the code for this case. We do this first to make sure it is
- // properly chained from our predecessor before generating the
- // switch machinery to enter this block.
- llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
- EmitBlockWithFallThrough(CaseDest, &S);
- EmitStmt(S.getSubStmt());
-
- // If range is empty, do nothing.
- if (LHS.isSigned() ? RHS.slt(LHS) : RHS.ult(LHS))
- return;
-
- llvm::APInt Range = RHS - LHS;
- // FIXME: parameters such as this should not be hardcoded.
- if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
- // Range is small enough to add multiple switch instruction cases.
- uint64_t Total = getProfileCount(&S);
- unsigned NCases = Range.getZExtValue() + 1;
- // We only have one region counter for the entire set of cases here, so we
- // need to divide the weights evenly between the generated cases, ensuring
- // that the total weight is preserved. E.g., a weight of 5 over three cases
- // will be distributed as weights of 2, 2, and 1.
- uint64_t Weight = Total / NCases, Rem = Total % NCases;
- for (unsigned I = 0; I != NCases; ++I) {
- if (SwitchWeights)
- SwitchWeights->push_back(Weight + (Rem ? 1 : 0));
- if (Rem)
- Rem--;
- SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
- ++LHS;
- }
- return;
- }
-
- // The range is too big. Emit "if" condition into a new block,
- // making sure to save and restore the current insertion point.
- llvm::BasicBlock *RestoreBB = Builder.GetInsertBlock();
-
- // Push this test onto the chain of range checks (which terminates
- // in the default basic block). The switch's default will be changed
- // to the top of this chain after switch emission is complete.
- llvm::BasicBlock *FalseDest = CaseRangeBlock;
- CaseRangeBlock = createBasicBlock("sw.caserange");
-
- CurFn->getBasicBlockList().push_back(CaseRangeBlock);
- Builder.SetInsertPoint(CaseRangeBlock);
-
- // Emit range check.
- llvm::Value *Diff =
- Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS));
- llvm::Value *Cond =
- Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds");
-
- llvm::MDNode *Weights = nullptr;
- if (SwitchWeights) {
- uint64_t ThisCount = getProfileCount(&S);
- uint64_t DefaultCount = (*SwitchWeights)[0];
- Weights = createProfileWeights(ThisCount, DefaultCount);
-
- // Since we're chaining the switch default through each large case range, we
- // need to update the weight for the default, ie, the first case, to include
- // this case.
- (*SwitchWeights)[0] += ThisCount;
- }
- Builder.CreateCondBr(Cond, CaseDest, FalseDest, Weights);
-
- // Restore the appropriate insertion point.
- if (RestoreBB)
- Builder.SetInsertPoint(RestoreBB);
- else
- Builder.ClearInsertionPoint();
-}
-
-void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
- // If there is no enclosing switch instance that we're aware of, then this
- // case statement and its block can be elided. This situation only happens
- // when we've constant-folded the switch, are emitting the constant case,
- // and part of the constant case includes another case statement. For
- // instance: switch (4) { case 4: do { case 5: } while (1); }
- if (!SwitchInsn) {
- EmitStmt(S.getSubStmt());
- return;
- }
-
- // Handle case ranges.
- if (S.getRHS()) {
- EmitCaseStmtRange(S);
- return;
- }
-
- llvm::ConstantInt *CaseVal =
- Builder.getInt(S.getLHS()->EvaluateKnownConstInt(getContext()));
-
- // If the body of the case is just a 'break', try to not emit an empty block.
- // If we're profiling or we're not optimizing, leave the block in for better
- // debug and coverage analysis.
- if (!CGM.getCodeGenOpts().hasProfileClangInstr() &&
- CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- isa<BreakStmt>(S.getSubStmt())) {
- JumpDest Block = BreakContinueStack.back().BreakBlock;
-
- // Only do this optimization if there are no cleanups that need emitting.
- if (isObviouslyBranchWithoutCleanups(Block)) {
- if (SwitchWeights)
- SwitchWeights->push_back(getProfileCount(&S));
- SwitchInsn->addCase(CaseVal, Block.getBlock());
-
- // If there was a fallthrough into this case, make sure to redirect it to
- // the end of the switch as well.
- if (Builder.GetInsertBlock()) {
- Builder.CreateBr(Block.getBlock());
- Builder.ClearInsertionPoint();
- }
- return;
- }
- }
-
- llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
- EmitBlockWithFallThrough(CaseDest, &S);
- if (SwitchWeights)
- SwitchWeights->push_back(getProfileCount(&S));
- SwitchInsn->addCase(CaseVal, CaseDest);
-
- // Recursively emitting the statement is acceptable, but is not wonderful for
- // code where we have many case statements nested together, i.e.:
- // case 1:
- // case 2:
- // case 3: etc.
- // Handling this recursively will create a new block for each case statement
- // that falls through to the next case which is IR intensive. It also causes
- // deep recursion which can run into stack depth limitations. Handle
- // sequential non-range case statements specially.
- const CaseStmt *CurCase = &S;
- const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt());
-
- // Otherwise, iteratively add consecutive cases to this switch stmt.
- while (NextCase && NextCase->getRHS() == nullptr) {
- CurCase = NextCase;
- llvm::ConstantInt *CaseVal =
- Builder.getInt(CurCase->getLHS()->EvaluateKnownConstInt(getContext()));
-
- if (SwitchWeights)
- SwitchWeights->push_back(getProfileCount(NextCase));
- if (CGM.getCodeGenOpts().hasProfileClangInstr()) {
- CaseDest = createBasicBlock("sw.bb");
- EmitBlockWithFallThrough(CaseDest, &S);
- }
-
- SwitchInsn->addCase(CaseVal, CaseDest);
- NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
- }
-
- // Normal default recursion for non-cases.
- EmitStmt(CurCase->getSubStmt());
-}
-
-void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {
- // If there is no enclosing switch instance that we're aware of, then this
- // default statement can be elided. This situation only happens when we've
- // constant-folded the switch.
- if (!SwitchInsn) {
- EmitStmt(S.getSubStmt());
- return;
- }
-
- llvm::BasicBlock *DefaultBlock = SwitchInsn->getDefaultDest();
- assert(DefaultBlock->empty() &&
- "EmitDefaultStmt: Default block already defined?");
-
- EmitBlockWithFallThrough(DefaultBlock, &S);
-
- EmitStmt(S.getSubStmt());
-}
-
-/// CollectStatementsForCase - Given the body of a 'switch' statement and a
-/// constant value that is being switched on, see if we can dead code eliminate
-/// the body of the switch to a simple series of statements to emit. Basically,
-/// on a switch (5) we want to find these statements:
-/// case 5:
-/// printf(...); <--
-/// ++i; <--
-/// break;
-///
-/// and add them to the ResultStmts vector. If it is unsafe to do this
-/// transformation (for example, one of the elided statements contains a label
-/// that might be jumped to), return CSFC_Failure. If we handled it and 'S'
-/// should include statements after it (e.g. the printf() line is a substmt of
-/// the case) then return CSFC_FallThrough. If we handled it and found a break
-/// statement, then return CSFC_Success.
-///
-/// If Case is non-null, then we are looking for the specified case, checking
-/// that nothing we jump over contains labels. If Case is null, then we found
-/// the case and are looking for the break.
-///
-/// If the recursive walk actually finds our Case, then we set FoundCase to
-/// true.
-///
-enum CSFC_Result { CSFC_Failure, CSFC_FallThrough, CSFC_Success };
-static CSFC_Result CollectStatementsForCase(const Stmt *S,
- const SwitchCase *Case,
- bool &FoundCase,
- SmallVectorImpl<const Stmt*> &ResultStmts) {
- // If this is a null statement, just succeed.
- if (!S)
- return Case ? CSFC_Success : CSFC_FallThrough;
-
- // If this is the switchcase (case 4: or default) that we're looking for, then
- // we're in business. Just add the substatement.
- if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) {
- if (S == Case) {
- FoundCase = true;
- return CollectStatementsForCase(SC->getSubStmt(), nullptr, FoundCase,
- ResultStmts);
- }
-
- // Otherwise, this is some other case or default statement, just ignore it.
- return CollectStatementsForCase(SC->getSubStmt(), Case, FoundCase,
- ResultStmts);
- }
-
- // If we are in the live part of the code and we found our break statement,
- // return a success!
- if (!Case && isa<BreakStmt>(S))
- return CSFC_Success;
-
- // If this is a switch statement, then it might contain the SwitchCase, the
- // break, or neither.
- if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
- // Handle this as two cases: we might be looking for the SwitchCase (if so
- // the skipped statements must be skippable) or we might already have it.
- CompoundStmt::const_body_iterator I = CS->body_begin(), E = CS->body_end();
- bool StartedInLiveCode = FoundCase;
- unsigned StartSize = ResultStmts.size();
-
- // If we've not found the case yet, scan through looking for it.
- if (Case) {
- // Keep track of whether we see a skipped declaration. The code could be
- // using the declaration even if it is skipped, so we can't optimize out
- // the decl if the kept statements might refer to it.
- bool HadSkippedDecl = false;
-
- // If we're looking for the case, just see if we can skip each of the
- // substatements.
- for (; Case && I != E; ++I) {
- HadSkippedDecl |= CodeGenFunction::mightAddDeclToScope(*I);
-
- switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) {
- case CSFC_Failure: return CSFC_Failure;
- case CSFC_Success:
- // A successful result means that either 1) that the statement doesn't
- // have the case and is skippable, or 2) does contain the case value
- // and also contains the break to exit the switch. In the later case,
- // we just verify the rest of the statements are elidable.
- if (FoundCase) {
- // If we found the case and skipped declarations, we can't do the
- // optimization.
- if (HadSkippedDecl)
- return CSFC_Failure;
-
- for (++I; I != E; ++I)
- if (CodeGenFunction::ContainsLabel(*I, true))
- return CSFC_Failure;
- return CSFC_Success;
- }
- break;
- case CSFC_FallThrough:
- // If we have a fallthrough condition, then we must have found the
- // case started to include statements. Consider the rest of the
- // statements in the compound statement as candidates for inclusion.
- assert(FoundCase && "Didn't find case but returned fallthrough?");
- // We recursively found Case, so we're not looking for it anymore.
- Case = nullptr;
-
- // If we found the case and skipped declarations, we can't do the
- // optimization.
- if (HadSkippedDecl)
- return CSFC_Failure;
- break;
- }
- }
-
- if (!FoundCase)
- return CSFC_Success;
-
- assert(!HadSkippedDecl && "fallthrough after skipping decl");
- }
-
- // If we have statements in our range, then we know that the statements are
- // live and need to be added to the set of statements we're tracking.
- bool AnyDecls = false;
- for (; I != E; ++I) {
- AnyDecls |= CodeGenFunction::mightAddDeclToScope(*I);
-
- switch (CollectStatementsForCase(*I, nullptr, FoundCase, ResultStmts)) {
- case CSFC_Failure: return CSFC_Failure;
- case CSFC_FallThrough:
- // A fallthrough result means that the statement was simple and just
- // included in ResultStmt, keep adding them afterwards.
- break;
- case CSFC_Success:
- // A successful result means that we found the break statement and
- // stopped statement inclusion. We just ensure that any leftover stmts
- // are skippable and return success ourselves.
- for (++I; I != E; ++I)
- if (CodeGenFunction::ContainsLabel(*I, true))
- return CSFC_Failure;
- return CSFC_Success;
- }
- }
-
- // If we're about to fall out of a scope without hitting a 'break;', we
- // can't perform the optimization if there were any decls in that scope
- // (we'd lose their end-of-lifetime).
- if (AnyDecls) {
- // If the entire compound statement was live, there's one more thing we
- // can try before giving up: emit the whole thing as a single statement.
- // We can do that unless the statement contains a 'break;'.
- // FIXME: Such a break must be at the end of a construct within this one.
- // We could emit this by just ignoring the BreakStmts entirely.
- if (StartedInLiveCode && !CodeGenFunction::containsBreak(S)) {
- ResultStmts.resize(StartSize);
- ResultStmts.push_back(S);
- } else {
- return CSFC_Failure;
- }
- }
-
- return CSFC_FallThrough;
- }
-
- // Okay, this is some other statement that we don't handle explicitly, like a
- // for statement or increment etc. If we are skipping over this statement,
- // just verify it doesn't have labels, which would make it invalid to elide.
- if (Case) {
- if (CodeGenFunction::ContainsLabel(S, true))
- return CSFC_Failure;
- return CSFC_Success;
- }
-
- // Otherwise, we want to include this statement. Everything is cool with that
- // so long as it doesn't contain a break out of the switch we're in.
- if (CodeGenFunction::containsBreak(S)) return CSFC_Failure;
-
- // Otherwise, everything is great. Include the statement and tell the caller
- // that we fall through and include the next statement as well.
- ResultStmts.push_back(S);
- return CSFC_FallThrough;
-}
-
-/// FindCaseStatementsForValue - Find the case statement being jumped to and
-/// then invoke CollectStatementsForCase to find the list of statements to emit
-/// for a switch on constant. See the comment above CollectStatementsForCase
-/// for more details.
-static bool FindCaseStatementsForValue(const SwitchStmt &S,
- const llvm::APSInt &ConstantCondValue,
- SmallVectorImpl<const Stmt*> &ResultStmts,
- ASTContext &C,
- const SwitchCase *&ResultCase) {
- // First step, find the switch case that is being branched to. We can do this
- // efficiently by scanning the SwitchCase list.
- const SwitchCase *Case = S.getSwitchCaseList();
- const DefaultStmt *DefaultCase = nullptr;
-
- for (; Case; Case = Case->getNextSwitchCase()) {
- // It's either a default or case. Just remember the default statement in
- // case we're not jumping to any numbered cases.
- if (const DefaultStmt *DS = dyn_cast<DefaultStmt>(Case)) {
- DefaultCase = DS;
- continue;
- }
-
- // Check to see if this case is the one we're looking for.
- const CaseStmt *CS = cast<CaseStmt>(Case);
- // Don't handle case ranges yet.
- if (CS->getRHS()) return false;
-
- // If we found our case, remember it as 'case'.
- if (CS->getLHS()->EvaluateKnownConstInt(C) == ConstantCondValue)
- break;
- }
-
- // If we didn't find a matching case, we use a default if it exists, or we
- // elide the whole switch body!
- if (!Case) {
- // It is safe to elide the body of the switch if it doesn't contain labels
- // etc. If it is safe, return successfully with an empty ResultStmts list.
- if (!DefaultCase)
- return !CodeGenFunction::ContainsLabel(&S);
- Case = DefaultCase;
- }
-
- // Ok, we know which case is being jumped to, try to collect all the
- // statements that follow it. This can fail for a variety of reasons. Also,
- // check to see that the recursive walk actually found our case statement.
- // Insane cases like this can fail to find it in the recursive walk since we
- // don't handle every stmt kind:
- // switch (4) {
- // while (1) {
- // case 4: ...
- bool FoundCase = false;
- ResultCase = Case;
- return CollectStatementsForCase(S.getBody(), Case, FoundCase,
- ResultStmts) != CSFC_Failure &&
- FoundCase;
-}
-
-void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
- // Handle nested switch statements.
- llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
- SmallVector<uint64_t, 16> *SavedSwitchWeights = SwitchWeights;
- llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
-
- // See if we can constant fold the condition of the switch and therefore only
- // emit the live case statement (if any) of the switch.
- llvm::APSInt ConstantCondValue;
- if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) {
- SmallVector<const Stmt*, 4> CaseStmts;
- const SwitchCase *Case = nullptr;
- if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts,
- getContext(), Case)) {
- if (Case)
- incrementProfileCounter(Case);
- RunCleanupsScope ExecutedScope(*this);
-
- if (S.getInit())
- EmitStmt(S.getInit());
-
- // Emit the condition variable if needed inside the entire cleanup scope
- // used by this special case for constant folded switches.
- if (S.getConditionVariable())
- EmitDecl(*S.getConditionVariable());
-
- // At this point, we are no longer "within" a switch instance, so
- // we can temporarily enforce this to ensure that any embedded case
- // statements are not emitted.
- SwitchInsn = nullptr;
-
- // Okay, we can dead code eliminate everything except this case. Emit the
- // specified series of statements and we're good.
- for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i)
- EmitStmt(CaseStmts[i]);
- incrementProfileCounter(&S);
-
- // Now we want to restore the saved switch instance so that nested
- // switches continue to function properly
- SwitchInsn = SavedSwitchInsn;
-
- return;
- }
- }
-
- JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
-
- RunCleanupsScope ConditionScope(*this);
-
- if (S.getInit())
- EmitStmt(S.getInit());
-
- if (S.getConditionVariable())
- EmitDecl(*S.getConditionVariable());
- llvm::Value *CondV = EmitScalarExpr(S.getCond());
-
- // Create basic block to hold stuff that comes after switch
- // statement. We also need to create a default block now so that
- // explicit case ranges tests can have a place to jump to on
- // failure.
- llvm::BasicBlock *DefaultBlock = createBasicBlock("sw.default");
- SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
- if (PGO.haveRegionCounts()) {
- // Walk the SwitchCase list to find how many there are.
- uint64_t DefaultCount = 0;
- unsigned NumCases = 0;
- for (const SwitchCase *Case = S.getSwitchCaseList();
- Case;
- Case = Case->getNextSwitchCase()) {
- if (isa<DefaultStmt>(Case))
- DefaultCount = getProfileCount(Case);
- NumCases += 1;
- }
- SwitchWeights = new SmallVector<uint64_t, 16>();
- SwitchWeights->reserve(NumCases);
- // The default needs to be first. We store the edge count, so we already
- // know the right weight.
- SwitchWeights->push_back(DefaultCount);
- }
- CaseRangeBlock = DefaultBlock;
-
- // Clear the insertion point to indicate we are in unreachable code.
- Builder.ClearInsertionPoint();
-
- // All break statements jump to NextBlock. If BreakContinueStack is non-empty
- // then reuse last ContinueBlock.
- JumpDest OuterContinue;
- if (!BreakContinueStack.empty())
- OuterContinue = BreakContinueStack.back().ContinueBlock;
-
- BreakContinueStack.push_back(BreakContinue(SwitchExit, OuterContinue));
-
- // Emit switch body.
- EmitStmt(S.getBody());
-
- BreakContinueStack.pop_back();
-
- // Update the default block in case explicit case range tests have
- // been chained on top.
- SwitchInsn->setDefaultDest(CaseRangeBlock);
-
- // If a default was never emitted:
- if (!DefaultBlock->getParent()) {
- // If we have cleanups, emit the default block so that there's a
- // place to jump through the cleanups from.
- if (ConditionScope.requiresCleanups()) {
- EmitBlock(DefaultBlock);
-
- // Otherwise, just forward the default block to the switch end.
- } else {
- DefaultBlock->replaceAllUsesWith(SwitchExit.getBlock());
- delete DefaultBlock;
- }
- }
-
- ConditionScope.ForceCleanup();
-
- // Emit continuation.
- EmitBlock(SwitchExit.getBlock(), true);
- incrementProfileCounter(&S);
-
- // If the switch has a condition wrapped by __builtin_unpredictable,
- // create metadata that specifies that the switch is unpredictable.
- // Don't bother if not optimizing because that metadata would not be used.
- auto *Call = dyn_cast<CallExpr>(S.getCond());
- if (Call && CGM.getCodeGenOpts().OptimizationLevel != 0) {
- auto *FD = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
- if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable) {
- llvm::MDBuilder MDHelper(getLLVMContext());
- SwitchInsn->setMetadata(llvm::LLVMContext::MD_unpredictable,
- MDHelper.createUnpredictable());
- }
- }
-
- if (SwitchWeights) {
- assert(SwitchWeights->size() == 1 + SwitchInsn->getNumCases() &&
- "switch weights do not match switch cases");
- // If there's only one jump destination there's no sense weighting it.
- if (SwitchWeights->size() > 1)
- SwitchInsn->setMetadata(llvm::LLVMContext::MD_prof,
- createProfileWeights(*SwitchWeights));
- delete SwitchWeights;
- }
- SwitchInsn = SavedSwitchInsn;
- SwitchWeights = SavedSwitchWeights;
- CaseRangeBlock = SavedCRBlock;
-}
-
-static std::string
-SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
- SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=nullptr) {
- std::string Result;
-
- while (*Constraint) {
- switch (*Constraint) {
- default:
- Result += Target.convertConstraint(Constraint);
- break;
- // Ignore these
- case '*':
- case '?':
- case '!':
- case '=': // Will see this and the following in mult-alt constraints.
- case '+':
- break;
- case '#': // Ignore the rest of the constraint alternative.
- while (Constraint[1] && Constraint[1] != ',')
- Constraint++;
- break;
- case '&':
- case '%':
- Result += *Constraint;
- while (Constraint[1] && Constraint[1] == *Constraint)
- Constraint++;
- break;
- case ',':
- Result += "|";
- break;
- case 'g':
- Result += "imr";
- break;
- case '[': {
- assert(OutCons &&
- "Must pass output names to constraints with a symbolic name");
- unsigned Index;
- bool result = Target.resolveSymbolicName(Constraint, *OutCons, Index);
- assert(result && "Could not resolve symbolic name"); (void)result;
- Result += llvm::utostr(Index);
- break;
- }
- }
-
- Constraint++;
- }
-
- return Result;
-}
-
-/// AddVariableConstraints - Look at AsmExpr and if it is a variable declared
-/// as using a particular register add that as a constraint that will be used
-/// in this asm stmt.
-static std::string
-AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
- const TargetInfo &Target, CodeGenModule &CGM,
- const AsmStmt &Stmt, const bool EarlyClobber) {
- const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(&AsmExpr);
- if (!AsmDeclRef)
- return Constraint;
- const ValueDecl &Value = *AsmDeclRef->getDecl();
- const VarDecl *Variable = dyn_cast<VarDecl>(&Value);
- if (!Variable)
- return Constraint;
- if (Variable->getStorageClass() != SC_Register)
- return Constraint;
- AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>();
- if (!Attr)
- return Constraint;
- StringRef Register = Attr->getLabel();
- assert(Target.isValidGCCRegisterName(Register));
- // We're using validateOutputConstraint here because we only care if
- // this is a register constraint.
- TargetInfo::ConstraintInfo Info(Constraint, "");
- if (Target.validateOutputConstraint(Info) &&
- !Info.allowsRegister()) {
- CGM.ErrorUnsupported(&Stmt, "__asm__");
- return Constraint;
- }
- // Canonicalize the register here before returning it.
- Register = Target.getNormalizedGCCRegisterName(Register);
- return (EarlyClobber ? "&{" : "{") + Register.str() + "}";
-}
-
-llvm::Value*
-CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
- LValue InputValue, QualType InputType,
- std::string &ConstraintStr,
- SourceLocation Loc) {
- llvm::Value *Arg;
- if (Info.allowsRegister() || !Info.allowsMemory()) {
- if (CodeGenFunction::hasScalarEvaluationKind(InputType)) {
- Arg = EmitLoadOfLValue(InputValue, Loc).getScalarVal();
- } else {
- llvm::Type *Ty = ConvertType(InputType);
- uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
- if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
- Ty = llvm::IntegerType::get(getLLVMContext(), Size);
- Ty = llvm::PointerType::getUnqual(Ty);
-
- Arg = Builder.CreateLoad(Builder.CreateBitCast(InputValue.getAddress(),
- Ty));
- } else {
- Arg = InputValue.getPointer();
- ConstraintStr += '*';
- }
- }
- } else {
- Arg = InputValue.getPointer();
- ConstraintStr += '*';
- }
-
- return Arg;
-}
-
-llvm::Value* CodeGenFunction::EmitAsmInput(
- const TargetInfo::ConstraintInfo &Info,
- const Expr *InputExpr,
- std::string &ConstraintStr) {
- // If this can't be a register or memory, i.e., has to be a constant
- // (immediate or symbolic), try to emit it as such.
- if (!Info.allowsRegister() && !Info.allowsMemory()) {
- if (Info.requiresImmediateConstant()) {
- Expr::EvalResult EVResult;
- InputExpr->EvaluateAsRValue(EVResult, getContext(), true);
-
- llvm::APSInt IntResult;
- if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
- getContext()))
- llvm_unreachable("Invalid immediate constant!");
-
- return llvm::ConstantInt::get(getLLVMContext(), IntResult);
- }
-
- Expr::EvalResult Result;
- if (InputExpr->EvaluateAsInt(Result, getContext()))
- return llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt());
- }
-
- if (Info.allowsRegister() || !Info.allowsMemory())
- if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
- return EmitScalarExpr(InputExpr);
- if (InputExpr->getStmtClass() == Expr::CXXThisExprClass)
- return EmitScalarExpr(InputExpr);
- InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
- LValue Dest = EmitLValue(InputExpr);
- return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr,
- InputExpr->getExprLoc());
-}
-
-/// getAsmSrcLocInfo - Return the !srcloc metadata node to attach to an inline
-/// asm call instruction. The !srcloc MDNode contains a list of constant
-/// integers which are the source locations of the start of each line in the
-/// asm.
-static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
- CodeGenFunction &CGF) {
- SmallVector<llvm::Metadata *, 8> Locs;
- // Add the location of the first line to the MDNode.
- Locs.push_back(llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- CGF.Int32Ty, Str->getBeginLoc().getRawEncoding())));
- StringRef StrVal = Str->getString();
- if (!StrVal.empty()) {
- const SourceManager &SM = CGF.CGM.getContext().getSourceManager();
- const LangOptions &LangOpts = CGF.CGM.getLangOpts();
- unsigned StartToken = 0;
- unsigned ByteOffset = 0;
-
- // Add the location of the start of each subsequent line of the asm to the
- // MDNode.
- for (unsigned i = 0, e = StrVal.size() - 1; i != e; ++i) {
- if (StrVal[i] != '\n') continue;
- SourceLocation LineLoc = Str->getLocationOfByte(
- i + 1, SM, LangOpts, CGF.getTarget(), &StartToken, &ByteOffset);
- Locs.push_back(llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(CGF.Int32Ty, LineLoc.getRawEncoding())));
- }
- }
-
- return llvm::MDNode::get(CGF.getLLVMContext(), Locs);
-}
-
-void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
- // Assemble the final asm string.
- std::string AsmString = S.generateAsmString(getContext());
-
- // Get all the output and input constraints together.
- SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
- SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
-
- for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
- StringRef Name;
- if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
- Name = GAS->getOutputName(i);
- TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name);
- bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid;
- assert(IsValid && "Failed to parse output constraint");
- OutputConstraintInfos.push_back(Info);
- }
-
- for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
- StringRef Name;
- if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
- Name = GAS->getInputName(i);
- TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), Name);
- bool IsValid =
- getTarget().validateInputConstraint(OutputConstraintInfos, Info);
- assert(IsValid && "Failed to parse input constraint"); (void)IsValid;
- InputConstraintInfos.push_back(Info);
- }
-
- std::string Constraints;
-
- std::vector<LValue> ResultRegDests;
- std::vector<QualType> ResultRegQualTys;
- std::vector<llvm::Type *> ResultRegTypes;
- std::vector<llvm::Type *> ResultTruncRegTypes;
- std::vector<llvm::Type *> ArgTypes;
- std::vector<llvm::Value*> Args;
-
- // Keep track of inout constraints.
- std::string InOutConstraints;
- std::vector<llvm::Value*> InOutArgs;
- std::vector<llvm::Type*> InOutArgTypes;
-
- // An inline asm can be marked readonly if it meets the following conditions:
- // - it doesn't have any sideeffects
- // - it doesn't clobber memory
- // - it doesn't return a value by-reference
- // It can be marked readnone if it doesn't have any input memory constraints
- // in addition to meeting the conditions listed above.
- bool ReadOnly = true, ReadNone = true;
-
- for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
- TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
-
- // Simplify the output constraint.
- std::string OutputConstraint(S.getOutputConstraint(i));
- OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1,
- getTarget(), &OutputConstraintInfos);
-
- const Expr *OutExpr = S.getOutputExpr(i);
- OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
-
- OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr,
- getTarget(), CGM, S,
- Info.earlyClobber());
-
- LValue Dest = EmitLValue(OutExpr);
- if (!Constraints.empty())
- Constraints += ',';
-
- // If this is a register output, then make the inline asm return it
- // by-value. If this is a memory result, return the value by-reference.
- if (!Info.allowsMemory() && hasScalarEvaluationKind(OutExpr->getType())) {
- Constraints += "=" + OutputConstraint;
- ResultRegQualTys.push_back(OutExpr->getType());
- ResultRegDests.push_back(Dest);
- ResultRegTypes.push_back(ConvertTypeForMem(OutExpr->getType()));
- ResultTruncRegTypes.push_back(ResultRegTypes.back());
-
- // If this output is tied to an input, and if the input is larger, then
- // we need to set the actual result type of the inline asm node to be the
- // same as the input type.
- if (Info.hasMatchingInput()) {
- unsigned InputNo;
- for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
- TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
- if (Input.hasTiedOperand() && Input.getTiedOperand() == i)
- break;
- }
- assert(InputNo != S.getNumInputs() && "Didn't find matching input!");
-
- QualType InputTy = S.getInputExpr(InputNo)->getType();
- QualType OutputType = OutExpr->getType();
-
- uint64_t InputSize = getContext().getTypeSize(InputTy);
- if (getContext().getTypeSize(OutputType) < InputSize) {
- // Form the asm to return the value as a larger integer or fp type.
- ResultRegTypes.back() = ConvertType(InputTy);
- }
- }
- if (llvm::Type* AdjTy =
- getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
- ResultRegTypes.back()))
- ResultRegTypes.back() = AdjTy;
- else {
- CGM.getDiags().Report(S.getAsmLoc(),
- diag::err_asm_invalid_type_in_input)
- << OutExpr->getType() << OutputConstraint;
- }
-
- // Update largest vector width for any vector types.
- if (auto *VT = dyn_cast<llvm::VectorType>(ResultRegTypes.back()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
- } else {
- ArgTypes.push_back(Dest.getAddress().getType());
- Args.push_back(Dest.getPointer());
- Constraints += "=*";
- Constraints += OutputConstraint;
- ReadOnly = ReadNone = false;
- }
-
- if (Info.isReadWrite()) {
- InOutConstraints += ',';
-
- const Expr *InputExpr = S.getOutputExpr(i);
- llvm::Value *Arg = EmitAsmInputLValue(Info, Dest, InputExpr->getType(),
- InOutConstraints,
- InputExpr->getExprLoc());
-
- if (llvm::Type* AdjTy =
- getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
- Arg->getType()))
- Arg = Builder.CreateBitCast(Arg, AdjTy);
-
- // Update largest vector width for any vector types.
- if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
- if (Info.allowsRegister())
- InOutConstraints += llvm::utostr(i);
- else
- InOutConstraints += OutputConstraint;
-
- InOutArgTypes.push_back(Arg->getType());
- InOutArgs.push_back(Arg);
- }
- }
-
- // If this is a Microsoft-style asm blob, store the return registers (EAX:EDX)
- // to the return value slot. Only do this when returning in registers.
- if (isa<MSAsmStmt>(&S)) {
- const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
- if (RetAI.isDirect() || RetAI.isExtend()) {
- // Make a fake lvalue for the return value slot.
- LValue ReturnSlot = MakeAddrLValue(ReturnValue, FnRetTy);
- CGM.getTargetCodeGenInfo().addReturnRegisterOutputs(
- *this, ReturnSlot, Constraints, ResultRegTypes, ResultTruncRegTypes,
- ResultRegDests, AsmString, S.getNumOutputs());
- SawAsmBlock = true;
- }
- }
-
- for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
- const Expr *InputExpr = S.getInputExpr(i);
-
- TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
-
- if (Info.allowsMemory())
- ReadNone = false;
-
- if (!Constraints.empty())
- Constraints += ',';
-
- // Simplify the input constraint.
- std::string InputConstraint(S.getInputConstraint(i));
- InputConstraint = SimplifyConstraint(InputConstraint.c_str(), getTarget(),
- &OutputConstraintInfos);
-
- InputConstraint = AddVariableConstraints(
- InputConstraint, *InputExpr->IgnoreParenNoopCasts(getContext()),
- getTarget(), CGM, S, false /* No EarlyClobber */);
-
- llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints);
-
- // If this input argument is tied to a larger output result, extend the
- // input to be the same size as the output. The LLVM backend wants to see
- // the input and output of a matching constraint be the same size. Note
- // that GCC does not define what the top bits are here. We use zext because
- // that is usually cheaper, but LLVM IR should really get an anyext someday.
- if (Info.hasTiedOperand()) {
- unsigned Output = Info.getTiedOperand();
- QualType OutputType = S.getOutputExpr(Output)->getType();
- QualType InputTy = InputExpr->getType();
-
- if (getContext().getTypeSize(OutputType) >
- getContext().getTypeSize(InputTy)) {
- // Use ptrtoint as appropriate so that we can do our extension.
- if (isa<llvm::PointerType>(Arg->getType()))
- Arg = Builder.CreatePtrToInt(Arg, IntPtrTy);
- llvm::Type *OutputTy = ConvertType(OutputType);
- if (isa<llvm::IntegerType>(OutputTy))
- Arg = Builder.CreateZExt(Arg, OutputTy);
- else if (isa<llvm::PointerType>(OutputTy))
- Arg = Builder.CreateZExt(Arg, IntPtrTy);
- else {
- assert(OutputTy->isFloatingPointTy() && "Unexpected output type");
- Arg = Builder.CreateFPExt(Arg, OutputTy);
- }
- }
- }
- if (llvm::Type* AdjTy =
- getTargetHooks().adjustInlineAsmType(*this, InputConstraint,
- Arg->getType()))
- Arg = Builder.CreateBitCast(Arg, AdjTy);
- else
- CGM.getDiags().Report(S.getAsmLoc(), diag::err_asm_invalid_type_in_input)
- << InputExpr->getType() << InputConstraint;
-
- // Update largest vector width for any vector types.
- if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
-
- ArgTypes.push_back(Arg->getType());
- Args.push_back(Arg);
- Constraints += InputConstraint;
- }
-
- // Append the "input" part of inout constraints last.
- for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) {
- ArgTypes.push_back(InOutArgTypes[i]);
- Args.push_back(InOutArgs[i]);
- }
- Constraints += InOutConstraints;
-
- // Clobbers
- for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
- StringRef Clobber = S.getClobber(i);
-
- if (Clobber == "memory")
- ReadOnly = ReadNone = false;
- else if (Clobber != "cc")
- Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
-
- if (!Constraints.empty())
- Constraints += ',';
-
- Constraints += "~{";
- Constraints += Clobber;
- Constraints += '}';
- }
-
- // Add machine specific clobbers
- std::string MachineClobbers = getTarget().getClobbers();
- if (!MachineClobbers.empty()) {
- if (!Constraints.empty())
- Constraints += ',';
- Constraints += MachineClobbers;
- }
-
- llvm::Type *ResultType;
- if (ResultRegTypes.empty())
- ResultType = VoidTy;
- else if (ResultRegTypes.size() == 1)
- ResultType = ResultRegTypes[0];
- else
- ResultType = llvm::StructType::get(getLLVMContext(), ResultRegTypes);
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(ResultType, ArgTypes, false);
-
- bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
- llvm::InlineAsm::AsmDialect AsmDialect = isa<MSAsmStmt>(&S) ?
- llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT;
- llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
- /* IsAlignStack */ false, AsmDialect);
- llvm::CallInst *Result =
- Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
- Result->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind);
-
- // Attach readnone and readonly attributes.
- if (!HasSideEffect) {
- if (ReadNone)
- Result->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::ReadNone);
- else if (ReadOnly)
- Result->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::ReadOnly);
- }
-
- // Slap the source location of the inline asm into a !srcloc metadata on the
- // call.
- if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) {
- Result->setMetadata("srcloc", getAsmSrcLocInfo(gccAsmStmt->getAsmString(),
- *this));
- } else {
- // At least put the line number on MS inline asm blobs.
- auto Loc = llvm::ConstantInt::get(Int32Ty, S.getAsmLoc().getRawEncoding());
- Result->setMetadata("srcloc",
- llvm::MDNode::get(getLLVMContext(),
- llvm::ConstantAsMetadata::get(Loc)));
- }
-
- if (getLangOpts().assumeFunctionsAreConvergent()) {
- // Conservatively, mark all inline asm blocks in CUDA or OpenCL as
- // convergent (meaning, they may call an intrinsically convergent op, such
- // as bar.sync, and so can't have certain optimizations applied around
- // them).
- Result->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::Convergent);
- }
-
- // Extract all of the register value results from the asm.
- std::vector<llvm::Value*> RegResults;
- if (ResultRegTypes.size() == 1) {
- RegResults.push_back(Result);
- } else {
- for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
- llvm::Value *Tmp = Builder.CreateExtractValue(Result, i, "asmresult");
- RegResults.push_back(Tmp);
- }
- }
-
- assert(RegResults.size() == ResultRegTypes.size());
- assert(RegResults.size() == ResultTruncRegTypes.size());
- assert(RegResults.size() == ResultRegDests.size());
- for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
- llvm::Value *Tmp = RegResults[i];
-
- // If the result type of the LLVM IR asm doesn't match the result type of
- // the expression, do the conversion.
- if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
- llvm::Type *TruncTy = ResultTruncRegTypes[i];
-
- // Truncate the integer result to the right size, note that TruncTy can be
- // a pointer.
- if (TruncTy->isFloatingPointTy())
- Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
- else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
- uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy);
- Tmp = Builder.CreateTrunc(Tmp,
- llvm::IntegerType::get(getLLVMContext(), (unsigned)ResSize));
- Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
- } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
- uint64_t TmpSize =CGM.getDataLayout().getTypeSizeInBits(Tmp->getType());
- Tmp = Builder.CreatePtrToInt(Tmp,
- llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize));
- Tmp = Builder.CreateTrunc(Tmp, TruncTy);
- } else if (TruncTy->isIntegerTy()) {
- Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
- } else if (TruncTy->isVectorTy()) {
- Tmp = Builder.CreateBitCast(Tmp, TruncTy);
- }
- }
-
- EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
- }
-}
-
-LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) {
- const RecordDecl *RD = S.getCapturedRecordDecl();
- QualType RecordTy = getContext().getRecordType(RD);
-
- // Initialize the captured struct.
- LValue SlotLV =
- MakeAddrLValue(CreateMemTemp(RecordTy, "agg.captured"), RecordTy);
-
- RecordDecl::field_iterator CurField = RD->field_begin();
- for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(),
- E = S.capture_init_end();
- I != E; ++I, ++CurField) {
- LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
- if (CurField->hasCapturedVLAType()) {
- auto VAT = CurField->getCapturedVLAType();
- EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV);
- } else {
- EmitInitializerForField(*CurField, LV, *I);
- }
- }
-
- return SlotLV;
-}
-
-/// Generate an outlined function for the body of a CapturedStmt, store any
-/// captured variables into the captured struct, and call the outlined function.
-llvm::Function *
-CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
- LValue CapStruct = InitCapturedStruct(S);
-
- // Emit the CapturedDecl
- CodeGenFunction CGF(CGM, true);
- CGCapturedStmtRAII CapInfoRAII(CGF, new CGCapturedStmtInfo(S, K));
- llvm::Function *F = CGF.GenerateCapturedStmtFunction(S);
- delete CGF.CapturedStmtInfo;
-
- // Emit call to the helper function.
- EmitCallOrInvoke(F, CapStruct.getPointer());
-
- return F;
-}
-
-Address CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) {
- LValue CapStruct = InitCapturedStruct(S);
- return CapStruct.getAddress();
-}
-
-/// Creates the outlined function for a CapturedStmt.
-llvm::Function *
-CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) {
- assert(CapturedStmtInfo &&
- "CapturedStmtInfo should be set when generating the captured function");
- const CapturedDecl *CD = S.getCapturedDecl();
- const RecordDecl *RD = S.getCapturedRecordDecl();
- SourceLocation Loc = S.getBeginLoc();
- assert(CD->hasBody() && "missing CapturedDecl body");
-
- // Build the argument list.
- ASTContext &Ctx = CGM.getContext();
- FunctionArgList Args;
- Args.append(CD->param_begin(), CD->param_end());
-
- // Create the function declaration.
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
- llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
-
- llvm::Function *F =
- llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
- CapturedStmtInfo->getHelperName(), &CGM.getModule());
- CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
- if (CD->isNothrow())
- F->addFnAttr(llvm::Attribute::NoUnwind);
-
- // Generate the function.
- StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(),
- CD->getBody()->getBeginLoc());
- // Set the context parameter in CapturedStmtInfo.
- Address DeclPtr = GetAddrOfLocalVar(CD->getContextParam());
- CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr));
-
- // Initialize variable-length arrays.
- LValue Base = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(),
- Ctx.getTagDeclType(RD));
- for (auto *FD : RD->fields()) {
- if (FD->hasCapturedVLAType()) {
- auto *ExprArg =
- EmitLoadOfLValue(EmitLValueForField(Base, FD), S.getBeginLoc())
- .getScalarVal();
- auto VAT = FD->getCapturedVLAType();
- VLASizeMap[VAT->getSizeExpr()] = ExprArg;
- }
- }
-
- // If 'this' is captured, load it into CXXThisValue.
- if (CapturedStmtInfo->isCXXThisExprCaptured()) {
- FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl();
- LValue ThisLValue = EmitLValueForField(Base, FD);
- CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
- }
-
- PGO.assignRegionCounters(GlobalDecl(CD), F);
- CapturedStmtInfo->EmitBody(*this, CD->getBody());
- FinishFunction(CD->getBodyRBrace());
-
- return F;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp
deleted file mode 100644
index 44dc1cdee0b..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ /dev/null
@@ -1,5081 +0,0 @@
-//===--- CGStmtOpenMP.cpp - Emit LLVM Code from Statements ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code to emit OpenMP nodes as LLVM code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCleanup.h"
-#include "CGOpenMPRuntime.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/StmtOpenMP.h"
-#include "clang/AST/DeclOpenMP.h"
-#include "llvm/IR/CallSite.h"
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-/// Lexical scope for OpenMP executable constructs, that handles correct codegen
-/// for captured expressions.
-class OMPLexicalScope : public CodeGenFunction::LexicalScope {
- void emitPreInitStmt(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
- for (const auto *C : S.clauses()) {
- if (const auto *CPI = OMPClauseWithPreInit::get(C)) {
- if (const auto *PreInit =
- cast_or_null<DeclStmt>(CPI->getPreInitStmt())) {
- for (const auto *I : PreInit->decls()) {
- if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
- CGF.EmitVarDecl(cast<VarDecl>(*I));
- } else {
- CodeGenFunction::AutoVarEmission Emission =
- CGF.EmitAutoVarAlloca(cast<VarDecl>(*I));
- CGF.EmitAutoVarCleanups(Emission);
- }
- }
- }
- }
- }
- }
- CodeGenFunction::OMPPrivateScope InlinedShareds;
-
- static bool isCapturedVar(CodeGenFunction &CGF, const VarDecl *VD) {
- return CGF.LambdaCaptureFields.lookup(VD) ||
- (CGF.CapturedStmtInfo && CGF.CapturedStmtInfo->lookup(VD)) ||
- (CGF.CurCodeDecl && isa<BlockDecl>(CGF.CurCodeDecl));
- }
-
-public:
- OMPLexicalScope(
- CodeGenFunction &CGF, const OMPExecutableDirective &S,
- const llvm::Optional<OpenMPDirectiveKind> CapturedRegion = llvm::None,
- const bool EmitPreInitStmt = true)
- : CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
- InlinedShareds(CGF) {
- if (EmitPreInitStmt)
- emitPreInitStmt(CGF, S);
- if (!CapturedRegion.hasValue())
- return;
- assert(S.hasAssociatedStmt() &&
- "Expected associated statement for inlined directive.");
- const CapturedStmt *CS = S.getCapturedStmt(*CapturedRegion);
- for (const auto &C : CS->captures()) {
- if (C.capturesVariable() || C.capturesVariableByCopy()) {
- auto *VD = C.getCapturedVar();
- assert(VD == VD->getCanonicalDecl() &&
- "Canonical decl must be captured.");
- DeclRefExpr DRE(
- CGF.getContext(), const_cast<VarDecl *>(VD),
- isCapturedVar(CGF, VD) || (CGF.CapturedStmtInfo &&
- InlinedShareds.isGlobalVarCaptured(VD)),
- VD->getType().getNonReferenceType(), VK_LValue, C.getLocation());
- InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address {
- return CGF.EmitLValue(&DRE).getAddress();
- });
- }
- }
- (void)InlinedShareds.Privatize();
- }
-};
-
-/// Lexical scope for OpenMP parallel construct, that handles correct codegen
-/// for captured expressions.
-class OMPParallelScope final : public OMPLexicalScope {
- bool EmitPreInitStmt(const OMPExecutableDirective &S) {
- OpenMPDirectiveKind Kind = S.getDirectiveKind();
- return !(isOpenMPTargetExecutionDirective(Kind) ||
- isOpenMPLoopBoundSharingDirective(Kind)) &&
- isOpenMPParallelDirective(Kind);
- }
-
-public:
- OMPParallelScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
- : OMPLexicalScope(CGF, S, /*CapturedRegion=*/llvm::None,
- EmitPreInitStmt(S)) {}
-};
-
-/// Lexical scope for OpenMP teams construct, that handles correct codegen
-/// for captured expressions.
-class OMPTeamsScope final : public OMPLexicalScope {
- bool EmitPreInitStmt(const OMPExecutableDirective &S) {
- OpenMPDirectiveKind Kind = S.getDirectiveKind();
- return !isOpenMPTargetExecutionDirective(Kind) &&
- isOpenMPTeamsDirective(Kind);
- }
-
-public:
- OMPTeamsScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
- : OMPLexicalScope(CGF, S, /*CapturedRegion=*/llvm::None,
- EmitPreInitStmt(S)) {}
-};
-
-/// Private scope for OpenMP loop-based directives, that supports capturing
-/// of used expression from loop statement.
-class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
- void emitPreInitStmt(CodeGenFunction &CGF, const OMPLoopDirective &S) {
- CodeGenFunction::OMPMapVars PreCondVars;
- for (const auto *E : S.counters()) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- (void)PreCondVars.setVarAddr(
- CGF, VD, CGF.CreateMemTemp(VD->getType().getNonReferenceType()));
- }
- (void)PreCondVars.apply(CGF);
- if (const auto *PreInits = cast_or_null<DeclStmt>(S.getPreInits())) {
- for (const auto *I : PreInits->decls())
- CGF.EmitVarDecl(cast<VarDecl>(*I));
- }
- PreCondVars.restore(CGF);
- }
-
-public:
- OMPLoopScope(CodeGenFunction &CGF, const OMPLoopDirective &S)
- : CodeGenFunction::RunCleanupsScope(CGF) {
- emitPreInitStmt(CGF, S);
- }
-};
-
-class OMPSimdLexicalScope : public CodeGenFunction::LexicalScope {
- CodeGenFunction::OMPPrivateScope InlinedShareds;
-
- static bool isCapturedVar(CodeGenFunction &CGF, const VarDecl *VD) {
- return CGF.LambdaCaptureFields.lookup(VD) ||
- (CGF.CapturedStmtInfo && CGF.CapturedStmtInfo->lookup(VD)) ||
- (CGF.CurCodeDecl && isa<BlockDecl>(CGF.CurCodeDecl) &&
- cast<BlockDecl>(CGF.CurCodeDecl)->capturesVariable(VD));
- }
-
-public:
- OMPSimdLexicalScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
- : CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
- InlinedShareds(CGF) {
- for (const auto *C : S.clauses()) {
- if (const auto *CPI = OMPClauseWithPreInit::get(C)) {
- if (const auto *PreInit =
- cast_or_null<DeclStmt>(CPI->getPreInitStmt())) {
- for (const auto *I : PreInit->decls()) {
- if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
- CGF.EmitVarDecl(cast<VarDecl>(*I));
- } else {
- CodeGenFunction::AutoVarEmission Emission =
- CGF.EmitAutoVarAlloca(cast<VarDecl>(*I));
- CGF.EmitAutoVarCleanups(Emission);
- }
- }
- }
- } else if (const auto *UDP = dyn_cast<OMPUseDevicePtrClause>(C)) {
- for (const Expr *E : UDP->varlists()) {
- const Decl *D = cast<DeclRefExpr>(E)->getDecl();
- if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(D))
- CGF.EmitVarDecl(*OED);
- }
- }
- }
- if (!isOpenMPSimdDirective(S.getDirectiveKind()))
- CGF.EmitOMPPrivateClause(S, InlinedShareds);
- if (const auto *TG = dyn_cast<OMPTaskgroupDirective>(&S)) {
- if (const Expr *E = TG->getReductionRef())
- CGF.EmitVarDecl(*cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()));
- }
- const auto *CS = cast_or_null<CapturedStmt>(S.getAssociatedStmt());
- while (CS) {
- for (auto &C : CS->captures()) {
- if (C.capturesVariable() || C.capturesVariableByCopy()) {
- auto *VD = C.getCapturedVar();
- assert(VD == VD->getCanonicalDecl() &&
- "Canonical decl must be captured.");
- DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(VD),
- isCapturedVar(CGF, VD) ||
- (CGF.CapturedStmtInfo &&
- InlinedShareds.isGlobalVarCaptured(VD)),
- VD->getType().getNonReferenceType(), VK_LValue,
- C.getLocation());
- InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address {
- return CGF.EmitLValue(&DRE).getAddress();
- });
- }
- }
- CS = dyn_cast<CapturedStmt>(CS->getCapturedStmt());
- }
- (void)InlinedShareds.Privatize();
- }
-};
-
-} // namespace
-
-static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
- const OMPExecutableDirective &S,
- const RegionCodeGenTy &CodeGen);
-
-LValue CodeGenFunction::EmitOMPSharedLValue(const Expr *E) {
- if (const auto *OrigDRE = dyn_cast<DeclRefExpr>(E)) {
- if (const auto *OrigVD = dyn_cast<VarDecl>(OrigDRE->getDecl())) {
- OrigVD = OrigVD->getCanonicalDecl();
- bool IsCaptured =
- LambdaCaptureFields.lookup(OrigVD) ||
- (CapturedStmtInfo && CapturedStmtInfo->lookup(OrigVD)) ||
- (CurCodeDecl && isa<BlockDecl>(CurCodeDecl));
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD), IsCaptured,
- OrigDRE->getType(), VK_LValue, OrigDRE->getExprLoc());
- return EmitLValue(&DRE);
- }
- }
- return EmitLValue(E);
-}
-
-llvm::Value *CodeGenFunction::getTypeSize(QualType Ty) {
- ASTContext &C = getContext();
- llvm::Value *Size = nullptr;
- auto SizeInChars = C.getTypeSizeInChars(Ty);
- if (SizeInChars.isZero()) {
- // getTypeSizeInChars() returns 0 for a VLA.
- while (const VariableArrayType *VAT = C.getAsVariableArrayType(Ty)) {
- VlaSizePair VlaSize = getVLASize(VAT);
- Ty = VlaSize.Type;
- Size = Size ? Builder.CreateNUWMul(Size, VlaSize.NumElts)
- : VlaSize.NumElts;
- }
- SizeInChars = C.getTypeSizeInChars(Ty);
- if (SizeInChars.isZero())
- return llvm::ConstantInt::get(SizeTy, /*V=*/0);
- return Builder.CreateNUWMul(Size, CGM.getSize(SizeInChars));
- }
- return CGM.getSize(SizeInChars);
-}
-
-void CodeGenFunction::GenerateOpenMPCapturedVars(
- const CapturedStmt &S, SmallVectorImpl<llvm::Value *> &CapturedVars) {
- const RecordDecl *RD = S.getCapturedRecordDecl();
- auto CurField = RD->field_begin();
- auto CurCap = S.captures().begin();
- for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(),
- E = S.capture_init_end();
- I != E; ++I, ++CurField, ++CurCap) {
- if (CurField->hasCapturedVLAType()) {
- const VariableArrayType *VAT = CurField->getCapturedVLAType();
- llvm::Value *Val = VLASizeMap[VAT->getSizeExpr()];
- CapturedVars.push_back(Val);
- } else if (CurCap->capturesThis()) {
- CapturedVars.push_back(CXXThisValue);
- } else if (CurCap->capturesVariableByCopy()) {
- llvm::Value *CV = EmitLoadOfScalar(EmitLValue(*I), CurCap->getLocation());
-
- // If the field is not a pointer, we need to save the actual value
- // and load it as a void pointer.
- if (!CurField->getType()->isAnyPointerType()) {
- ASTContext &Ctx = getContext();
- Address DstAddr = CreateMemTemp(
- Ctx.getUIntPtrType(),
- Twine(CurCap->getCapturedVar()->getName(), ".casted"));
- LValue DstLV = MakeAddrLValue(DstAddr, Ctx.getUIntPtrType());
-
- llvm::Value *SrcAddrVal = EmitScalarConversion(
- DstAddr.getPointer(), Ctx.getPointerType(Ctx.getUIntPtrType()),
- Ctx.getPointerType(CurField->getType()), CurCap->getLocation());
- LValue SrcLV =
- MakeNaturalAlignAddrLValue(SrcAddrVal, CurField->getType());
-
- // Store the value using the source type pointer.
- EmitStoreThroughLValue(RValue::get(CV), SrcLV);
-
- // Load the value using the destination type pointer.
- CV = EmitLoadOfScalar(DstLV, CurCap->getLocation());
- }
- CapturedVars.push_back(CV);
- } else {
- assert(CurCap->capturesVariable() && "Expected capture by reference.");
- CapturedVars.push_back(EmitLValue(*I).getAddress().getPointer());
- }
- }
-}
-
-static Address castValueFromUintptr(CodeGenFunction &CGF, SourceLocation Loc,
- QualType DstType, StringRef Name,
- LValue AddrLV,
- bool isReferenceType = false) {
- ASTContext &Ctx = CGF.getContext();
-
- llvm::Value *CastedPtr = CGF.EmitScalarConversion(
- AddrLV.getAddress().getPointer(), Ctx.getUIntPtrType(),
- Ctx.getPointerType(DstType), Loc);
- Address TmpAddr =
- CGF.MakeNaturalAlignAddrLValue(CastedPtr, Ctx.getPointerType(DstType))
- .getAddress();
-
- // If we are dealing with references we need to return the address of the
- // reference instead of the reference of the value.
- if (isReferenceType) {
- QualType RefType = Ctx.getLValueReferenceType(DstType);
- llvm::Value *RefVal = TmpAddr.getPointer();
- TmpAddr = CGF.CreateMemTemp(RefType, Twine(Name, ".ref"));
- LValue TmpLVal = CGF.MakeAddrLValue(TmpAddr, RefType);
- CGF.EmitStoreThroughLValue(RValue::get(RefVal), TmpLVal, /*isInit=*/true);
- }
-
- return TmpAddr;
-}
-
-static QualType getCanonicalParamType(ASTContext &C, QualType T) {
- if (T->isLValueReferenceType())
- return C.getLValueReferenceType(
- getCanonicalParamType(C, T.getNonReferenceType()),
- /*SpelledAsLValue=*/false);
- if (T->isPointerType())
- return C.getPointerType(getCanonicalParamType(C, T->getPointeeType()));
- if (const ArrayType *A = T->getAsArrayTypeUnsafe()) {
- if (const auto *VLA = dyn_cast<VariableArrayType>(A))
- return getCanonicalParamType(C, VLA->getElementType());
- if (!A->isVariablyModifiedType())
- return C.getCanonicalType(T);
- }
- return C.getCanonicalParamType(T);
-}
-
-namespace {
- /// Contains required data for proper outlined function codegen.
- struct FunctionOptions {
- /// Captured statement for which the function is generated.
- const CapturedStmt *S = nullptr;
- /// true if cast to/from UIntPtr is required for variables captured by
- /// value.
- const bool UIntPtrCastRequired = true;
- /// true if only casted arguments must be registered as local args or VLA
- /// sizes.
- const bool RegisterCastedArgsOnly = false;
- /// Name of the generated function.
- const StringRef FunctionName;
- explicit FunctionOptions(const CapturedStmt *S, bool UIntPtrCastRequired,
- bool RegisterCastedArgsOnly,
- StringRef FunctionName)
- : S(S), UIntPtrCastRequired(UIntPtrCastRequired),
- RegisterCastedArgsOnly(UIntPtrCastRequired && RegisterCastedArgsOnly),
- FunctionName(FunctionName) {}
- };
-}
-
-static llvm::Function *emitOutlinedFunctionPrologue(
- CodeGenFunction &CGF, FunctionArgList &Args,
- llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>>
- &LocalAddrs,
- llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>>
- &VLASizes,
- llvm::Value *&CXXThisValue, const FunctionOptions &FO) {
- const CapturedDecl *CD = FO.S->getCapturedDecl();
- const RecordDecl *RD = FO.S->getCapturedRecordDecl();
- assert(CD->hasBody() && "missing CapturedDecl body");
-
- CXXThisValue = nullptr;
- // Build the argument list.
- CodeGenModule &CGM = CGF.CGM;
- ASTContext &Ctx = CGM.getContext();
- FunctionArgList TargetArgs;
- Args.append(CD->param_begin(),
- std::next(CD->param_begin(), CD->getContextParamPosition()));
- TargetArgs.append(
- CD->param_begin(),
- std::next(CD->param_begin(), CD->getContextParamPosition()));
- auto I = FO.S->captures().begin();
- FunctionDecl *DebugFunctionDecl = nullptr;
- if (!FO.UIntPtrCastRequired) {
- FunctionProtoType::ExtProtoInfo EPI;
- QualType FunctionTy = Ctx.getFunctionType(Ctx.VoidTy, llvm::None, EPI);
- DebugFunctionDecl = FunctionDecl::Create(
- Ctx, Ctx.getTranslationUnitDecl(), FO.S->getBeginLoc(),
- SourceLocation(), DeclarationName(), FunctionTy,
- Ctx.getTrivialTypeSourceInfo(FunctionTy), SC_Static,
- /*isInlineSpecified=*/false, /*hasWrittenPrototype=*/false);
- }
- for (const FieldDecl *FD : RD->fields()) {
- QualType ArgType = FD->getType();
- IdentifierInfo *II = nullptr;
- VarDecl *CapVar = nullptr;
-
- // If this is a capture by copy and the type is not a pointer, the outlined
- // function argument type should be uintptr and the value properly casted to
- // uintptr. This is necessary given that the runtime library is only able to
- // deal with pointers. We can pass in the same way the VLA type sizes to the
- // outlined function.
- if (FO.UIntPtrCastRequired &&
- ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) ||
- I->capturesVariableArrayType()))
- ArgType = Ctx.getUIntPtrType();
-
- if (I->capturesVariable() || I->capturesVariableByCopy()) {
- CapVar = I->getCapturedVar();
- II = CapVar->getIdentifier();
- } else if (I->capturesThis()) {
- II = &Ctx.Idents.get("this");
- } else {
- assert(I->capturesVariableArrayType());
- II = &Ctx.Idents.get("vla");
- }
- if (ArgType->isVariablyModifiedType())
- ArgType = getCanonicalParamType(Ctx, ArgType);
- VarDecl *Arg;
- if (DebugFunctionDecl && (CapVar || I->capturesThis())) {
- Arg = ParmVarDecl::Create(
- Ctx, DebugFunctionDecl,
- CapVar ? CapVar->getBeginLoc() : FD->getBeginLoc(),
- CapVar ? CapVar->getLocation() : FD->getLocation(), II, ArgType,
- /*TInfo=*/nullptr, SC_None, /*DefArg=*/nullptr);
- } else {
- Arg = ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(),
- II, ArgType, ImplicitParamDecl::Other);
- }
- Args.emplace_back(Arg);
- // Do not cast arguments if we emit function with non-original types.
- TargetArgs.emplace_back(
- FO.UIntPtrCastRequired
- ? Arg
- : CGM.getOpenMPRuntime().translateParameter(FD, Arg));
- ++I;
- }
- Args.append(
- std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
- CD->param_end());
- TargetArgs.append(
- std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
- CD->param_end());
-
- // Create the function declaration.
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, TargetArgs);
- llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
-
- auto *F =
- llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
- FO.FunctionName, &CGM.getModule());
- CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
- if (CD->isNothrow())
- F->setDoesNotThrow();
- F->setDoesNotRecurse();
-
- // Generate the function.
- CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, TargetArgs,
- FO.S->getBeginLoc(), CD->getBody()->getBeginLoc());
- unsigned Cnt = CD->getContextParamPosition();
- I = FO.S->captures().begin();
- for (const FieldDecl *FD : RD->fields()) {
- // Do not map arguments if we emit function with non-original types.
- Address LocalAddr(Address::invalid());
- if (!FO.UIntPtrCastRequired && Args[Cnt] != TargetArgs[Cnt]) {
- LocalAddr = CGM.getOpenMPRuntime().getParameterAddress(CGF, Args[Cnt],
- TargetArgs[Cnt]);
- } else {
- LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]);
- }
- // If we are capturing a pointer by copy we don't need to do anything, just
- // use the value that we get from the arguments.
- if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) {
- const VarDecl *CurVD = I->getCapturedVar();
- // If the variable is a reference we need to materialize it here.
- if (CurVD->getType()->isReferenceType()) {
- Address RefAddr = CGF.CreateMemTemp(
- CurVD->getType(), CGM.getPointerAlign(), ".materialized_ref");
- CGF.EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr,
- /*Volatile=*/false, CurVD->getType());
- LocalAddr = RefAddr;
- }
- if (!FO.RegisterCastedArgsOnly)
- LocalAddrs.insert({Args[Cnt], {CurVD, LocalAddr}});
- ++Cnt;
- ++I;
- continue;
- }
-
- LValue ArgLVal = CGF.MakeAddrLValue(LocalAddr, Args[Cnt]->getType(),
- AlignmentSource::Decl);
- if (FD->hasCapturedVLAType()) {
- if (FO.UIntPtrCastRequired) {
- ArgLVal = CGF.MakeAddrLValue(
- castValueFromUintptr(CGF, I->getLocation(), FD->getType(),
- Args[Cnt]->getName(), ArgLVal),
- FD->getType(), AlignmentSource::Decl);
- }
- llvm::Value *ExprArg = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation());
- const VariableArrayType *VAT = FD->getCapturedVLAType();
- VLASizes.try_emplace(Args[Cnt], VAT->getSizeExpr(), ExprArg);
- } else if (I->capturesVariable()) {
- const VarDecl *Var = I->getCapturedVar();
- QualType VarTy = Var->getType();
- Address ArgAddr = ArgLVal.getAddress();
- if (!VarTy->isReferenceType()) {
- if (ArgLVal.getType()->isLValueReferenceType()) {
- ArgAddr = CGF.EmitLoadOfReference(ArgLVal);
- } else if (!VarTy->isVariablyModifiedType() ||
- !VarTy->isPointerType()) {
- assert(ArgLVal.getType()->isPointerType());
- ArgAddr = CGF.EmitLoadOfPointer(
- ArgAddr, ArgLVal.getType()->castAs<PointerType>());
- }
- }
- if (!FO.RegisterCastedArgsOnly) {
- LocalAddrs.insert(
- {Args[Cnt],
- {Var, Address(ArgAddr.getPointer(), Ctx.getDeclAlign(Var))}});
- }
- } else if (I->capturesVariableByCopy()) {
- assert(!FD->getType()->isAnyPointerType() &&
- "Not expecting a captured pointer.");
- const VarDecl *Var = I->getCapturedVar();
- QualType VarTy = Var->getType();
- LocalAddrs.insert(
- {Args[Cnt],
- {Var, FO.UIntPtrCastRequired
- ? castValueFromUintptr(CGF, I->getLocation(),
- FD->getType(), Args[Cnt]->getName(),
- ArgLVal, VarTy->isReferenceType())
- : ArgLVal.getAddress()}});
- } else {
- // If 'this' is captured, load it into CXXThisValue.
- assert(I->capturesThis());
- CXXThisValue = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation());
- LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress()}});
- }
- ++Cnt;
- ++I;
- }
-
- return F;
-}
-
-llvm::Function *
-CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
- assert(
- CapturedStmtInfo &&
- "CapturedStmtInfo should be set when generating the captured function");
- const CapturedDecl *CD = S.getCapturedDecl();
- // Build the argument list.
- bool NeedWrapperFunction =
- getDebugInfo() &&
- CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo;
- FunctionArgList Args;
- llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs;
- llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes;
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- Out << CapturedStmtInfo->getHelperName();
- if (NeedWrapperFunction)
- Out << "_debug__";
- FunctionOptions FO(&S, !NeedWrapperFunction, /*RegisterCastedArgsOnly=*/false,
- Out.str());
- llvm::Function *F = emitOutlinedFunctionPrologue(*this, Args, LocalAddrs,
- VLASizes, CXXThisValue, FO);
- for (const auto &LocalAddrPair : LocalAddrs) {
- if (LocalAddrPair.second.first) {
- setAddrOfLocalVar(LocalAddrPair.second.first,
- LocalAddrPair.second.second);
- }
- }
- for (const auto &VLASizePair : VLASizes)
- VLASizeMap[VLASizePair.second.first] = VLASizePair.second.second;
- PGO.assignRegionCounters(GlobalDecl(CD), F);
- CapturedStmtInfo->EmitBody(*this, CD->getBody());
- FinishFunction(CD->getBodyRBrace());
- if (!NeedWrapperFunction)
- return F;
-
- FunctionOptions WrapperFO(&S, /*UIntPtrCastRequired=*/true,
- /*RegisterCastedArgsOnly=*/true,
- CapturedStmtInfo->getHelperName());
- CodeGenFunction WrapperCGF(CGM, /*suppressNewContext=*/true);
- WrapperCGF.CapturedStmtInfo = CapturedStmtInfo;
- Args.clear();
- LocalAddrs.clear();
- VLASizes.clear();
- llvm::Function *WrapperF =
- emitOutlinedFunctionPrologue(WrapperCGF, Args, LocalAddrs, VLASizes,
- WrapperCGF.CXXThisValue, WrapperFO);
- llvm::SmallVector<llvm::Value *, 4> CallArgs;
- for (const auto *Arg : Args) {
- llvm::Value *CallArg;
- auto I = LocalAddrs.find(Arg);
- if (I != LocalAddrs.end()) {
- LValue LV = WrapperCGF.MakeAddrLValue(
- I->second.second,
- I->second.first ? I->second.first->getType() : Arg->getType(),
- AlignmentSource::Decl);
- CallArg = WrapperCGF.EmitLoadOfScalar(LV, S.getBeginLoc());
- } else {
- auto EI = VLASizes.find(Arg);
- if (EI != VLASizes.end()) {
- CallArg = EI->second.second;
- } else {
- LValue LV = WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg),
- Arg->getType(),
- AlignmentSource::Decl);
- CallArg = WrapperCGF.EmitLoadOfScalar(LV, S.getBeginLoc());
- }
- }
- CallArgs.emplace_back(WrapperCGF.EmitFromMemory(CallArg, Arg->getType()));
- }
- CGM.getOpenMPRuntime().emitOutlinedFunctionCall(WrapperCGF, S.getBeginLoc(),
- F, CallArgs);
- WrapperCGF.FinishFunction();
- return WrapperF;
-}
-
-//===----------------------------------------------------------------------===//
-// OpenMP Directive Emission
-//===----------------------------------------------------------------------===//
-void CodeGenFunction::EmitOMPAggregateAssign(
- Address DestAddr, Address SrcAddr, QualType OriginalType,
- const llvm::function_ref<void(Address, Address)> CopyGen) {
- // Perform element-by-element initialization.
- QualType ElementTy;
-
- // Drill down to the base element type on both arrays.
- const ArrayType *ArrayTy = OriginalType->getAsArrayTypeUnsafe();
- llvm::Value *NumElements = emitArrayLength(ArrayTy, ElementTy, DestAddr);
- SrcAddr = Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
-
- llvm::Value *SrcBegin = SrcAddr.getPointer();
- llvm::Value *DestBegin = DestAddr.getPointer();
- // Cast from pointer to array type to pointer to single element.
- llvm::Value *DestEnd = Builder.CreateGEP(DestBegin, NumElements);
- // The basic structure here is a while-do loop.
- llvm::BasicBlock *BodyBB = createBasicBlock("omp.arraycpy.body");
- llvm::BasicBlock *DoneBB = createBasicBlock("omp.arraycpy.done");
- llvm::Value *IsEmpty =
- Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
- Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
-
- // Enter the loop body, making that address the current address.
- llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
- EmitBlock(BodyBB);
-
- CharUnits ElementSize = getContext().getTypeSizeInChars(ElementTy);
-
- llvm::PHINode *SrcElementPHI =
- Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast");
- SrcElementPHI->addIncoming(SrcBegin, EntryBB);
- Address SrcElementCurrent =
- Address(SrcElementPHI,
- SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
-
- llvm::PHINode *DestElementPHI =
- Builder.CreatePHI(DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
- DestElementPHI->addIncoming(DestBegin, EntryBB);
- Address DestElementCurrent =
- Address(DestElementPHI,
- DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
-
- // Emit copy.
- CopyGen(DestElementCurrent, SrcElementCurrent);
-
- // Shift the address forward by one element.
- llvm::Value *DestElementNext = Builder.CreateConstGEP1_32(
- DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- llvm::Value *SrcElementNext = Builder.CreateConstGEP1_32(
- SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.src.element");
- // Check whether we've reached the end.
- llvm::Value *Done =
- Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
- Builder.CreateCondBr(Done, DoneBB, BodyBB);
- DestElementPHI->addIncoming(DestElementNext, Builder.GetInsertBlock());
- SrcElementPHI->addIncoming(SrcElementNext, Builder.GetInsertBlock());
-
- // Done.
- EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
-void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr,
- Address SrcAddr, const VarDecl *DestVD,
- const VarDecl *SrcVD, const Expr *Copy) {
- if (OriginalType->isArrayType()) {
- const auto *BO = dyn_cast<BinaryOperator>(Copy);
- if (BO && BO->getOpcode() == BO_Assign) {
- // Perform simple memcpy for simple copying.
- LValue Dest = MakeAddrLValue(DestAddr, OriginalType);
- LValue Src = MakeAddrLValue(SrcAddr, OriginalType);
- EmitAggregateAssign(Dest, Src, OriginalType);
- } else {
- // For arrays with complex element types perform element by element
- // copying.
- EmitOMPAggregateAssign(
- DestAddr, SrcAddr, OriginalType,
- [this, Copy, SrcVD, DestVD](Address DestElement, Address SrcElement) {
- // Working with the single array element, so have to remap
- // destination and source variables to corresponding array
- // elements.
- CodeGenFunction::OMPPrivateScope Remap(*this);
- Remap.addPrivate(DestVD, [DestElement]() { return DestElement; });
- Remap.addPrivate(SrcVD, [SrcElement]() { return SrcElement; });
- (void)Remap.Privatize();
- EmitIgnoredExpr(Copy);
- });
- }
- } else {
- // Remap pseudo source variable to private copy.
- CodeGenFunction::OMPPrivateScope Remap(*this);
- Remap.addPrivate(SrcVD, [SrcAddr]() { return SrcAddr; });
- Remap.addPrivate(DestVD, [DestAddr]() { return DestAddr; });
- (void)Remap.Privatize();
- // Emit copying of the whole variable.
- EmitIgnoredExpr(Copy);
- }
-}
-
-bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
- OMPPrivateScope &PrivateScope) {
- if (!HaveInsertPoint())
- return false;
- bool FirstprivateIsLastprivate = false;
- llvm::DenseSet<const VarDecl *> Lastprivates;
- for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
- for (const auto *D : C->varlists())
- Lastprivates.insert(
- cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl());
- }
- llvm::DenseSet<const VarDecl *> EmittedAsFirstprivate;
- llvm::SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
- getOpenMPCaptureRegions(CaptureRegions, D.getDirectiveKind());
- // Force emission of the firstprivate copy if the directive does not emit
- // outlined function, like omp for, omp simd, omp distribute etc.
- bool MustEmitFirstprivateCopy =
- CaptureRegions.size() == 1 && CaptureRegions.back() == OMPD_unknown;
- for (const auto *C : D.getClausesOfKind<OMPFirstprivateClause>()) {
- auto IRef = C->varlist_begin();
- auto InitsRef = C->inits().begin();
- for (const Expr *IInit : C->private_copies()) {
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- bool ThisFirstprivateIsLastprivate =
- Lastprivates.count(OrigVD->getCanonicalDecl()) > 0;
- const FieldDecl *FD = CapturedStmtInfo->lookup(OrigVD);
- if (!MustEmitFirstprivateCopy && !ThisFirstprivateIsLastprivate && FD &&
- !FD->getType()->isReferenceType()) {
- EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl());
- ++IRef;
- ++InitsRef;
- continue;
- }
- FirstprivateIsLastprivate =
- FirstprivateIsLastprivate || ThisFirstprivateIsLastprivate;
- if (EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl()).second) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
- const auto *VDInit =
- cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
- bool IsRegistered;
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
- /*RefersToEnclosingVariableOrCapture=*/FD != nullptr,
- (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
- LValue OriginalLVal = EmitLValue(&DRE);
- QualType Type = VD->getType();
- if (Type->isArrayType()) {
- // Emit VarDecl with copy init for arrays.
- // Get the address of the original variable captured in current
- // captured region.
- IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, VD, Type, OriginalLVal, VDInit]() {
- AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
- const Expr *Init = VD->getInit();
- if (!isa<CXXConstructExpr>(Init) ||
- isTrivialInitializer(Init)) {
- // Perform simple memcpy.
- LValue Dest =
- MakeAddrLValue(Emission.getAllocatedAddress(), Type);
- EmitAggregateAssign(Dest, OriginalLVal, Type);
- } else {
- EmitOMPAggregateAssign(
- Emission.getAllocatedAddress(), OriginalLVal.getAddress(),
- Type,
- [this, VDInit, Init](Address DestElement,
- Address SrcElement) {
- // Clean up any temporaries needed by the
- // initialization.
- RunCleanupsScope InitScope(*this);
- // Emit initialization for single element.
- setAddrOfLocalVar(VDInit, SrcElement);
- EmitAnyExprToMem(Init, DestElement,
- Init->getType().getQualifiers(),
- /*IsInitializer*/ false);
- LocalDeclMap.erase(VDInit);
- });
- }
- EmitAutoVarCleanups(Emission);
- return Emission.getAllocatedAddress();
- });
- } else {
- Address OriginalAddr = OriginalLVal.getAddress();
- IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, VDInit, OriginalAddr, VD]() {
- // Emit private VarDecl with copy init.
- // Remap temp VDInit variable to the address of the original
- // variable (for proper handling of captured global variables).
- setAddrOfLocalVar(VDInit, OriginalAddr);
- EmitDecl(*VD);
- LocalDeclMap.erase(VDInit);
- return GetAddrOfLocalVar(VD);
- });
- }
- assert(IsRegistered &&
- "firstprivate var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- }
- ++IRef;
- ++InitsRef;
- }
- }
- return FirstprivateIsLastprivate && !EmittedAsFirstprivate.empty();
-}
-
-void CodeGenFunction::EmitOMPPrivateClause(
- const OMPExecutableDirective &D,
- CodeGenFunction::OMPPrivateScope &PrivateScope) {
- if (!HaveInsertPoint())
- return;
- llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
- for (const auto *C : D.getClausesOfKind<OMPPrivateClause>()) {
- auto IRef = C->varlist_begin();
- for (const Expr *IInit : C->private_copies()) {
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
- bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, VD]() {
- // Emit private VarDecl with copy init.
- EmitDecl(*VD);
- return GetAddrOfLocalVar(VD);
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- }
- ++IRef;
- }
- }
-}
-
-bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) {
- if (!HaveInsertPoint())
- return false;
- // threadprivate_var1 = master_threadprivate_var1;
- // operator=(threadprivate_var2, master_threadprivate_var2);
- // ...
- // __kmpc_barrier(&loc, global_tid);
- llvm::DenseSet<const VarDecl *> CopiedVars;
- llvm::BasicBlock *CopyBegin = nullptr, *CopyEnd = nullptr;
- for (const auto *C : D.getClausesOfKind<OMPCopyinClause>()) {
- auto IRef = C->varlist_begin();
- auto ISrcRef = C->source_exprs().begin();
- auto IDestRef = C->destination_exprs().begin();
- for (const Expr *AssignOp : C->assignment_ops()) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- QualType Type = VD->getType();
- if (CopiedVars.insert(VD->getCanonicalDecl()).second) {
- // Get the address of the master variable. If we are emitting code with
- // TLS support, the address is passed from the master as field in the
- // captured declaration.
- Address MasterAddr = Address::invalid();
- if (getLangOpts().OpenMPUseTLS &&
- getContext().getTargetInfo().isTLSSupported()) {
- assert(CapturedStmtInfo->lookup(VD) &&
- "Copyin threadprivates should have been captured!");
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD), true,
- (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
- MasterAddr = EmitLValue(&DRE).getAddress();
- LocalDeclMap.erase(VD);
- } else {
- MasterAddr =
- Address(VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD)
- : CGM.GetAddrOfGlobal(VD),
- getContext().getDeclAlign(VD));
- }
- // Get the address of the threadprivate variable.
- Address PrivateAddr = EmitLValue(*IRef).getAddress();
- if (CopiedVars.size() == 1) {
- // At first check if current thread is a master thread. If it is, no
- // need to copy data.
- CopyBegin = createBasicBlock("copyin.not.master");
- CopyEnd = createBasicBlock("copyin.not.master.end");
- Builder.CreateCondBr(
- Builder.CreateICmpNE(
- Builder.CreatePtrToInt(MasterAddr.getPointer(), CGM.IntPtrTy),
- Builder.CreatePtrToInt(PrivateAddr.getPointer(),
- CGM.IntPtrTy)),
- CopyBegin, CopyEnd);
- EmitBlock(CopyBegin);
- }
- const auto *SrcVD =
- cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
- const auto *DestVD =
- cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
- EmitOMPCopy(Type, PrivateAddr, MasterAddr, DestVD, SrcVD, AssignOp);
- }
- ++IRef;
- ++ISrcRef;
- ++IDestRef;
- }
- }
- if (CopyEnd) {
- // Exit out of copying procedure for non-master thread.
- EmitBlock(CopyEnd, /*IsFinished=*/true);
- return true;
- }
- return false;
-}
-
-bool CodeGenFunction::EmitOMPLastprivateClauseInit(
- const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) {
- if (!HaveInsertPoint())
- return false;
- bool HasAtLeastOneLastprivate = false;
- llvm::DenseSet<const VarDecl *> SIMDLCVs;
- if (isOpenMPSimdDirective(D.getDirectiveKind())) {
- const auto *LoopDirective = cast<OMPLoopDirective>(&D);
- for (const Expr *C : LoopDirective->counters()) {
- SIMDLCVs.insert(
- cast<VarDecl>(cast<DeclRefExpr>(C)->getDecl())->getCanonicalDecl());
- }
- }
- llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
- for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
- HasAtLeastOneLastprivate = true;
- if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) &&
- !getLangOpts().OpenMPSimd)
- break;
- auto IRef = C->varlist_begin();
- auto IDestRef = C->destination_exprs().begin();
- for (const Expr *IInit : C->private_copies()) {
- // Keep the address of the original variable for future update at the end
- // of the loop.
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- // Taskloops do not require additional initialization, it is done in
- // runtime support library.
- if (AlreadyEmittedVars.insert(OrigVD->getCanonicalDecl()).second) {
- const auto *DestVD =
- cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
- PrivateScope.addPrivate(DestVD, [this, OrigVD, IRef]() {
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
- /*RefersToEnclosingVariableOrCapture=*/
- CapturedStmtInfo->lookup(OrigVD) != nullptr,
- (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
- return EmitLValue(&DRE).getAddress();
- });
- // Check if the variable is also a firstprivate: in this case IInit is
- // not generated. Initialization of this variable will happen in codegen
- // for 'firstprivate' clause.
- if (IInit && !SIMDLCVs.count(OrigVD->getCanonicalDecl())) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
- bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, VD]() {
- // Emit private VarDecl with copy init.
- EmitDecl(*VD);
- return GetAddrOfLocalVar(VD);
- });
- assert(IsRegistered &&
- "lastprivate var already registered as private");
- (void)IsRegistered;
- }
- }
- ++IRef;
- ++IDestRef;
- }
- }
- return HasAtLeastOneLastprivate;
-}
-
-void CodeGenFunction::EmitOMPLastprivateClauseFinal(
- const OMPExecutableDirective &D, bool NoFinals,
- llvm::Value *IsLastIterCond) {
- if (!HaveInsertPoint())
- return;
- // Emit following code:
- // if (<IsLastIterCond>) {
- // orig_var1 = private_orig_var1;
- // ...
- // orig_varn = private_orig_varn;
- // }
- llvm::BasicBlock *ThenBB = nullptr;
- llvm::BasicBlock *DoneBB = nullptr;
- if (IsLastIterCond) {
- ThenBB = createBasicBlock(".omp.lastprivate.then");
- DoneBB = createBasicBlock(".omp.lastprivate.done");
- Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
- EmitBlock(ThenBB);
- }
- llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
- llvm::DenseMap<const VarDecl *, const Expr *> LoopCountersAndUpdates;
- if (const auto *LoopDirective = dyn_cast<OMPLoopDirective>(&D)) {
- auto IC = LoopDirective->counters().begin();
- for (const Expr *F : LoopDirective->finals()) {
- const auto *D =
- cast<VarDecl>(cast<DeclRefExpr>(*IC)->getDecl())->getCanonicalDecl();
- if (NoFinals)
- AlreadyEmittedVars.insert(D);
- else
- LoopCountersAndUpdates[D] = F;
- ++IC;
- }
- }
- for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
- auto IRef = C->varlist_begin();
- auto ISrcRef = C->source_exprs().begin();
- auto IDestRef = C->destination_exprs().begin();
- for (const Expr *AssignOp : C->assignment_ops()) {
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- QualType Type = PrivateVD->getType();
- const auto *CanonicalVD = PrivateVD->getCanonicalDecl();
- if (AlreadyEmittedVars.insert(CanonicalVD).second) {
- // If lastprivate variable is a loop control variable for loop-based
- // directive, update its value before copyin back to original
- // variable.
- if (const Expr *FinalExpr = LoopCountersAndUpdates.lookup(CanonicalVD))
- EmitIgnoredExpr(FinalExpr);
- const auto *SrcVD =
- cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
- const auto *DestVD =
- cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
- // Get the address of the original variable.
- Address OriginalAddr = GetAddrOfLocalVar(DestVD);
- // Get the address of the private variable.
- Address PrivateAddr = GetAddrOfLocalVar(PrivateVD);
- if (const auto *RefTy = PrivateVD->getType()->getAs<ReferenceType>())
- PrivateAddr =
- Address(Builder.CreateLoad(PrivateAddr),
- getNaturalTypeAlignment(RefTy->getPointeeType()));
- EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp);
- }
- ++IRef;
- ++ISrcRef;
- ++IDestRef;
- }
- if (const Expr *PostUpdate = C->getPostUpdateExpr())
- EmitIgnoredExpr(PostUpdate);
- }
- if (IsLastIterCond)
- EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
-void CodeGenFunction::EmitOMPReductionClauseInit(
- const OMPExecutableDirective &D,
- CodeGenFunction::OMPPrivateScope &PrivateScope) {
- if (!HaveInsertPoint())
- return;
- SmallVector<const Expr *, 4> Shareds;
- SmallVector<const Expr *, 4> Privates;
- SmallVector<const Expr *, 4> ReductionOps;
- SmallVector<const Expr *, 4> LHSs;
- SmallVector<const Expr *, 4> RHSs;
- for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
- auto IPriv = C->privates().begin();
- auto IRed = C->reduction_ops().begin();
- auto ILHS = C->lhs_exprs().begin();
- auto IRHS = C->rhs_exprs().begin();
- for (const Expr *Ref : C->varlists()) {
- Shareds.emplace_back(Ref);
- Privates.emplace_back(*IPriv);
- ReductionOps.emplace_back(*IRed);
- LHSs.emplace_back(*ILHS);
- RHSs.emplace_back(*IRHS);
- std::advance(IPriv, 1);
- std::advance(IRed, 1);
- std::advance(ILHS, 1);
- std::advance(IRHS, 1);
- }
- }
- ReductionCodeGen RedCG(Shareds, Privates, ReductionOps);
- unsigned Count = 0;
- auto ILHS = LHSs.begin();
- auto IRHS = RHSs.begin();
- auto IPriv = Privates.begin();
- for (const Expr *IRef : Shareds) {
- const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
- // Emit private VarDecl with reduction init.
- RedCG.emitSharedLValue(*this, Count);
- RedCG.emitAggregateType(*this, Count);
- AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
- RedCG.emitInitialization(*this, Count, Emission.getAllocatedAddress(),
- RedCG.getSharedLValue(Count),
- [&Emission](CodeGenFunction &CGF) {
- CGF.EmitAutoVarInit(Emission);
- return true;
- });
- EmitAutoVarCleanups(Emission);
- Address BaseAddr = RedCG.adjustPrivateAddress(
- *this, Count, Emission.getAllocatedAddress());
- bool IsRegistered = PrivateScope.addPrivate(
- RedCG.getBaseDecl(Count), [BaseAddr]() { return BaseAddr; });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
-
- const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
- const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
- QualType Type = PrivateVD->getType();
- bool isaOMPArraySectionExpr = isa<OMPArraySectionExpr>(IRef);
- if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) {
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() {
- return RedCG.getSharedLValue(Count).getAddress();
- });
- PrivateScope.addPrivate(
- RHSVD, [this, PrivateVD]() { return GetAddrOfLocalVar(PrivateVD); });
- } else if ((isaOMPArraySectionExpr && Type->isScalarType()) ||
- isa<ArraySubscriptExpr>(IRef)) {
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() {
- return RedCG.getSharedLValue(Count).getAddress();
- });
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() {
- return Builder.CreateElementBitCast(GetAddrOfLocalVar(PrivateVD),
- ConvertTypeForMem(RHSVD->getType()),
- "rhs.begin");
- });
- } else {
- QualType Type = PrivateVD->getType();
- bool IsArray = getContext().getAsArrayType(Type) != nullptr;
- Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress();
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- if (IsArray) {
- OriginalAddr = Builder.CreateElementBitCast(
- OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
- }
- PrivateScope.addPrivate(LHSVD, [OriginalAddr]() { return OriginalAddr; });
- PrivateScope.addPrivate(
- RHSVD, [this, PrivateVD, RHSVD, IsArray]() {
- return IsArray
- ? Builder.CreateElementBitCast(
- GetAddrOfLocalVar(PrivateVD),
- ConvertTypeForMem(RHSVD->getType()), "rhs.begin")
- : GetAddrOfLocalVar(PrivateVD);
- });
- }
- ++ILHS;
- ++IRHS;
- ++IPriv;
- ++Count;
- }
-}
-
-void CodeGenFunction::EmitOMPReductionClauseFinal(
- const OMPExecutableDirective &D, const OpenMPDirectiveKind ReductionKind) {
- if (!HaveInsertPoint())
- return;
- llvm::SmallVector<const Expr *, 8> Privates;
- llvm::SmallVector<const Expr *, 8> LHSExprs;
- llvm::SmallVector<const Expr *, 8> RHSExprs;
- llvm::SmallVector<const Expr *, 8> ReductionOps;
- bool HasAtLeastOneReduction = false;
- for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
- HasAtLeastOneReduction = true;
- Privates.append(C->privates().begin(), C->privates().end());
- LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
- RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
- ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
- }
- if (HasAtLeastOneReduction) {
- bool WithNowait = D.getSingleClause<OMPNowaitClause>() ||
- isOpenMPParallelDirective(D.getDirectiveKind()) ||
- ReductionKind == OMPD_simd;
- bool SimpleReduction = ReductionKind == OMPD_simd;
- // Emit nowait reduction if nowait clause is present or directive is a
- // parallel directive (it always has implicit barrier).
- CGM.getOpenMPRuntime().emitReduction(
- *this, D.getEndLoc(), Privates, LHSExprs, RHSExprs, ReductionOps,
- {WithNowait, SimpleReduction, ReductionKind});
- }
-}
-
-static void emitPostUpdateForReductionClause(
- CodeGenFunction &CGF, const OMPExecutableDirective &D,
- const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
- if (!CGF.HaveInsertPoint())
- return;
- llvm::BasicBlock *DoneBB = nullptr;
- for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
- if (const Expr *PostUpdate = C->getPostUpdateExpr()) {
- if (!DoneBB) {
- if (llvm::Value *Cond = CondGen(CGF)) {
- // If the first post-update expression is found, emit conditional
- // block if it was requested.
- llvm::BasicBlock *ThenBB = CGF.createBasicBlock(".omp.reduction.pu");
- DoneBB = CGF.createBasicBlock(".omp.reduction.pu.done");
- CGF.Builder.CreateCondBr(Cond, ThenBB, DoneBB);
- CGF.EmitBlock(ThenBB);
- }
- }
- CGF.EmitIgnoredExpr(PostUpdate);
- }
- }
- if (DoneBB)
- CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
-namespace {
-/// Codegen lambda for appending distribute lower and upper bounds to outlined
-/// parallel function. This is necessary for combined constructs such as
-/// 'distribute parallel for'
-typedef llvm::function_ref<void(CodeGenFunction &,
- const OMPExecutableDirective &,
- llvm::SmallVectorImpl<llvm::Value *> &)>
- CodeGenBoundParametersTy;
-} // anonymous namespace
-
-static void emitCommonOMPParallelDirective(
- CodeGenFunction &CGF, const OMPExecutableDirective &S,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
- const CodeGenBoundParametersTy &CodeGenBoundParameters) {
- const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
- llvm::Value *OutlinedFn =
- CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction(
- S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
- if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>()) {
- CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
- llvm::Value *NumThreads =
- CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
- /*IgnoreResultAssign=*/true);
- CGF.CGM.getOpenMPRuntime().emitNumThreadsClause(
- CGF, NumThreads, NumThreadsClause->getBeginLoc());
- }
- if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>()) {
- CodeGenFunction::RunCleanupsScope ProcBindScope(CGF);
- CGF.CGM.getOpenMPRuntime().emitProcBindClause(
- CGF, ProcBindClause->getProcBindKind(), ProcBindClause->getBeginLoc());
- }
- const Expr *IfCond = nullptr;
- for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
- if (C->getNameModifier() == OMPD_unknown ||
- C->getNameModifier() == OMPD_parallel) {
- IfCond = C->getCondition();
- break;
- }
- }
-
- OMPParallelScope Scope(CGF, S);
- llvm::SmallVector<llvm::Value *, 16> CapturedVars;
- // Combining 'distribute' with 'for' requires sharing each 'distribute' chunk
- // lower and upper bounds with the pragma 'for' chunking mechanism.
- // The following lambda takes care of appending the lower and upper bound
- // parameters when necessary
- CodeGenBoundParameters(CGF, S, CapturedVars);
- CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
- CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getBeginLoc(), OutlinedFn,
- CapturedVars, IfCond);
-}
-
-static void emitEmptyBoundParameters(CodeGenFunction &,
- const OMPExecutableDirective &,
- llvm::SmallVectorImpl<llvm::Value *> &) {}
-
-void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
- // Emit parallel region as a standalone region.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPPrivateScope PrivateScope(CGF);
- bool Copyins = CGF.EmitOMPCopyinClause(S);
- (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- if (Copyins) {
- // Emit implicit barrier to synchronize threads and avoid data races on
- // propagation master's thread values of threadprivate variables to local
- // instances of that variables of all other implicit threads.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
- }
- CGF.EmitOMPPrivateClause(S, PrivateScope);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.EmitStmt(S.getCapturedStmt(OMPD_parallel)->getCapturedStmt());
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
- };
- emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen,
- emitEmptyBoundParameters);
- emitPostUpdateForReductionClause(*this, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
- JumpDest LoopExit) {
- RunCleanupsScope BodyScope(*this);
- // Update counters values on current iteration.
- for (const Expr *UE : D.updates())
- EmitIgnoredExpr(UE);
- // Update the linear variables.
- // In distribute directives only loop counters may be marked as linear, no
- // need to generate the code for them.
- if (!isOpenMPDistributeDirective(D.getDirectiveKind())) {
- for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
- for (const Expr *UE : C->updates())
- EmitIgnoredExpr(UE);
- }
- }
-
- // On a continue in the body, jump to the end.
- JumpDest Continue = getJumpDestInCurrentScope("omp.body.continue");
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
- // Emit loop body.
- EmitStmt(D.getBody());
- // The end (updates/cleanups).
- EmitBlock(Continue.getBlock());
- BreakContinueStack.pop_back();
-}
-
-void CodeGenFunction::EmitOMPInnerLoop(
- const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
- const Expr *IncExpr,
- const llvm::function_ref<void(CodeGenFunction &)> BodyGen,
- const llvm::function_ref<void(CodeGenFunction &)> PostIncGen) {
- auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
-
- // Start the loop with a block that tests the condition.
- auto CondBlock = createBasicBlock("omp.inner.for.cond");
- EmitBlock(CondBlock);
- const SourceRange R = S.getSourceRange();
- LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()),
- SourceLocToDebugLoc(R.getEnd()));
-
- // If there are any cleanups between here and the loop-exit scope,
- // create a block to stage a loop exit along.
- llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
- if (RequiresCleanup)
- ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup");
-
- llvm::BasicBlock *LoopBody = createBasicBlock("omp.inner.for.body");
-
- // Emit condition.
- EmitBranchOnBoolExpr(LoopCond, LoopBody, ExitBlock, getProfileCount(&S));
- if (ExitBlock != LoopExit.getBlock()) {
- EmitBlock(ExitBlock);
- EmitBranchThroughCleanup(LoopExit);
- }
-
- EmitBlock(LoopBody);
- incrementProfileCounter(&S);
-
- // Create a block for the increment.
- JumpDest Continue = getJumpDestInCurrentScope("omp.inner.for.inc");
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
-
- BodyGen(*this);
-
- // Emit "IV = IV + 1" and a back-edge to the condition block.
- EmitBlock(Continue.getBlock());
- EmitIgnoredExpr(IncExpr);
- PostIncGen(*this);
- BreakContinueStack.pop_back();
- EmitBranch(CondBlock);
- LoopStack.pop();
- // Emit the fall-through block.
- EmitBlock(LoopExit.getBlock());
-}
-
-bool CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) {
- if (!HaveInsertPoint())
- return false;
- // Emit inits for the linear variables.
- bool HasLinears = false;
- for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
- for (const Expr *Init : C->inits()) {
- HasLinears = true;
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
- if (const auto *Ref =
- dyn_cast<DeclRefExpr>(VD->getInit()->IgnoreImpCasts())) {
- AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
- const auto *OrigVD = cast<VarDecl>(Ref->getDecl());
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
- CapturedStmtInfo->lookup(OrigVD) != nullptr,
- VD->getInit()->getType(), VK_LValue,
- VD->getInit()->getExprLoc());
- EmitExprAsInit(&DRE, VD, MakeAddrLValue(Emission.getAllocatedAddress(),
- VD->getType()),
- /*capturedByInit=*/false);
- EmitAutoVarCleanups(Emission);
- } else {
- EmitVarDecl(*VD);
- }
- }
- // Emit the linear steps for the linear clauses.
- // If a step is not constant, it is pre-calculated before the loop.
- if (const auto *CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
- if (const auto *SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
- EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
- // Emit calculation of the linear step.
- EmitIgnoredExpr(CS);
- }
- }
- return HasLinears;
-}
-
-void CodeGenFunction::EmitOMPLinearClauseFinal(
- const OMPLoopDirective &D,
- const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
- if (!HaveInsertPoint())
- return;
- llvm::BasicBlock *DoneBB = nullptr;
- // Emit the final values of the linear variables.
- for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
- auto IC = C->varlist_begin();
- for (const Expr *F : C->finals()) {
- if (!DoneBB) {
- if (llvm::Value *Cond = CondGen(*this)) {
- // If the first post-update expression is found, emit conditional
- // block if it was requested.
- llvm::BasicBlock *ThenBB = createBasicBlock(".omp.linear.pu");
- DoneBB = createBasicBlock(".omp.linear.pu.done");
- Builder.CreateCondBr(Cond, ThenBB, DoneBB);
- EmitBlock(ThenBB);
- }
- }
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IC)->getDecl());
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
- CapturedStmtInfo->lookup(OrigVD) != nullptr,
- (*IC)->getType(), VK_LValue, (*IC)->getExprLoc());
- Address OrigAddr = EmitLValue(&DRE).getAddress();
- CodeGenFunction::OMPPrivateScope VarScope(*this);
- VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; });
- (void)VarScope.Privatize();
- EmitIgnoredExpr(F);
- ++IC;
- }
- if (const Expr *PostUpdate = C->getPostUpdateExpr())
- EmitIgnoredExpr(PostUpdate);
- }
- if (DoneBB)
- EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
-static void emitAlignedClause(CodeGenFunction &CGF,
- const OMPExecutableDirective &D) {
- if (!CGF.HaveInsertPoint())
- return;
- for (const auto *Clause : D.getClausesOfKind<OMPAlignedClause>()) {
- unsigned ClauseAlignment = 0;
- if (const Expr *AlignmentExpr = Clause->getAlignment()) {
- auto *AlignmentCI =
- cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
- ClauseAlignment = static_cast<unsigned>(AlignmentCI->getZExtValue());
- }
- for (const Expr *E : Clause->varlists()) {
- unsigned Alignment = ClauseAlignment;
- if (Alignment == 0) {
- // OpenMP [2.8.1, Description]
- // If no optional parameter is specified, implementation-defined default
- // alignments for SIMD instructions on the target platforms are assumed.
- Alignment =
- CGF.getContext()
- .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign(
- E->getType()->getPointeeType()))
- .getQuantity();
- }
- assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) &&
- "alignment is not power of 2");
- if (Alignment != 0) {
- llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
- CGF.EmitAlignmentAssumption(
- PtrValue, E, /*No second loc needed*/ SourceLocation(), Alignment);
- }
- }
- }
-}
-
-void CodeGenFunction::EmitOMPPrivateLoopCounters(
- const OMPLoopDirective &S, CodeGenFunction::OMPPrivateScope &LoopScope) {
- if (!HaveInsertPoint())
- return;
- auto I = S.private_counters().begin();
- for (const Expr *E : S.counters()) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
- // Emit var without initialization.
- AutoVarEmission VarEmission = EmitAutoVarAlloca(*PrivateVD);
- EmitAutoVarCleanups(VarEmission);
- LocalDeclMap.erase(PrivateVD);
- (void)LoopScope.addPrivate(VD, [&VarEmission]() {
- return VarEmission.getAllocatedAddress();
- });
- if (LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD) ||
- VD->hasGlobalStorage()) {
- (void)LoopScope.addPrivate(PrivateVD, [this, VD, E]() {
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD),
- LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD),
- E->getType(), VK_LValue, E->getExprLoc());
- return EmitLValue(&DRE).getAddress();
- });
- } else {
- (void)LoopScope.addPrivate(PrivateVD, [&VarEmission]() {
- return VarEmission.getAllocatedAddress();
- });
- }
- ++I;
- }
- // Privatize extra loop counters used in loops for ordered(n) clauses.
- for (const auto *C : S.getClausesOfKind<OMPOrderedClause>()) {
- if (!C->getNumForLoops())
- continue;
- for (unsigned I = S.getCollapsedNumber(),
- E = C->getLoopNumIterations().size();
- I < E; ++I) {
- const auto *DRE = cast<DeclRefExpr>(C->getLoopCounter(I));
- const auto *VD = cast<VarDecl>(DRE->getDecl());
- // Override only those variables that can be captured to avoid re-emission
- // of the variables declared within the loops.
- if (DRE->refersToEnclosingVariableOrCapture()) {
- (void)LoopScope.addPrivate(VD, [this, DRE, VD]() {
- return CreateMemTemp(DRE->getType(), VD->getName());
- });
- }
- }
- }
-}
-
-static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S,
- const Expr *Cond, llvm::BasicBlock *TrueBlock,
- llvm::BasicBlock *FalseBlock, uint64_t TrueCount) {
- if (!CGF.HaveInsertPoint())
- return;
- {
- CodeGenFunction::OMPPrivateScope PreCondScope(CGF);
- CGF.EmitOMPPrivateLoopCounters(S, PreCondScope);
- (void)PreCondScope.Privatize();
- // Get initial values of real counters.
- for (const Expr *I : S.inits()) {
- CGF.EmitIgnoredExpr(I);
- }
- }
- // Check that loop is executed at least one time.
- CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount);
-}
-
-void CodeGenFunction::EmitOMPLinearClause(
- const OMPLoopDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) {
- if (!HaveInsertPoint())
- return;
- llvm::DenseSet<const VarDecl *> SIMDLCVs;
- if (isOpenMPSimdDirective(D.getDirectiveKind())) {
- const auto *LoopDirective = cast<OMPLoopDirective>(&D);
- for (const Expr *C : LoopDirective->counters()) {
- SIMDLCVs.insert(
- cast<VarDecl>(cast<DeclRefExpr>(C)->getDecl())->getCanonicalDecl());
- }
- }
- for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
- auto CurPrivate = C->privates().begin();
- for (const Expr *E : C->varlists()) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- const auto *PrivateVD =
- cast<VarDecl>(cast<DeclRefExpr>(*CurPrivate)->getDecl());
- if (!SIMDLCVs.count(VD->getCanonicalDecl())) {
- bool IsRegistered = PrivateScope.addPrivate(VD, [this, PrivateVD]() {
- // Emit private VarDecl with copy init.
- EmitVarDecl(*PrivateVD);
- return GetAddrOfLocalVar(PrivateVD);
- });
- assert(IsRegistered && "linear var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- } else {
- EmitVarDecl(*PrivateVD);
- }
- ++CurPrivate;
- }
- }
-}
-
-static void emitSimdlenSafelenClause(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- bool IsMonotonic) {
- if (!CGF.HaveInsertPoint())
- return;
- if (const auto *C = D.getSingleClause<OMPSimdlenClause>()) {
- RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
- /*ignoreResult=*/true);
- auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
- CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
- // In presence of finite 'safelen', it may be unsafe to mark all
- // the memory instructions parallel, because loop-carried
- // dependences of 'safelen' iterations are possible.
- if (!IsMonotonic)
- CGF.LoopStack.setParallel(!D.getSingleClause<OMPSafelenClause>());
- } else if (const auto *C = D.getSingleClause<OMPSafelenClause>()) {
- RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
- /*ignoreResult=*/true);
- auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
- CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
- // In presence of finite 'safelen', it may be unsafe to mark all
- // the memory instructions parallel, because loop-carried
- // dependences of 'safelen' iterations are possible.
- CGF.LoopStack.setParallel(/*Enable=*/false);
- }
-}
-
-void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D,
- bool IsMonotonic) {
- // Walk clauses and process safelen/lastprivate.
- LoopStack.setParallel(!IsMonotonic);
- LoopStack.setVectorizeEnable();
- emitSimdlenSafelenClause(*this, D, IsMonotonic);
-}
-
-void CodeGenFunction::EmitOMPSimdFinal(
- const OMPLoopDirective &D,
- const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
- if (!HaveInsertPoint())
- return;
- llvm::BasicBlock *DoneBB = nullptr;
- auto IC = D.counters().begin();
- auto IPC = D.private_counters().begin();
- for (const Expr *F : D.finals()) {
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>((*IC))->getDecl());
- const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>((*IPC))->getDecl());
- const auto *CED = dyn_cast<OMPCapturedExprDecl>(OrigVD);
- if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD) ||
- OrigVD->hasGlobalStorage() || CED) {
- if (!DoneBB) {
- if (llvm::Value *Cond = CondGen(*this)) {
- // If the first post-update expression is found, emit conditional
- // block if it was requested.
- llvm::BasicBlock *ThenBB = createBasicBlock(".omp.final.then");
- DoneBB = createBasicBlock(".omp.final.done");
- Builder.CreateCondBr(Cond, ThenBB, DoneBB);
- EmitBlock(ThenBB);
- }
- }
- Address OrigAddr = Address::invalid();
- if (CED) {
- OrigAddr = EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress();
- } else {
- DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(PrivateVD),
- /*RefersToEnclosingVariableOrCapture=*/false,
- (*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc());
- OrigAddr = EmitLValue(&DRE).getAddress();
- }
- OMPPrivateScope VarScope(*this);
- VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; });
- (void)VarScope.Privatize();
- EmitIgnoredExpr(F);
- }
- ++IC;
- ++IPC;
- }
- if (DoneBB)
- EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
-static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF,
- const OMPLoopDirective &S,
- CodeGenFunction::JumpDest LoopExit) {
- CGF.EmitOMPLoopBody(S, LoopExit);
- CGF.EmitStopPoint(&S);
-}
-
-/// Emit a helper variable and return corresponding lvalue.
-static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
- const DeclRefExpr *Helper) {
- auto VDecl = cast<VarDecl>(Helper->getDecl());
- CGF.EmitVarDecl(*VDecl);
- return CGF.EmitLValue(Helper);
-}
-
-static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- assert(isOpenMPSimdDirective(S.getDirectiveKind()) &&
- "Expected simd directive");
- OMPLoopScope PreInitScope(CGF, S);
- // if (PreCond) {
- // for (IV in 0..LastIteration) BODY;
- // <Final counter/linear vars updates>;
- // }
- //
- if (isOpenMPDistributeDirective(S.getDirectiveKind()) ||
- isOpenMPWorksharingDirective(S.getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(S.getDirectiveKind())) {
- (void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()));
- (void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()));
- }
-
- // Emit: if (PreCond) - begin.
- // If the condition constant folds and can be elided, avoid emitting the
- // whole loop.
- bool CondConstant;
- llvm::BasicBlock *ContBlock = nullptr;
- if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
- if (!CondConstant)
- return;
- } else {
- llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("simd.if.then");
- ContBlock = CGF.createBasicBlock("simd.if.end");
- emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
- CGF.getProfileCount(&S));
- CGF.EmitBlock(ThenBlock);
- CGF.incrementProfileCounter(&S);
- }
-
- // Emit the loop iteration variable.
- const Expr *IVExpr = S.getIterationVariable();
- const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
- CGF.EmitVarDecl(*IVDecl);
- CGF.EmitIgnoredExpr(S.getInit());
-
- // Emit the iterations count variable.
- // If it is not a variable, Sema decided to calculate iterations count on
- // each iteration (e.g., it is foldable into a constant).
- if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
- CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
- // Emit calculation of the iterations count.
- CGF.EmitIgnoredExpr(S.getCalcLastIteration());
- }
-
- CGF.EmitOMPSimdInit(S);
-
- emitAlignedClause(CGF, S);
- (void)CGF.EmitOMPLinearClauseInit(S);
- {
- CodeGenFunction::OMPPrivateScope LoopScope(CGF);
- CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
- CGF.EmitOMPLinearClause(S, LoopScope);
- CGF.EmitOMPPrivateClause(S, LoopScope);
- CGF.EmitOMPReductionClauseInit(S, LoopScope);
- bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
- (void)LoopScope.Privatize();
- if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
- CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
- CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
- S.getInc(),
- [&S](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest());
- CGF.EmitStopPoint(&S);
- },
- [](CodeGenFunction &) {});
- CGF.EmitOMPSimdFinal(S, [](CodeGenFunction &) { return nullptr; });
- // Emit final copy of the lastprivate variables at the end of loops.
- if (HasLastprivateClause)
- CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd);
- emitPostUpdateForReductionClause(CGF, S,
- [](CodeGenFunction &) { return nullptr; });
- }
- CGF.EmitOMPLinearClauseFinal(S, [](CodeGenFunction &) { return nullptr; });
- // Emit: if (PreCond) - end.
- if (ContBlock) {
- CGF.EmitBranch(ContBlock);
- CGF.EmitBlock(ContBlock, true);
- }
-}
-
-void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitOMPSimdRegion(CGF, S, Action);
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
-}
-
-void CodeGenFunction::EmitOMPOuterLoop(
- bool DynamicOrOrdered, bool IsMonotonic, const OMPLoopDirective &S,
- CodeGenFunction::OMPPrivateScope &LoopScope,
- const CodeGenFunction::OMPLoopArguments &LoopArgs,
- const CodeGenFunction::CodeGenLoopTy &CodeGenLoop,
- const CodeGenFunction::CodeGenOrderedTy &CodeGenOrdered) {
- CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
-
- const Expr *IVExpr = S.getIterationVariable();
- const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
- const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
-
- JumpDest LoopExit = getJumpDestInCurrentScope("omp.dispatch.end");
-
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("omp.dispatch.cond");
- EmitBlock(CondBlock);
- const SourceRange R = S.getSourceRange();
- LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()),
- SourceLocToDebugLoc(R.getEnd()));
-
- llvm::Value *BoolCondVal = nullptr;
- if (!DynamicOrOrdered) {
- // UB = min(UB, GlobalUB) or
- // UB = min(UB, PrevUB) for combined loop sharing constructs (e.g.
- // 'distribute parallel for')
- EmitIgnoredExpr(LoopArgs.EUB);
- // IV = LB
- EmitIgnoredExpr(LoopArgs.Init);
- // IV < UB
- BoolCondVal = EvaluateExprAsBool(LoopArgs.Cond);
- } else {
- BoolCondVal =
- RT.emitForNext(*this, S.getBeginLoc(), IVSize, IVSigned, LoopArgs.IL,
- LoopArgs.LB, LoopArgs.UB, LoopArgs.ST);
- }
-
- // If there are any cleanups between here and the loop-exit scope,
- // create a block to stage a loop exit along.
- llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
- if (LoopScope.requiresCleanups())
- ExitBlock = createBasicBlock("omp.dispatch.cleanup");
-
- llvm::BasicBlock *LoopBody = createBasicBlock("omp.dispatch.body");
- Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
- if (ExitBlock != LoopExit.getBlock()) {
- EmitBlock(ExitBlock);
- EmitBranchThroughCleanup(LoopExit);
- }
- EmitBlock(LoopBody);
-
- // Emit "IV = LB" (in case of static schedule, we have already calculated new
- // LB for loop condition and emitted it above).
- if (DynamicOrOrdered)
- EmitIgnoredExpr(LoopArgs.Init);
-
- // Create a block for the increment.
- JumpDest Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
-
- // Generate !llvm.loop.parallel metadata for loads and stores for loops
- // with dynamic/guided scheduling and without ordered clause.
- if (!isOpenMPSimdDirective(S.getDirectiveKind()))
- LoopStack.setParallel(!IsMonotonic);
- else
- EmitOMPSimdInit(S, IsMonotonic);
-
- SourceLocation Loc = S.getBeginLoc();
-
- // when 'distribute' is not combined with a 'for':
- // while (idx <= UB) { BODY; ++idx; }
- // when 'distribute' is combined with a 'for'
- // (e.g. 'distribute parallel for')
- // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
- EmitOMPInnerLoop(
- S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
- [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
- CodeGenLoop(CGF, S, LoopExit);
- },
- [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
- CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
- });
-
- EmitBlock(Continue.getBlock());
- BreakContinueStack.pop_back();
- if (!DynamicOrOrdered) {
- // Emit "LB = LB + Stride", "UB = UB + Stride".
- EmitIgnoredExpr(LoopArgs.NextLB);
- EmitIgnoredExpr(LoopArgs.NextUB);
- }
-
- EmitBranch(CondBlock);
- LoopStack.pop();
- // Emit the fall-through block.
- EmitBlock(LoopExit.getBlock());
-
- // Tell the runtime we are done.
- auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) {
- if (!DynamicOrOrdered)
- CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
- S.getDirectiveKind());
- };
- OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
-}
-
-void CodeGenFunction::EmitOMPForOuterLoop(
- const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic,
- const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
- const OMPLoopArguments &LoopArgs,
- const CodeGenDispatchBoundsTy &CGDispatchBounds) {
- CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
-
- // Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
- const bool DynamicOrOrdered =
- Ordered || RT.isDynamic(ScheduleKind.Schedule);
-
- assert((Ordered ||
- !RT.isStaticNonchunked(ScheduleKind.Schedule,
- LoopArgs.Chunk != nullptr)) &&
- "static non-chunked schedule does not need outer loop");
-
- // Emit outer loop.
- //
- // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
- // When schedule(dynamic,chunk_size) is specified, the iterations are
- // distributed to threads in the team in chunks as the threads request them.
- // Each thread executes a chunk of iterations, then requests another chunk,
- // until no chunks remain to be distributed. Each chunk contains chunk_size
- // iterations, except for the last chunk to be distributed, which may have
- // fewer iterations. When no chunk_size is specified, it defaults to 1.
- //
- // When schedule(guided,chunk_size) is specified, the iterations are assigned
- // to threads in the team in chunks as the executing threads request them.
- // Each thread executes a chunk of iterations, then requests another chunk,
- // until no chunks remain to be assigned. For a chunk_size of 1, the size of
- // each chunk is proportional to the number of unassigned iterations divided
- // by the number of threads in the team, decreasing to 1. For a chunk_size
- // with value k (greater than 1), the size of each chunk is determined in the
- // same way, with the restriction that the chunks do not contain fewer than k
- // iterations (except for the last chunk to be assigned, which may have fewer
- // than k iterations).
- //
- // When schedule(auto) is specified, the decision regarding scheduling is
- // delegated to the compiler and/or runtime system. The programmer gives the
- // implementation the freedom to choose any possible mapping of iterations to
- // threads in the team.
- //
- // When schedule(runtime) is specified, the decision regarding scheduling is
- // deferred until run time, and the schedule and chunk size are taken from the
- // run-sched-var ICV. If the ICV is set to auto, the schedule is
- // implementation defined
- //
- // while(__kmpc_dispatch_next(&LB, &UB)) {
- // idx = LB;
- // while (idx <= UB) { BODY; ++idx;
- // __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only.
- // } // inner loop
- // }
- //
- // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
- // When schedule(static, chunk_size) is specified, iterations are divided into
- // chunks of size chunk_size, and the chunks are assigned to the threads in
- // the team in a round-robin fashion in the order of the thread number.
- //
- // while(UB = min(UB, GlobalUB), idx = LB, idx < UB) {
- // while (idx <= UB) { BODY; ++idx; } // inner loop
- // LB = LB + ST;
- // UB = UB + ST;
- // }
- //
-
- const Expr *IVExpr = S.getIterationVariable();
- const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
- const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
-
- if (DynamicOrOrdered) {
- const std::pair<llvm::Value *, llvm::Value *> DispatchBounds =
- CGDispatchBounds(*this, S, LoopArgs.LB, LoopArgs.UB);
- llvm::Value *LBVal = DispatchBounds.first;
- llvm::Value *UBVal = DispatchBounds.second;
- CGOpenMPRuntime::DispatchRTInput DipatchRTInputValues = {LBVal, UBVal,
- LoopArgs.Chunk};
- RT.emitForDispatchInit(*this, S.getBeginLoc(), ScheduleKind, IVSize,
- IVSigned, Ordered, DipatchRTInputValues);
- } else {
- CGOpenMPRuntime::StaticRTInput StaticInit(
- IVSize, IVSigned, Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB,
- LoopArgs.ST, LoopArgs.Chunk);
- RT.emitForStaticInit(*this, S.getBeginLoc(), S.getDirectiveKind(),
- ScheduleKind, StaticInit);
- }
-
- auto &&CodeGenOrdered = [Ordered](CodeGenFunction &CGF, SourceLocation Loc,
- const unsigned IVSize,
- const bool IVSigned) {
- if (Ordered) {
- CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(CGF, Loc, IVSize,
- IVSigned);
- }
- };
-
- OMPLoopArguments OuterLoopArgs(LoopArgs.LB, LoopArgs.UB, LoopArgs.ST,
- LoopArgs.IL, LoopArgs.Chunk, LoopArgs.EUB);
- OuterLoopArgs.IncExpr = S.getInc();
- OuterLoopArgs.Init = S.getInit();
- OuterLoopArgs.Cond = S.getCond();
- OuterLoopArgs.NextLB = S.getNextLowerBound();
- OuterLoopArgs.NextUB = S.getNextUpperBound();
- EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, OuterLoopArgs,
- emitOMPLoopBodyWithStopPoint, CodeGenOrdered);
-}
-
-static void emitEmptyOrdered(CodeGenFunction &, SourceLocation Loc,
- const unsigned IVSize, const bool IVSigned) {}
-
-void CodeGenFunction::EmitOMPDistributeOuterLoop(
- OpenMPDistScheduleClauseKind ScheduleKind, const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope, const OMPLoopArguments &LoopArgs,
- const CodeGenLoopTy &CodeGenLoopContent) {
-
- CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
-
- // Emit outer loop.
- // Same behavior as a OMPForOuterLoop, except that schedule cannot be
- // dynamic
- //
-
- const Expr *IVExpr = S.getIterationVariable();
- const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
- const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
-
- CGOpenMPRuntime::StaticRTInput StaticInit(
- IVSize, IVSigned, /* Ordered = */ false, LoopArgs.IL, LoopArgs.LB,
- LoopArgs.UB, LoopArgs.ST, LoopArgs.Chunk);
- RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind, StaticInit);
-
- // for combined 'distribute' and 'for' the increment expression of distribute
- // is stored in DistInc. For 'distribute' alone, it is in Inc.
- Expr *IncExpr;
- if (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind()))
- IncExpr = S.getDistInc();
- else
- IncExpr = S.getInc();
-
- // this routine is shared by 'omp distribute parallel for' and
- // 'omp distribute': select the right EUB expression depending on the
- // directive
- OMPLoopArguments OuterLoopArgs;
- OuterLoopArgs.LB = LoopArgs.LB;
- OuterLoopArgs.UB = LoopArgs.UB;
- OuterLoopArgs.ST = LoopArgs.ST;
- OuterLoopArgs.IL = LoopArgs.IL;
- OuterLoopArgs.Chunk = LoopArgs.Chunk;
- OuterLoopArgs.EUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedEnsureUpperBound()
- : S.getEnsureUpperBound();
- OuterLoopArgs.IncExpr = IncExpr;
- OuterLoopArgs.Init = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedInit()
- : S.getInit();
- OuterLoopArgs.Cond = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedCond()
- : S.getCond();
- OuterLoopArgs.NextLB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedNextLowerBound()
- : S.getNextLowerBound();
- OuterLoopArgs.NextUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedNextUpperBound()
- : S.getNextUpperBound();
-
- EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false, S,
- LoopScope, OuterLoopArgs, CodeGenLoopContent,
- emitEmptyOrdered);
-}
-
-static std::pair<LValue, LValue>
-emitDistributeParallelForInnerBounds(CodeGenFunction &CGF,
- const OMPExecutableDirective &S) {
- const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
- LValue LB =
- EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
- LValue UB =
- EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
-
- // When composing 'distribute' with 'for' (e.g. as in 'distribute
- // parallel for') we need to use the 'distribute'
- // chunk lower and upper bounds rather than the whole loop iteration
- // space. These are parameters to the outlined function for 'parallel'
- // and we copy the bounds of the previous schedule into the
- // the current ones.
- LValue PrevLB = CGF.EmitLValue(LS.getPrevLowerBoundVariable());
- LValue PrevUB = CGF.EmitLValue(LS.getPrevUpperBoundVariable());
- llvm::Value *PrevLBVal = CGF.EmitLoadOfScalar(
- PrevLB, LS.getPrevLowerBoundVariable()->getExprLoc());
- PrevLBVal = CGF.EmitScalarConversion(
- PrevLBVal, LS.getPrevLowerBoundVariable()->getType(),
- LS.getIterationVariable()->getType(),
- LS.getPrevLowerBoundVariable()->getExprLoc());
- llvm::Value *PrevUBVal = CGF.EmitLoadOfScalar(
- PrevUB, LS.getPrevUpperBoundVariable()->getExprLoc());
- PrevUBVal = CGF.EmitScalarConversion(
- PrevUBVal, LS.getPrevUpperBoundVariable()->getType(),
- LS.getIterationVariable()->getType(),
- LS.getPrevUpperBoundVariable()->getExprLoc());
-
- CGF.EmitStoreOfScalar(PrevLBVal, LB);
- CGF.EmitStoreOfScalar(PrevUBVal, UB);
-
- return {LB, UB};
-}
-
-/// if the 'for' loop has a dispatch schedule (e.g. dynamic, guided) then
-/// we need to use the LB and UB expressions generated by the worksharing
-/// code generation support, whereas in non combined situations we would
-/// just emit 0 and the LastIteration expression
-/// This function is necessary due to the difference of the LB and UB
-/// types for the RT emission routines for 'for_static_init' and
-/// 'for_dispatch_init'
-static std::pair<llvm::Value *, llvm::Value *>
-emitDistributeParallelForDispatchBounds(CodeGenFunction &CGF,
- const OMPExecutableDirective &S,
- Address LB, Address UB) {
- const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
- const Expr *IVExpr = LS.getIterationVariable();
- // when implementing a dynamic schedule for a 'for' combined with a
- // 'distribute' (e.g. 'distribute parallel for'), the 'for' loop
- // is not normalized as each team only executes its own assigned
- // distribute chunk
- QualType IteratorTy = IVExpr->getType();
- llvm::Value *LBVal =
- CGF.EmitLoadOfScalar(LB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
- llvm::Value *UBVal =
- CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
- return {LBVal, UBVal};
-}
-
-static void emitDistributeParallelForDistributeInnerBoundParams(
- CodeGenFunction &CGF, const OMPExecutableDirective &S,
- llvm::SmallVectorImpl<llvm::Value *> &CapturedVars) {
- const auto &Dir = cast<OMPLoopDirective>(S);
- LValue LB =
- CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable()));
- llvm::Value *LBCast = CGF.Builder.CreateIntCast(
- CGF.Builder.CreateLoad(LB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
- CapturedVars.push_back(LBCast);
- LValue UB =
- CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable()));
-
- llvm::Value *UBCast = CGF.Builder.CreateIntCast(
- CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
- CapturedVars.push_back(UBCast);
-}
-
-static void
-emitInnerParallelForWhenCombined(CodeGenFunction &CGF,
- const OMPLoopDirective &S,
- CodeGenFunction::JumpDest LoopExit) {
- auto &&CGInlinedWorksharingLoop = [&S](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- bool HasCancel = false;
- if (!isOpenMPSimdDirective(S.getDirectiveKind())) {
- if (const auto *D = dyn_cast<OMPTeamsDistributeParallelForDirective>(&S))
- HasCancel = D->hasCancel();
- else if (const auto *D = dyn_cast<OMPDistributeParallelForDirective>(&S))
- HasCancel = D->hasCancel();
- else if (const auto *D =
- dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&S))
- HasCancel = D->hasCancel();
- }
- CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, S.getDirectiveKind(),
- HasCancel);
- CGF.EmitOMPWorksharingLoop(S, S.getPrevEnsureUpperBound(),
- emitDistributeParallelForInnerBounds,
- emitDistributeParallelForDispatchBounds);
- };
-
- emitCommonOMPParallelDirective(
- CGF, S,
- isOpenMPSimdDirective(S.getDirectiveKind()) ? OMPD_for_simd : OMPD_for,
- CGInlinedWorksharingLoop,
- emitDistributeParallelForDistributeInnerBoundParams);
-}
-
-void CodeGenFunction::EmitOMPDistributeParallelForDirective(
- const OMPDistributeParallelForDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
- S.getDistInc());
- };
- OMPLexicalScope Scope(*this, S, OMPD_parallel);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
-}
-
-void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective(
- const OMPDistributeParallelForSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
- S.getDistInc());
- };
- OMPLexicalScope Scope(*this, S, OMPD_parallel);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
-}
-
-void CodeGenFunction::EmitOMPDistributeSimdDirective(
- const OMPDistributeSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
-}
-
-void CodeGenFunction::EmitOMPTargetSimdDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName, const OMPTargetSimdDirective &S) {
- // Emit SPMD target parallel for region as a standalone region.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitOMPSimdRegion(CGF, S, Action);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetSimdDirective(
- const OMPTargetSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitOMPSimdRegion(CGF, S, Action);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-namespace {
- struct ScheduleKindModifiersTy {
- OpenMPScheduleClauseKind Kind;
- OpenMPScheduleClauseModifier M1;
- OpenMPScheduleClauseModifier M2;
- ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind,
- OpenMPScheduleClauseModifier M1,
- OpenMPScheduleClauseModifier M2)
- : Kind(Kind), M1(M1), M2(M2) {}
- };
-} // namespace
-
-bool CodeGenFunction::EmitOMPWorksharingLoop(
- const OMPLoopDirective &S, Expr *EUB,
- const CodeGenLoopBoundsTy &CodeGenLoopBounds,
- const CodeGenDispatchBoundsTy &CGDispatchBounds) {
- // Emit the loop iteration variable.
- const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
- const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
- EmitVarDecl(*IVDecl);
-
- // Emit the iterations count variable.
- // If it is not a variable, Sema decided to calculate iterations count on each
- // iteration (e.g., it is foldable into a constant).
- if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
- EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
- // Emit calculation of the iterations count.
- EmitIgnoredExpr(S.getCalcLastIteration());
- }
-
- CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
-
- bool HasLastprivateClause;
- // Check pre-condition.
- {
- OMPLoopScope PreInitScope(*this, S);
- // Skip the entire loop if we don't meet the precondition.
- // If the condition constant folds and can be elided, avoid emitting the
- // whole loop.
- bool CondConstant;
- llvm::BasicBlock *ContBlock = nullptr;
- if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
- if (!CondConstant)
- return false;
- } else {
- llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
- ContBlock = createBasicBlock("omp.precond.end");
- emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
- getProfileCount(&S));
- EmitBlock(ThenBlock);
- incrementProfileCounter(&S);
- }
-
- RunCleanupsScope DoacrossCleanupScope(*this);
- bool Ordered = false;
- if (const auto *OrderedClause = S.getSingleClause<OMPOrderedClause>()) {
- if (OrderedClause->getNumForLoops())
- RT.emitDoacrossInit(*this, S, OrderedClause->getLoopNumIterations());
- else
- Ordered = true;
- }
-
- llvm::DenseSet<const Expr *> EmittedFinals;
- emitAlignedClause(*this, S);
- bool HasLinears = EmitOMPLinearClauseInit(S);
- // Emit helper vars inits.
-
- std::pair<LValue, LValue> Bounds = CodeGenLoopBounds(*this, S);
- LValue LB = Bounds.first;
- LValue UB = Bounds.second;
- LValue ST =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
- LValue IL =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
-
- // Emit 'then' code.
- {
- OMPPrivateScope LoopScope(*this);
- if (EmitOMPFirstprivateClause(S, LoopScope) || HasLinears) {
- // Emit implicit barrier to synchronize threads and avoid data races on
- // initialization of firstprivate variables and post-update of
- // lastprivate variables.
- CGM.getOpenMPRuntime().emitBarrierCall(
- *this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
- }
- EmitOMPPrivateClause(S, LoopScope);
- HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
- EmitOMPReductionClauseInit(S, LoopScope);
- EmitOMPPrivateLoopCounters(S, LoopScope);
- EmitOMPLinearClause(S, LoopScope);
- (void)LoopScope.Privatize();
- if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
- CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
-
- // Detect the loop schedule kind and chunk.
- const Expr *ChunkExpr = nullptr;
- OpenMPScheduleTy ScheduleKind;
- if (const auto *C = S.getSingleClause<OMPScheduleClause>()) {
- ScheduleKind.Schedule = C->getScheduleKind();
- ScheduleKind.M1 = C->getFirstScheduleModifier();
- ScheduleKind.M2 = C->getSecondScheduleModifier();
- ChunkExpr = C->getChunkSize();
- } else {
- // Default behaviour for schedule clause.
- CGM.getOpenMPRuntime().getDefaultScheduleAndChunk(
- *this, S, ScheduleKind.Schedule, ChunkExpr);
- }
- bool HasChunkSizeOne = false;
- llvm::Value *Chunk = nullptr;
- if (ChunkExpr) {
- Chunk = EmitScalarExpr(ChunkExpr);
- Chunk = EmitScalarConversion(Chunk, ChunkExpr->getType(),
- S.getIterationVariable()->getType(),
- S.getBeginLoc());
- Expr::EvalResult Result;
- if (ChunkExpr->EvaluateAsInt(Result, getContext())) {
- llvm::APSInt EvaluatedChunk = Result.Val.getInt();
- HasChunkSizeOne = (EvaluatedChunk.getLimitedValue() == 1);
- }
- }
- const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
- const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
- // OpenMP 4.5, 2.7.1 Loop Construct, Description.
- // If the static schedule kind is specified or if the ordered clause is
- // specified, and if no monotonic modifier is specified, the effect will
- // be as if the monotonic modifier was specified.
- bool StaticChunkedOne = RT.isStaticChunked(ScheduleKind.Schedule,
- /* Chunked */ Chunk != nullptr) && HasChunkSizeOne &&
- isOpenMPLoopBoundSharingDirective(S.getDirectiveKind());
- if ((RT.isStaticNonchunked(ScheduleKind.Schedule,
- /* Chunked */ Chunk != nullptr) ||
- StaticChunkedOne) &&
- !Ordered) {
- if (isOpenMPSimdDirective(S.getDirectiveKind()))
- EmitOMPSimdInit(S, /*IsMonotonic=*/true);
- // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
- // When no chunk_size is specified, the iteration space is divided into
- // chunks that are approximately equal in size, and at most one chunk is
- // distributed to each thread. Note that the size of the chunks is
- // unspecified in this case.
- CGOpenMPRuntime::StaticRTInput StaticInit(
- IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(),
- UB.getAddress(), ST.getAddress(),
- StaticChunkedOne ? Chunk : nullptr);
- RT.emitForStaticInit(*this, S.getBeginLoc(), S.getDirectiveKind(),
- ScheduleKind, StaticInit);
- JumpDest LoopExit =
- getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
- // UB = min(UB, GlobalUB);
- if (!StaticChunkedOne)
- EmitIgnoredExpr(S.getEnsureUpperBound());
- // IV = LB;
- EmitIgnoredExpr(S.getInit());
- // For unchunked static schedule generate:
- //
- // while (idx <= UB) {
- // BODY;
- // ++idx;
- // }
- //
- // For static schedule with chunk one:
- //
- // while (IV <= PrevUB) {
- // BODY;
- // IV += ST;
- // }
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
- StaticChunkedOne ? S.getCombinedParForInDistCond() : S.getCond(),
- StaticChunkedOne ? S.getDistInc() : S.getInc(),
- [&S, LoopExit](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, LoopExit);
- CGF.EmitStopPoint(&S);
- },
- [](CodeGenFunction &) {});
- EmitBlock(LoopExit.getBlock());
- // Tell the runtime we are done.
- auto &&CodeGen = [&S](CodeGenFunction &CGF) {
- CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
- S.getDirectiveKind());
- };
- OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
- } else {
- const bool IsMonotonic =
- Ordered || ScheduleKind.Schedule == OMPC_SCHEDULE_static ||
- ScheduleKind.Schedule == OMPC_SCHEDULE_unknown ||
- ScheduleKind.M1 == OMPC_SCHEDULE_MODIFIER_monotonic ||
- ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
- // Emit the outer loop, which requests its work chunk [LB..UB] from
- // runtime and runs the inner loop to process it.
- const OMPLoopArguments LoopArguments(LB.getAddress(), UB.getAddress(),
- ST.getAddress(), IL.getAddress(),
- Chunk, EUB);
- EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
- LoopArguments, CGDispatchBounds);
- }
- if (isOpenMPSimdDirective(S.getDirectiveKind())) {
- EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
- return CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
- });
- }
- EmitOMPReductionClauseFinal(
- S, /*ReductionKind=*/isOpenMPSimdDirective(S.getDirectiveKind())
- ? /*Parallel and Simd*/ OMPD_parallel_for_simd
- : /*Parallel only*/ OMPD_parallel);
- // Emit post-update of the reduction variables if IsLastIter != 0.
- emitPostUpdateForReductionClause(
- *this, S, [IL, &S](CodeGenFunction &CGF) {
- return CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
- });
- // Emit final copy of the lastprivate variables if IsLastIter != 0.
- if (HasLastprivateClause)
- EmitOMPLastprivateClauseFinal(
- S, isOpenMPSimdDirective(S.getDirectiveKind()),
- Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
- }
- EmitOMPLinearClauseFinal(S, [IL, &S](CodeGenFunction &CGF) {
- return CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
- });
- DoacrossCleanupScope.ForceCleanup();
- // We're now done with the loop, so jump to the continuation block.
- if (ContBlock) {
- EmitBranch(ContBlock);
- EmitBlock(ContBlock, /*IsFinished=*/true);
- }
- }
- return HasLastprivateClause;
-}
-
-/// The following two functions generate expressions for the loop lower
-/// and upper bounds in case of static and dynamic (dispatch) schedule
-/// of the associated 'for' or 'distribute' loop.
-static std::pair<LValue, LValue>
-emitForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
- const auto &LS = cast<OMPLoopDirective>(S);
- LValue LB =
- EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
- LValue UB =
- EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
- return {LB, UB};
-}
-
-/// When dealing with dispatch schedules (e.g. dynamic, guided) we do not
-/// consider the lower and upper bound expressions generated by the
-/// worksharing loop support, but we use 0 and the iteration space size as
-/// constants
-static std::pair<llvm::Value *, llvm::Value *>
-emitDispatchForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S,
- Address LB, Address UB) {
- const auto &LS = cast<OMPLoopDirective>(S);
- const Expr *IVExpr = LS.getIterationVariable();
- const unsigned IVSize = CGF.getContext().getTypeSize(IVExpr->getType());
- llvm::Value *LBVal = CGF.Builder.getIntN(IVSize, 0);
- llvm::Value *UBVal = CGF.EmitScalarExpr(LS.getLastIteration());
- return {LBVal, UBVal};
-}
-
-void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
- bool HasLastprivates = false;
- auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
- PrePostActionTy &) {
- OMPCancelStackRAII CancelRegion(CGF, OMPD_for, S.hasCancel());
- HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
- emitForLoopBounds,
- emitDispatchForLoopBounds);
- };
- {
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_for, CodeGen,
- S.hasCancel());
- }
-
- // Emit an implicit barrier at the end.
- if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for);
-}
-
-void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) {
- bool HasLastprivates = false;
- auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
- PrePostActionTy &) {
- HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
- emitForLoopBounds,
- emitDispatchForLoopBounds);
- };
- {
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
- }
-
- // Emit an implicit barrier at the end.
- if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for);
-}
-
-static LValue createSectionLVal(CodeGenFunction &CGF, QualType Ty,
- const Twine &Name,
- llvm::Value *Init = nullptr) {
- LValue LVal = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty, Name), Ty);
- if (Init)
- CGF.EmitStoreThroughLValue(RValue::get(Init), LVal, /*isInit*/ true);
- return LVal;
-}
-
-void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
- const Stmt *CapturedStmt = S.getInnermostCapturedStmt()->getCapturedStmt();
- const auto *CS = dyn_cast<CompoundStmt>(CapturedStmt);
- bool HasLastprivates = false;
- auto &&CodeGen = [&S, CapturedStmt, CS,
- &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) {
- ASTContext &C = CGF.getContext();
- QualType KmpInt32Ty =
- C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
- // Emit helper vars inits.
- LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.",
- CGF.Builder.getInt32(0));
- llvm::ConstantInt *GlobalUBVal = CS != nullptr
- ? CGF.Builder.getInt32(CS->size() - 1)
- : CGF.Builder.getInt32(0);
- LValue UB =
- createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
- LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.",
- CGF.Builder.getInt32(1));
- LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.",
- CGF.Builder.getInt32(0));
- // Loop counter.
- LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv.");
- OpaqueValueExpr IVRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
- CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV);
- OpaqueValueExpr UBRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
- CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
- // Generate condition for loop.
- BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
- OK_Ordinary, S.getBeginLoc(), FPOptions());
- // Increment for loop counter.
- UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
- S.getBeginLoc(), true);
- auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
- // Iterate through all sections and emit a switch construct:
- // switch (IV) {
- // case 0:
- // <SectionStmt[0]>;
- // break;
- // ...
- // case <NumSection> - 1:
- // <SectionStmt[<NumSection> - 1]>;
- // break;
- // }
- // .omp.sections.exit:
- llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
- llvm::SwitchInst *SwitchStmt =
- CGF.Builder.CreateSwitch(CGF.EmitLoadOfScalar(IV, S.getBeginLoc()),
- ExitBB, CS == nullptr ? 1 : CS->size());
- if (CS) {
- unsigned CaseNumber = 0;
- for (const Stmt *SubStmt : CS->children()) {
- auto CaseBB = CGF.createBasicBlock(".omp.sections.case");
- CGF.EmitBlock(CaseBB);
- SwitchStmt->addCase(CGF.Builder.getInt32(CaseNumber), CaseBB);
- CGF.EmitStmt(SubStmt);
- CGF.EmitBranch(ExitBB);
- ++CaseNumber;
- }
- } else {
- llvm::BasicBlock *CaseBB = CGF.createBasicBlock(".omp.sections.case");
- CGF.EmitBlock(CaseBB);
- SwitchStmt->addCase(CGF.Builder.getInt32(0), CaseBB);
- CGF.EmitStmt(CapturedStmt);
- CGF.EmitBranch(ExitBB);
- }
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
- };
-
- CodeGenFunction::OMPPrivateScope LoopScope(CGF);
- if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) {
- // Emit implicit barrier to synchronize threads and avoid data races on
- // initialization of firstprivate variables and post-update of lastprivate
- // variables.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
- }
- CGF.EmitOMPPrivateClause(S, LoopScope);
- HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
- CGF.EmitOMPReductionClauseInit(S, LoopScope);
- (void)LoopScope.Privatize();
- if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
- CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
-
- // Emit static non-chunked loop.
- OpenMPScheduleTy ScheduleKind;
- ScheduleKind.Schedule = OMPC_SCHEDULE_static;
- CGOpenMPRuntime::StaticRTInput StaticInit(
- /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(),
- LB.getAddress(), UB.getAddress(), ST.getAddress());
- CGF.CGM.getOpenMPRuntime().emitForStaticInit(
- CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind, StaticInit);
- // UB = min(UB, GlobalUB);
- llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, S.getBeginLoc());
- llvm::Value *MinUBGlobalUB = CGF.Builder.CreateSelect(
- CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
- CGF.EmitStoreOfScalar(MinUBGlobalUB, UB);
- // IV = LB;
- CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
- // while (idx <= UB) { BODY; ++idx; }
- CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen,
- [](CodeGenFunction &) {});
- // Tell the runtime we are done.
- auto &&CodeGen = [&S](CodeGenFunction &CGF) {
- CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
- S.getDirectiveKind());
- };
- CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
- // Emit post-update of the reduction variables if IsLastIter != 0.
- emitPostUpdateForReductionClause(CGF, S, [IL, &S](CodeGenFunction &CGF) {
- return CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
- });
-
- // Emit final copy of the lastprivate variables if IsLastIter != 0.
- if (HasLastprivates)
- CGF.EmitOMPLastprivateClauseFinal(
- S, /*NoFinals=*/false,
- CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc())));
- };
-
- bool HasCancel = false;
- if (auto *OSD = dyn_cast<OMPSectionsDirective>(&S))
- HasCancel = OSD->hasCancel();
- else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S))
- HasCancel = OPSD->hasCancel();
- OMPCancelStackRAII CancelRegion(*this, S.getDirectiveKind(), HasCancel);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen,
- HasCancel);
- // Emit barrier for lastprivates only if 'sections' directive has 'nowait'
- // clause. Otherwise the barrier will be generated by the codegen for the
- // directive.
- if (HasLastprivates && S.getSingleClause<OMPNowaitClause>()) {
- // Emit implicit barrier to synchronize threads and avoid data races on
- // initialization of firstprivate variables.
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
- OMPD_unknown);
- }
-}
-
-void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
- {
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- EmitSections(S);
- }
- // Emit an implicit barrier at the end.
- if (!S.getSingleClause<OMPNowaitClause>()) {
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
- OMPD_sections);
- }
-}
-
-void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_section, CodeGen,
- S.hasCancel());
-}
-
-void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
- llvm::SmallVector<const Expr *, 8> CopyprivateVars;
- llvm::SmallVector<const Expr *, 8> DestExprs;
- llvm::SmallVector<const Expr *, 8> SrcExprs;
- llvm::SmallVector<const Expr *, 8> AssignmentOps;
- // Check if there are any 'copyprivate' clauses associated with this
- // 'single' construct.
- // Build a list of copyprivate variables along with helper expressions
- // (<source>, <destination>, <destination>=<source> expressions)
- for (const auto *C : S.getClausesOfKind<OMPCopyprivateClause>()) {
- CopyprivateVars.append(C->varlists().begin(), C->varlists().end());
- DestExprs.append(C->destination_exprs().begin(),
- C->destination_exprs().end());
- SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end());
- AssignmentOps.append(C->assignment_ops().begin(),
- C->assignment_ops().end());
- }
- // Emit code for 'single' region along with 'copyprivate' clauses
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPPrivateScope SingleScope(CGF);
- (void)CGF.EmitOMPFirstprivateClause(S, SingleScope);
- CGF.EmitOMPPrivateClause(S, SingleScope);
- (void)SingleScope.Privatize();
- CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
- };
- {
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getBeginLoc(),
- CopyprivateVars, DestExprs,
- SrcExprs, AssignmentOps);
- }
- // Emit an implicit barrier at the end (to avoid data race on firstprivate
- // init or if no 'nowait' clause was specified and no 'copyprivate' clause).
- if (!S.getSingleClause<OMPNowaitClause>() && CopyprivateVars.empty()) {
- CGM.getOpenMPRuntime().emitBarrierCall(
- *this, S.getBeginLoc(),
- S.getSingleClause<OMPNowaitClause>() ? OMPD_unknown : OMPD_single);
- }
-}
-
-void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
-}
-
-void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
- };
- const Expr *Hint = nullptr;
- if (const auto *HintClause = S.getSingleClause<OMPHintClause>())
- Hint = HintClause->getHint();
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitCriticalRegion(*this,
- S.getDirectiveName().getAsString(),
- CodeGen, S.getBeginLoc(), Hint);
-}
-
-void CodeGenFunction::EmitOMPParallelForDirective(
- const OMPParallelForDirective &S) {
- // Emit directive as a combined directive that consists of two implicit
- // directives: 'parallel' with 'for' directive.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPCancelStackRAII CancelRegion(CGF, OMPD_parallel_for, S.hasCancel());
- CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
- emitDispatchForLoopBounds);
- };
- emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen,
- emitEmptyBoundParameters);
-}
-
-void CodeGenFunction::EmitOMPParallelForSimdDirective(
- const OMPParallelForSimdDirective &S) {
- // Emit directive as a combined directive that consists of two implicit
- // directives: 'parallel' with 'for' directive.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
- emitDispatchForLoopBounds);
- };
- emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen,
- emitEmptyBoundParameters);
-}
-
-void CodeGenFunction::EmitOMPParallelSectionsDirective(
- const OMPParallelSectionsDirective &S) {
- // Emit directive as a combined directive that consists of two implicit
- // directives: 'parallel' with 'sections' directive.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CGF.EmitSections(S);
- };
- emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen,
- emitEmptyBoundParameters);
-}
-
-void CodeGenFunction::EmitOMPTaskBasedDirective(
- const OMPExecutableDirective &S, const OpenMPDirectiveKind CapturedRegion,
- const RegionCodeGenTy &BodyGen, const TaskGenTy &TaskGen,
- OMPTaskDataTy &Data) {
- // Emit outlined function for task construct.
- const CapturedStmt *CS = S.getCapturedStmt(CapturedRegion);
- auto I = CS->getCapturedDecl()->param_begin();
- auto PartId = std::next(I);
- auto TaskT = std::next(I, 4);
- // Check if the task is final
- if (const auto *Clause = S.getSingleClause<OMPFinalClause>()) {
- // If the condition constant folds and can be elided, try to avoid emitting
- // the condition and the dead arm of the if/else.
- const Expr *Cond = Clause->getCondition();
- bool CondConstant;
- if (ConstantFoldsToSimpleInteger(Cond, CondConstant))
- Data.Final.setInt(CondConstant);
- else
- Data.Final.setPointer(EvaluateExprAsBool(Cond));
- } else {
- // By default the task is not final.
- Data.Final.setInt(/*IntVal=*/false);
- }
- // Check if the task has 'priority' clause.
- if (const auto *Clause = S.getSingleClause<OMPPriorityClause>()) {
- const Expr *Prio = Clause->getPriority();
- Data.Priority.setInt(/*IntVal=*/true);
- Data.Priority.setPointer(EmitScalarConversion(
- EmitScalarExpr(Prio), Prio->getType(),
- getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
- Prio->getExprLoc()));
- }
- // The first function argument for tasks is a thread id, the second one is a
- // part id (0 for tied tasks, >=0 for untied task).
- llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
- // Get list of private variables.
- for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
- auto IRef = C->varlist_begin();
- for (const Expr *IInit : C->private_copies()) {
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
- Data.PrivateVars.push_back(*IRef);
- Data.PrivateCopies.push_back(IInit);
- }
- ++IRef;
- }
- }
- EmittedAsPrivate.clear();
- // Get list of firstprivate variables.
- for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
- auto IRef = C->varlist_begin();
- auto IElemInitRef = C->inits().begin();
- for (const Expr *IInit : C->private_copies()) {
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
- Data.FirstprivateVars.push_back(*IRef);
- Data.FirstprivateCopies.push_back(IInit);
- Data.FirstprivateInits.push_back(*IElemInitRef);
- }
- ++IRef;
- ++IElemInitRef;
- }
- }
- // Get list of lastprivate variables (for taskloops).
- llvm::DenseMap<const VarDecl *, const DeclRefExpr *> LastprivateDstsOrigs;
- for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
- auto IRef = C->varlist_begin();
- auto ID = C->destination_exprs().begin();
- for (const Expr *IInit : C->private_copies()) {
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
- Data.LastprivateVars.push_back(*IRef);
- Data.LastprivateCopies.push_back(IInit);
- }
- LastprivateDstsOrigs.insert(
- {cast<VarDecl>(cast<DeclRefExpr>(*ID)->getDecl()),
- cast<DeclRefExpr>(*IRef)});
- ++IRef;
- ++ID;
- }
- }
- SmallVector<const Expr *, 4> LHSs;
- SmallVector<const Expr *, 4> RHSs;
- for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
- auto IPriv = C->privates().begin();
- auto IRed = C->reduction_ops().begin();
- auto ILHS = C->lhs_exprs().begin();
- auto IRHS = C->rhs_exprs().begin();
- for (const Expr *Ref : C->varlists()) {
- Data.ReductionVars.emplace_back(Ref);
- Data.ReductionCopies.emplace_back(*IPriv);
- Data.ReductionOps.emplace_back(*IRed);
- LHSs.emplace_back(*ILHS);
- RHSs.emplace_back(*IRHS);
- std::advance(IPriv, 1);
- std::advance(IRed, 1);
- std::advance(ILHS, 1);
- std::advance(IRHS, 1);
- }
- }
- Data.Reductions = CGM.getOpenMPRuntime().emitTaskReductionInit(
- *this, S.getBeginLoc(), LHSs, RHSs, Data);
- // Build list of dependences.
- for (const auto *C : S.getClausesOfKind<OMPDependClause>())
- for (const Expr *IRef : C->varlists())
- Data.Dependences.emplace_back(C->getDependencyKind(), IRef);
- auto &&CodeGen = [&Data, &S, CS, &BodyGen, &LastprivateDstsOrigs,
- CapturedRegion](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- // Set proper addresses for generated private copies.
- OMPPrivateScope Scope(CGF);
- if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() ||
- !Data.LastprivateVars.empty()) {
- enum { PrivatesParam = 2, CopyFnParam = 3 };
- llvm::Value *CopyFn = CGF.Builder.CreateLoad(
- CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
- llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
- CS->getCapturedDecl()->getParam(PrivatesParam)));
- // Map privates.
- llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> PrivatePtrs;
- llvm::SmallVector<llvm::Value *, 16> CallArgs;
- CallArgs.push_back(PrivatesPtr);
- for (const Expr *E : Data.PrivateVars) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- Address PrivatePtr = CGF.CreateMemTemp(
- CGF.getContext().getPointerType(E->getType()), ".priv.ptr.addr");
- PrivatePtrs.emplace_back(VD, PrivatePtr);
- CallArgs.push_back(PrivatePtr.getPointer());
- }
- for (const Expr *E : Data.FirstprivateVars) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- Address PrivatePtr =
- CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
- ".firstpriv.ptr.addr");
- PrivatePtrs.emplace_back(VD, PrivatePtr);
- CallArgs.push_back(PrivatePtr.getPointer());
- }
- for (const Expr *E : Data.LastprivateVars) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- Address PrivatePtr =
- CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
- ".lastpriv.ptr.addr");
- PrivatePtrs.emplace_back(VD, PrivatePtr);
- CallArgs.push_back(PrivatePtr.getPointer());
- }
- CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
- CopyFn, CallArgs);
- for (const auto &Pair : LastprivateDstsOrigs) {
- const auto *OrigVD = cast<VarDecl>(Pair.second->getDecl());
- DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(OrigVD),
- /*RefersToEnclosingVariableOrCapture=*/
- CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr,
- Pair.second->getType(), VK_LValue,
- Pair.second->getExprLoc());
- Scope.addPrivate(Pair.first, [&CGF, &DRE]() {
- return CGF.EmitLValue(&DRE).getAddress();
- });
- }
- for (const auto &Pair : PrivatePtrs) {
- Address Replacement(CGF.Builder.CreateLoad(Pair.second),
- CGF.getContext().getDeclAlign(Pair.first));
- Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; });
- }
- }
- if (Data.Reductions) {
- OMPLexicalScope LexScope(CGF, S, CapturedRegion);
- ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionCopies,
- Data.ReductionOps);
- llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
- CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(9)));
- for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
- RedCG.emitSharedLValue(CGF, Cnt);
- RedCG.emitAggregateType(CGF, Cnt);
- // FIXME: This must removed once the runtime library is fixed.
- // Emit required threadprivate variables for
- // initializer/combiner/finalizer.
- CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
- RedCG, Cnt);
- Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
- CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
- Replacement =
- Address(CGF.EmitScalarConversion(
- Replacement.getPointer(), CGF.getContext().VoidPtrTy,
- CGF.getContext().getPointerType(
- Data.ReductionCopies[Cnt]->getType()),
- Data.ReductionCopies[Cnt]->getExprLoc()),
- Replacement.getAlignment());
- Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
- Scope.addPrivate(RedCG.getBaseDecl(Cnt),
- [Replacement]() { return Replacement; });
- }
- }
- // Privatize all private variables except for in_reduction items.
- (void)Scope.Privatize();
- SmallVector<const Expr *, 4> InRedVars;
- SmallVector<const Expr *, 4> InRedPrivs;
- SmallVector<const Expr *, 4> InRedOps;
- SmallVector<const Expr *, 4> TaskgroupDescriptors;
- for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
- auto IPriv = C->privates().begin();
- auto IRed = C->reduction_ops().begin();
- auto ITD = C->taskgroup_descriptors().begin();
- for (const Expr *Ref : C->varlists()) {
- InRedVars.emplace_back(Ref);
- InRedPrivs.emplace_back(*IPriv);
- InRedOps.emplace_back(*IRed);
- TaskgroupDescriptors.emplace_back(*ITD);
- std::advance(IPriv, 1);
- std::advance(IRed, 1);
- std::advance(ITD, 1);
- }
- }
- // Privatize in_reduction items here, because taskgroup descriptors must be
- // privatized earlier.
- OMPPrivateScope InRedScope(CGF);
- if (!InRedVars.empty()) {
- ReductionCodeGen RedCG(InRedVars, InRedPrivs, InRedOps);
- for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) {
- RedCG.emitSharedLValue(CGF, Cnt);
- RedCG.emitAggregateType(CGF, Cnt);
- // The taskgroup descriptor variable is always implicit firstprivate and
- // privatized already during processing of the firstprivates.
- // FIXME: This must removed once the runtime library is fixed.
- // Emit required threadprivate variables for
- // initializer/combiner/finalizer.
- CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
- RedCG, Cnt);
- llvm::Value *ReductionsPtr =
- CGF.EmitLoadOfScalar(CGF.EmitLValue(TaskgroupDescriptors[Cnt]),
- TaskgroupDescriptors[Cnt]->getExprLoc());
- Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
- CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
- Replacement = Address(
- CGF.EmitScalarConversion(
- Replacement.getPointer(), CGF.getContext().VoidPtrTy,
- CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()),
- InRedPrivs[Cnt]->getExprLoc()),
- Replacement.getAlignment());
- Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
- InRedScope.addPrivate(RedCG.getBaseDecl(Cnt),
- [Replacement]() { return Replacement; });
- }
- }
- (void)InRedScope.Privatize();
-
- Action.Enter(CGF);
- BodyGen(CGF);
- };
- llvm::Value *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
- S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied,
- Data.NumberOfParts);
- OMPLexicalScope Scope(*this, S);
- TaskGen(*this, OutlinedFn, Data);
-}
-
-static ImplicitParamDecl *
-createImplicitFirstprivateForType(ASTContext &C, OMPTaskDataTy &Data,
- QualType Ty, CapturedDecl *CD,
- SourceLocation Loc) {
- auto *OrigVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
- ImplicitParamDecl::Other);
- auto *OrigRef = DeclRefExpr::Create(
- C, NestedNameSpecifierLoc(), SourceLocation(), OrigVD,
- /*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
- auto *PrivateVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
- ImplicitParamDecl::Other);
- auto *PrivateRef = DeclRefExpr::Create(
- C, NestedNameSpecifierLoc(), SourceLocation(), PrivateVD,
- /*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
- QualType ElemType = C.getBaseElementType(Ty);
- auto *InitVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, ElemType,
- ImplicitParamDecl::Other);
- auto *InitRef = DeclRefExpr::Create(
- C, NestedNameSpecifierLoc(), SourceLocation(), InitVD,
- /*RefersToEnclosingVariableOrCapture=*/false, Loc, ElemType, VK_LValue);
- PrivateVD->setInitStyle(VarDecl::CInit);
- PrivateVD->setInit(ImplicitCastExpr::Create(C, ElemType, CK_LValueToRValue,
- InitRef, /*BasePath=*/nullptr,
- VK_RValue));
- Data.FirstprivateVars.emplace_back(OrigRef);
- Data.FirstprivateCopies.emplace_back(PrivateRef);
- Data.FirstprivateInits.emplace_back(InitRef);
- return OrigVD;
-}
-
-void CodeGenFunction::EmitOMPTargetTaskBasedDirective(
- const OMPExecutableDirective &S, const RegionCodeGenTy &BodyGen,
- OMPTargetDataInfo &InputInfo) {
- // Emit outlined function for task construct.
- const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
- Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
- QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
- auto I = CS->getCapturedDecl()->param_begin();
- auto PartId = std::next(I);
- auto TaskT = std::next(I, 4);
- OMPTaskDataTy Data;
- // The task is not final.
- Data.Final.setInt(/*IntVal=*/false);
- // Get list of firstprivate variables.
- for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
- auto IRef = C->varlist_begin();
- auto IElemInitRef = C->inits().begin();
- for (auto *IInit : C->private_copies()) {
- Data.FirstprivateVars.push_back(*IRef);
- Data.FirstprivateCopies.push_back(IInit);
- Data.FirstprivateInits.push_back(*IElemInitRef);
- ++IRef;
- ++IElemInitRef;
- }
- }
- OMPPrivateScope TargetScope(*this);
- VarDecl *BPVD = nullptr;
- VarDecl *PVD = nullptr;
- VarDecl *SVD = nullptr;
- if (InputInfo.NumberOfTargetItems > 0) {
- auto *CD = CapturedDecl::Create(
- getContext(), getContext().getTranslationUnitDecl(), /*NumParams=*/0);
- llvm::APInt ArrSize(/*numBits=*/32, InputInfo.NumberOfTargetItems);
- QualType BaseAndPointersType = getContext().getConstantArrayType(
- getContext().VoidPtrTy, ArrSize, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- BPVD = createImplicitFirstprivateForType(
- getContext(), Data, BaseAndPointersType, CD, S.getBeginLoc());
- PVD = createImplicitFirstprivateForType(
- getContext(), Data, BaseAndPointersType, CD, S.getBeginLoc());
- QualType SizesType = getContext().getConstantArrayType(
- getContext().getSizeType(), ArrSize, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
- SVD = createImplicitFirstprivateForType(getContext(), Data, SizesType, CD,
- S.getBeginLoc());
- TargetScope.addPrivate(
- BPVD, [&InputInfo]() { return InputInfo.BasePointersArray; });
- TargetScope.addPrivate(PVD,
- [&InputInfo]() { return InputInfo.PointersArray; });
- TargetScope.addPrivate(SVD,
- [&InputInfo]() { return InputInfo.SizesArray; });
- }
- (void)TargetScope.Privatize();
- // Build list of dependences.
- for (const auto *C : S.getClausesOfKind<OMPDependClause>())
- for (const Expr *IRef : C->varlists())
- Data.Dependences.emplace_back(C->getDependencyKind(), IRef);
- auto &&CodeGen = [&Data, &S, CS, &BodyGen, BPVD, PVD, SVD,
- &InputInfo](CodeGenFunction &CGF, PrePostActionTy &Action) {
- // Set proper addresses for generated private copies.
- OMPPrivateScope Scope(CGF);
- if (!Data.FirstprivateVars.empty()) {
- enum { PrivatesParam = 2, CopyFnParam = 3 };
- llvm::Value *CopyFn = CGF.Builder.CreateLoad(
- CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
- llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
- CS->getCapturedDecl()->getParam(PrivatesParam)));
- // Map privates.
- llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> PrivatePtrs;
- llvm::SmallVector<llvm::Value *, 16> CallArgs;
- CallArgs.push_back(PrivatesPtr);
- for (const Expr *E : Data.FirstprivateVars) {
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- Address PrivatePtr =
- CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
- ".firstpriv.ptr.addr");
- PrivatePtrs.emplace_back(VD, PrivatePtr);
- CallArgs.push_back(PrivatePtr.getPointer());
- }
- CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
- CopyFn, CallArgs);
- for (const auto &Pair : PrivatePtrs) {
- Address Replacement(CGF.Builder.CreateLoad(Pair.second),
- CGF.getContext().getDeclAlign(Pair.first));
- Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; });
- }
- }
- // Privatize all private variables except for in_reduction items.
- (void)Scope.Privatize();
- if (InputInfo.NumberOfTargetItems > 0) {
- InputInfo.BasePointersArray = CGF.Builder.CreateConstArrayGEP(
- CGF.GetAddrOfLocalVar(BPVD), /*Index=*/0, CGF.getPointerSize());
- InputInfo.PointersArray = CGF.Builder.CreateConstArrayGEP(
- CGF.GetAddrOfLocalVar(PVD), /*Index=*/0, CGF.getPointerSize());
- InputInfo.SizesArray = CGF.Builder.CreateConstArrayGEP(
- CGF.GetAddrOfLocalVar(SVD), /*Index=*/0, CGF.getSizeSize());
- }
-
- Action.Enter(CGF);
- OMPLexicalScope LexScope(CGF, S, OMPD_task, /*EmitPreInitStmt=*/false);
- BodyGen(CGF);
- };
- llvm::Value *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
- S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, /*Tied=*/true,
- Data.NumberOfParts);
- llvm::APInt TrueOrFalse(32, S.hasClausesOfKind<OMPNowaitClause>() ? 1 : 0);
- IntegerLiteral IfCond(getContext(), TrueOrFalse,
- getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
- SourceLocation());
-
- CGM.getOpenMPRuntime().emitTaskCall(*this, S.getBeginLoc(), S, OutlinedFn,
- SharedsTy, CapturedStruct, &IfCond, Data);
-}
-
-void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) {
- // Emit outlined function for task construct.
- const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
- Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
- QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
- const Expr *IfCond = nullptr;
- for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
- if (C->getNameModifier() == OMPD_unknown ||
- C->getNameModifier() == OMPD_task) {
- IfCond = C->getCondition();
- break;
- }
- }
-
- OMPTaskDataTy Data;
- // Check if we should emit tied or untied task.
- Data.Tied = !S.getSingleClause<OMPUntiedClause>();
- auto &&BodyGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitStmt(CS->getCapturedStmt());
- };
- auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
- IfCond](CodeGenFunction &CGF, llvm::Value *OutlinedFn,
- const OMPTaskDataTy &Data) {
- CGF.CGM.getOpenMPRuntime().emitTaskCall(CGF, S.getBeginLoc(), S, OutlinedFn,
- SharedsTy, CapturedStruct, IfCond,
- Data);
- };
- EmitOMPTaskBasedDirective(S, OMPD_task, BodyGen, TaskGen, Data);
-}
-
-void CodeGenFunction::EmitOMPTaskyieldDirective(
- const OMPTaskyieldDirective &S) {
- CGM.getOpenMPRuntime().emitTaskyieldCall(*this, S.getBeginLoc());
-}
-
-void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_barrier);
-}
-
-void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
- CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc());
-}
-
-void CodeGenFunction::EmitOMPTaskgroupDirective(
- const OMPTaskgroupDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- if (const Expr *E = S.getReductionRef()) {
- SmallVector<const Expr *, 4> LHSs;
- SmallVector<const Expr *, 4> RHSs;
- OMPTaskDataTy Data;
- for (const auto *C : S.getClausesOfKind<OMPTaskReductionClause>()) {
- auto IPriv = C->privates().begin();
- auto IRed = C->reduction_ops().begin();
- auto ILHS = C->lhs_exprs().begin();
- auto IRHS = C->rhs_exprs().begin();
- for (const Expr *Ref : C->varlists()) {
- Data.ReductionVars.emplace_back(Ref);
- Data.ReductionCopies.emplace_back(*IPriv);
- Data.ReductionOps.emplace_back(*IRed);
- LHSs.emplace_back(*ILHS);
- RHSs.emplace_back(*IRHS);
- std::advance(IPriv, 1);
- std::advance(IRed, 1);
- std::advance(ILHS, 1);
- std::advance(IRHS, 1);
- }
- }
- llvm::Value *ReductionDesc =
- CGF.CGM.getOpenMPRuntime().emitTaskReductionInit(CGF, S.getBeginLoc(),
- LHSs, RHSs, Data);
- const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- CGF.EmitVarDecl(*VD);
- CGF.EmitStoreOfScalar(ReductionDesc, CGF.GetAddrOfLocalVar(VD),
- /*Volatile=*/false, E->getType());
- }
- CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getBeginLoc());
-}
-
-void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
- CGM.getOpenMPRuntime().emitFlush(
- *this,
- [&S]() -> ArrayRef<const Expr *> {
- if (const auto *FlushClause = S.getSingleClause<OMPFlushClause>())
- return llvm::makeArrayRef(FlushClause->varlist_begin(),
- FlushClause->varlist_end());
- return llvm::None;
- }(),
- S.getBeginLoc());
-}
-
-void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
- const CodeGenLoopTy &CodeGenLoop,
- Expr *IncExpr) {
- // Emit the loop iteration variable.
- const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
- const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
- EmitVarDecl(*IVDecl);
-
- // Emit the iterations count variable.
- // If it is not a variable, Sema decided to calculate iterations count on each
- // iteration (e.g., it is foldable into a constant).
- if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
- EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
- // Emit calculation of the iterations count.
- EmitIgnoredExpr(S.getCalcLastIteration());
- }
-
- CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
-
- bool HasLastprivateClause = false;
- // Check pre-condition.
- {
- OMPLoopScope PreInitScope(*this, S);
- // Skip the entire loop if we don't meet the precondition.
- // If the condition constant folds and can be elided, avoid emitting the
- // whole loop.
- bool CondConstant;
- llvm::BasicBlock *ContBlock = nullptr;
- if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
- if (!CondConstant)
- return;
- } else {
- llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
- ContBlock = createBasicBlock("omp.precond.end");
- emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
- getProfileCount(&S));
- EmitBlock(ThenBlock);
- incrementProfileCounter(&S);
- }
-
- emitAlignedClause(*this, S);
- // Emit 'then' code.
- {
- // Emit helper vars inits.
-
- LValue LB = EmitOMPHelperVar(
- *this, cast<DeclRefExpr>(
- (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedLowerBoundVariable()
- : S.getLowerBoundVariable())));
- LValue UB = EmitOMPHelperVar(
- *this, cast<DeclRefExpr>(
- (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedUpperBoundVariable()
- : S.getUpperBoundVariable())));
- LValue ST =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
- LValue IL =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
-
- OMPPrivateScope LoopScope(*this);
- if (EmitOMPFirstprivateClause(S, LoopScope)) {
- // Emit implicit barrier to synchronize threads and avoid data races
- // on initialization of firstprivate variables and post-update of
- // lastprivate variables.
- CGM.getOpenMPRuntime().emitBarrierCall(
- *this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
- }
- EmitOMPPrivateClause(S, LoopScope);
- if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
- !isOpenMPParallelDirective(S.getDirectiveKind()) &&
- !isOpenMPTeamsDirective(S.getDirectiveKind()))
- EmitOMPReductionClauseInit(S, LoopScope);
- HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
- EmitOMPPrivateLoopCounters(S, LoopScope);
- (void)LoopScope.Privatize();
- if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
- CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
-
- // Detect the distribute schedule kind and chunk.
- llvm::Value *Chunk = nullptr;
- OpenMPDistScheduleClauseKind ScheduleKind = OMPC_DIST_SCHEDULE_unknown;
- if (const auto *C = S.getSingleClause<OMPDistScheduleClause>()) {
- ScheduleKind = C->getDistScheduleKind();
- if (const Expr *Ch = C->getChunkSize()) {
- Chunk = EmitScalarExpr(Ch);
- Chunk = EmitScalarConversion(Chunk, Ch->getType(),
- S.getIterationVariable()->getType(),
- S.getBeginLoc());
- }
- } else {
- // Default behaviour for dist_schedule clause.
- CGM.getOpenMPRuntime().getDefaultDistScheduleAndChunk(
- *this, S, ScheduleKind, Chunk);
- }
- const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
- const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
-
- // OpenMP [2.10.8, distribute Construct, Description]
- // If dist_schedule is specified, kind must be static. If specified,
- // iterations are divided into chunks of size chunk_size, chunks are
- // assigned to the teams of the league in a round-robin fashion in the
- // order of the team number. When no chunk_size is specified, the
- // iteration space is divided into chunks that are approximately equal
- // in size, and at most one chunk is distributed to each team of the
- // league. The size of the chunks is unspecified in this case.
- bool StaticChunked = RT.isStaticChunked(
- ScheduleKind, /* Chunked */ Chunk != nullptr) &&
- isOpenMPLoopBoundSharingDirective(S.getDirectiveKind());
- if (RT.isStaticNonchunked(ScheduleKind,
- /* Chunked */ Chunk != nullptr) ||
- StaticChunked) {
- if (isOpenMPSimdDirective(S.getDirectiveKind()))
- EmitOMPSimdInit(S, /*IsMonotonic=*/true);
- CGOpenMPRuntime::StaticRTInput StaticInit(
- IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(),
- LB.getAddress(), UB.getAddress(), ST.getAddress(),
- StaticChunked ? Chunk : nullptr);
- RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind,
- StaticInit);
- JumpDest LoopExit =
- getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
- // UB = min(UB, GlobalUB);
- EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedEnsureUpperBound()
- : S.getEnsureUpperBound());
- // IV = LB;
- EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedInit()
- : S.getInit());
-
- const Expr *Cond =
- isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
- ? S.getCombinedCond()
- : S.getCond();
-
- if (StaticChunked)
- Cond = S.getCombinedDistCond();
-
- // For static unchunked schedules generate:
- //
- // 1. For distribute alone, codegen
- // while (idx <= UB) {
- // BODY;
- // ++idx;
- // }
- //
- // 2. When combined with 'for' (e.g. as in 'distribute parallel for')
- // while (idx <= UB) {
- // <CodeGen rest of pragma>(LB, UB);
- // idx += ST;
- // }
- //
- // For static chunk one schedule generate:
- //
- // while (IV <= GlobalUB) {
- // <CodeGen rest of pragma>(LB, UB);
- // LB += ST;
- // UB += ST;
- // UB = min(UB, GlobalUB);
- // IV = LB;
- // }
- //
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), Cond, IncExpr,
- [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
- CodeGenLoop(CGF, S, LoopExit);
- },
- [&S, StaticChunked](CodeGenFunction &CGF) {
- if (StaticChunked) {
- CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound());
- CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound());
- CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound());
- CGF.EmitIgnoredExpr(S.getCombinedInit());
- }
- });
- EmitBlock(LoopExit.getBlock());
- // Tell the runtime we are done.
- RT.emitForStaticFinish(*this, S.getBeginLoc(), S.getDirectiveKind());
- } else {
- // Emit the outer loop, which requests its work chunk [LB..UB] from
- // runtime and runs the inner loop to process it.
- const OMPLoopArguments LoopArguments = {
- LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(),
- Chunk};
- EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments,
- CodeGenLoop);
- }
- if (isOpenMPSimdDirective(S.getDirectiveKind())) {
- EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
- return CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
- });
- }
- if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
- !isOpenMPParallelDirective(S.getDirectiveKind()) &&
- !isOpenMPTeamsDirective(S.getDirectiveKind())) {
- EmitOMPReductionClauseFinal(S, OMPD_simd);
- // Emit post-update of the reduction variables if IsLastIter != 0.
- emitPostUpdateForReductionClause(
- *this, S, [IL, &S](CodeGenFunction &CGF) {
- return CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
- });
- }
- // Emit final copy of the lastprivate variables if IsLastIter != 0.
- if (HasLastprivateClause) {
- EmitOMPLastprivateClauseFinal(
- S, /*NoFinals=*/false,
- Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
- }
- }
-
- // We're now done with the loop, so jump to the continuation block.
- if (ContBlock) {
- EmitBranch(ContBlock);
- EmitBlock(ContBlock, true);
- }
- }
-}
-
-void CodeGenFunction::EmitOMPDistributeDirective(
- const OMPDistributeDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
-}
-
-static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM,
- const CapturedStmt *S) {
- CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
- CodeGenFunction::CGCapturedStmtInfo CapStmtInfo;
- CGF.CapturedStmtInfo = &CapStmtInfo;
- llvm::Function *Fn = CGF.GenerateOpenMPCapturedStmtFunction(*S);
- Fn->setDoesNotRecurse();
- return Fn;
-}
-
-void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) {
- if (S.hasClausesOfKind<OMPDependClause>()) {
- assert(!S.getAssociatedStmt() &&
- "No associated statement must be in ordered depend construct.");
- for (const auto *DC : S.getClausesOfKind<OMPDependClause>())
- CGM.getOpenMPRuntime().emitDoacrossOrdered(*this, DC);
- return;
- }
- const auto *C = S.getSingleClause<OMPSIMDClause>();
- auto &&CodeGen = [&S, C, this](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- const CapturedStmt *CS = S.getInnermostCapturedStmt();
- if (C) {
- llvm::SmallVector<llvm::Value *, 16> CapturedVars;
- CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
- llvm::Function *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS);
- CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
- OutlinedFn, CapturedVars);
- } else {
- Action.Enter(CGF);
- CGF.EmitStmt(CS->getCapturedStmt());
- }
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getBeginLoc(), !C);
-}
-
-static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val,
- QualType SrcType, QualType DestType,
- SourceLocation Loc) {
- assert(CGF.hasScalarEvaluationKind(DestType) &&
- "DestType must have scalar evaluation kind.");
- assert(!Val.isAggregate() && "Must be a scalar or complex.");
- return Val.isScalar() ? CGF.EmitScalarConversion(Val.getScalarVal(), SrcType,
- DestType, Loc)
- : CGF.EmitComplexToScalarConversion(
- Val.getComplexVal(), SrcType, DestType, Loc);
-}
-
-static CodeGenFunction::ComplexPairTy
-convertToComplexValue(CodeGenFunction &CGF, RValue Val, QualType SrcType,
- QualType DestType, SourceLocation Loc) {
- assert(CGF.getEvaluationKind(DestType) == TEK_Complex &&
- "DestType must have complex evaluation kind.");
- CodeGenFunction::ComplexPairTy ComplexVal;
- if (Val.isScalar()) {
- // Convert the input element to the element type of the complex.
- QualType DestElementType =
- DestType->castAs<ComplexType>()->getElementType();
- llvm::Value *ScalarVal = CGF.EmitScalarConversion(
- Val.getScalarVal(), SrcType, DestElementType, Loc);
- ComplexVal = CodeGenFunction::ComplexPairTy(
- ScalarVal, llvm::Constant::getNullValue(ScalarVal->getType()));
- } else {
- assert(Val.isComplex() && "Must be a scalar or complex.");
- QualType SrcElementType = SrcType->castAs<ComplexType>()->getElementType();
- QualType DestElementType =
- DestType->castAs<ComplexType>()->getElementType();
- ComplexVal.first = CGF.EmitScalarConversion(
- Val.getComplexVal().first, SrcElementType, DestElementType, Loc);
- ComplexVal.second = CGF.EmitScalarConversion(
- Val.getComplexVal().second, SrcElementType, DestElementType, Loc);
- }
- return ComplexVal;
-}
-
-static void emitSimpleAtomicStore(CodeGenFunction &CGF, bool IsSeqCst,
- LValue LVal, RValue RVal) {
- if (LVal.isGlobalReg()) {
- CGF.EmitStoreThroughGlobalRegLValue(RVal, LVal);
- } else {
- CGF.EmitAtomicStore(RVal, LVal,
- IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent
- : llvm::AtomicOrdering::Monotonic,
- LVal.isVolatile(), /*IsInit=*/false);
- }
-}
-
-void CodeGenFunction::emitOMPSimpleStore(LValue LVal, RValue RVal,
- QualType RValTy, SourceLocation Loc) {
- switch (getEvaluationKind(LVal.getType())) {
- case TEK_Scalar:
- EmitStoreThroughLValue(RValue::get(convertToScalarValue(
- *this, RVal, RValTy, LVal.getType(), Loc)),
- LVal);
- break;
- case TEK_Complex:
- EmitStoreOfComplex(
- convertToComplexValue(*this, RVal, RValTy, LVal.getType(), Loc), LVal,
- /*isInit=*/false);
- break;
- case TEK_Aggregate:
- llvm_unreachable("Must be a scalar or complex.");
- }
-}
-
-static void emitOMPAtomicReadExpr(CodeGenFunction &CGF, bool IsSeqCst,
- const Expr *X, const Expr *V,
- SourceLocation Loc) {
- // v = x;
- assert(V->isLValue() && "V of 'omp atomic read' is not lvalue");
- assert(X->isLValue() && "X of 'omp atomic read' is not lvalue");
- LValue XLValue = CGF.EmitLValue(X);
- LValue VLValue = CGF.EmitLValue(V);
- RValue Res = XLValue.isGlobalReg()
- ? CGF.EmitLoadOfLValue(XLValue, Loc)
- : CGF.EmitAtomicLoad(
- XLValue, Loc,
- IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent
- : llvm::AtomicOrdering::Monotonic,
- XLValue.isVolatile());
- // OpenMP, 2.12.6, atomic Construct
- // Any atomic construct with a seq_cst clause forces the atomically
- // performed operation to include an implicit flush operation without a
- // list.
- if (IsSeqCst)
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
- CGF.emitOMPSimpleStore(VLValue, Res, X->getType().getNonReferenceType(), Loc);
-}
-
-static void emitOMPAtomicWriteExpr(CodeGenFunction &CGF, bool IsSeqCst,
- const Expr *X, const Expr *E,
- SourceLocation Loc) {
- // x = expr;
- assert(X->isLValue() && "X of 'omp atomic write' is not lvalue");
- emitSimpleAtomicStore(CGF, IsSeqCst, CGF.EmitLValue(X), CGF.EmitAnyExpr(E));
- // OpenMP, 2.12.6, atomic Construct
- // Any atomic construct with a seq_cst clause forces the atomically
- // performed operation to include an implicit flush operation without a
- // list.
- if (IsSeqCst)
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
-}
-
-static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
- RValue Update,
- BinaryOperatorKind BO,
- llvm::AtomicOrdering AO,
- bool IsXLHSInRHSPart) {
- ASTContext &Context = CGF.getContext();
- // Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x'
- // expression is simple and atomic is allowed for the given type for the
- // target platform.
- if (BO == BO_Comma || !Update.isScalar() ||
- !Update.getScalarVal()->getType()->isIntegerTy() ||
- !X.isSimple() || (!isa<llvm::ConstantInt>(Update.getScalarVal()) &&
- (Update.getScalarVal()->getType() !=
- X.getAddress().getElementType())) ||
- !X.getAddress().getElementType()->isIntegerTy() ||
- !Context.getTargetInfo().hasBuiltinAtomic(
- Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment())))
- return std::make_pair(false, RValue::get(nullptr));
-
- llvm::AtomicRMWInst::BinOp RMWOp;
- switch (BO) {
- case BO_Add:
- RMWOp = llvm::AtomicRMWInst::Add;
- break;
- case BO_Sub:
- if (!IsXLHSInRHSPart)
- return std::make_pair(false, RValue::get(nullptr));
- RMWOp = llvm::AtomicRMWInst::Sub;
- break;
- case BO_And:
- RMWOp = llvm::AtomicRMWInst::And;
- break;
- case BO_Or:
- RMWOp = llvm::AtomicRMWInst::Or;
- break;
- case BO_Xor:
- RMWOp = llvm::AtomicRMWInst::Xor;
- break;
- case BO_LT:
- RMWOp = X.getType()->hasSignedIntegerRepresentation()
- ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
- : llvm::AtomicRMWInst::Max)
- : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
- : llvm::AtomicRMWInst::UMax);
- break;
- case BO_GT:
- RMWOp = X.getType()->hasSignedIntegerRepresentation()
- ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
- : llvm::AtomicRMWInst::Min)
- : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
- : llvm::AtomicRMWInst::UMin);
- break;
- case BO_Assign:
- RMWOp = llvm::AtomicRMWInst::Xchg;
- break;
- case BO_Mul:
- case BO_Div:
- case BO_Rem:
- case BO_Shl:
- case BO_Shr:
- case BO_LAnd:
- case BO_LOr:
- return std::make_pair(false, RValue::get(nullptr));
- case BO_PtrMemD:
- case BO_PtrMemI:
- case BO_LE:
- case BO_GE:
- case BO_EQ:
- case BO_NE:
- case BO_Cmp:
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_AndAssign:
- case BO_OrAssign:
- case BO_XorAssign:
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_RemAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_Comma:
- llvm_unreachable("Unsupported atomic update operation");
- }
- llvm::Value *UpdateVal = Update.getScalarVal();
- if (auto *IC = dyn_cast<llvm::ConstantInt>(UpdateVal)) {
- UpdateVal = CGF.Builder.CreateIntCast(
- IC, X.getAddress().getElementType(),
- X.getType()->hasSignedIntegerRepresentation());
- }
- llvm::Value *Res =
- CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(), UpdateVal, AO);
- return std::make_pair(true, RValue::get(Res));
-}
-
-std::pair<bool, RValue> CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr(
- LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart,
- llvm::AtomicOrdering AO, SourceLocation Loc,
- const llvm::function_ref<RValue(RValue)> CommonGen) {
- // Update expressions are allowed to have the following forms:
- // x binop= expr; -> xrval + expr;
- // x++, ++x -> xrval + 1;
- // x--, --x -> xrval - 1;
- // x = x binop expr; -> xrval binop expr
- // x = expr Op x; - > expr binop xrval;
- auto Res = emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart);
- if (!Res.first) {
- if (X.isGlobalReg()) {
- // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop
- // 'xrval'.
- EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X);
- } else {
- // Perform compare-and-swap procedure.
- EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified());
- }
- }
- return Res;
-}
-
-static void emitOMPAtomicUpdateExpr(CodeGenFunction &CGF, bool IsSeqCst,
- const Expr *X, const Expr *E,
- const Expr *UE, bool IsXLHSInRHSPart,
- SourceLocation Loc) {
- assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
- "Update expr in 'atomic update' must be a binary operator.");
- const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
- // Update expressions are allowed to have the following forms:
- // x binop= expr; -> xrval + expr;
- // x++, ++x -> xrval + 1;
- // x--, --x -> xrval - 1;
- // x = x binop expr; -> xrval binop expr
- // x = expr Op x; - > expr binop xrval;
- assert(X->isLValue() && "X of 'omp atomic update' is not lvalue");
- LValue XLValue = CGF.EmitLValue(X);
- RValue ExprRValue = CGF.EmitAnyExpr(E);
- llvm::AtomicOrdering AO = IsSeqCst
- ? llvm::AtomicOrdering::SequentiallyConsistent
- : llvm::AtomicOrdering::Monotonic;
- const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
- const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
- const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
- const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
- auto &&Gen = [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) {
- CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
- CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
- return CGF.EmitAnyExpr(UE);
- };
- (void)CGF.EmitOMPAtomicSimpleUpdateExpr(
- XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
- // OpenMP, 2.12.6, atomic Construct
- // Any atomic construct with a seq_cst clause forces the atomically
- // performed operation to include an implicit flush operation without a
- // list.
- if (IsSeqCst)
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
-}
-
-static RValue convertToType(CodeGenFunction &CGF, RValue Value,
- QualType SourceType, QualType ResType,
- SourceLocation Loc) {
- switch (CGF.getEvaluationKind(ResType)) {
- case TEK_Scalar:
- return RValue::get(
- convertToScalarValue(CGF, Value, SourceType, ResType, Loc));
- case TEK_Complex: {
- auto Res = convertToComplexValue(CGF, Value, SourceType, ResType, Loc);
- return RValue::getComplex(Res.first, Res.second);
- }
- case TEK_Aggregate:
- break;
- }
- llvm_unreachable("Must be a scalar or complex.");
-}
-
-static void emitOMPAtomicCaptureExpr(CodeGenFunction &CGF, bool IsSeqCst,
- bool IsPostfixUpdate, const Expr *V,
- const Expr *X, const Expr *E,
- const Expr *UE, bool IsXLHSInRHSPart,
- SourceLocation Loc) {
- assert(X->isLValue() && "X of 'omp atomic capture' is not lvalue");
- assert(V->isLValue() && "V of 'omp atomic capture' is not lvalue");
- RValue NewVVal;
- LValue VLValue = CGF.EmitLValue(V);
- LValue XLValue = CGF.EmitLValue(X);
- RValue ExprRValue = CGF.EmitAnyExpr(E);
- llvm::AtomicOrdering AO = IsSeqCst
- ? llvm::AtomicOrdering::SequentiallyConsistent
- : llvm::AtomicOrdering::Monotonic;
- QualType NewVValType;
- if (UE) {
- // 'x' is updated with some additional value.
- assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
- "Update expr in 'atomic capture' must be a binary operator.");
- const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
- // Update expressions are allowed to have the following forms:
- // x binop= expr; -> xrval + expr;
- // x++, ++x -> xrval + 1;
- // x--, --x -> xrval - 1;
- // x = x binop expr; -> xrval binop expr
- // x = expr Op x; - > expr binop xrval;
- const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
- const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
- const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
- NewVValType = XRValExpr->getType();
- const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
- auto &&Gen = [&CGF, &NewVVal, UE, ExprRValue, XRValExpr, ERValExpr,
- IsPostfixUpdate](RValue XRValue) {
- CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
- CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
- RValue Res = CGF.EmitAnyExpr(UE);
- NewVVal = IsPostfixUpdate ? XRValue : Res;
- return Res;
- };
- auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
- XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
- if (Res.first) {
- // 'atomicrmw' instruction was generated.
- if (IsPostfixUpdate) {
- // Use old value from 'atomicrmw'.
- NewVVal = Res.second;
- } else {
- // 'atomicrmw' does not provide new value, so evaluate it using old
- // value of 'x'.
- CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
- CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, Res.second);
- NewVVal = CGF.EmitAnyExpr(UE);
- }
- }
- } else {
- // 'x' is simply rewritten with some 'expr'.
- NewVValType = X->getType().getNonReferenceType();
- ExprRValue = convertToType(CGF, ExprRValue, E->getType(),
- X->getType().getNonReferenceType(), Loc);
- auto &&Gen = [&NewVVal, ExprRValue](RValue XRValue) {
- NewVVal = XRValue;
- return ExprRValue;
- };
- // Try to perform atomicrmw xchg, otherwise simple exchange.
- auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
- XLValue, ExprRValue, /*BO=*/BO_Assign, /*IsXLHSInRHSPart=*/false, AO,
- Loc, Gen);
- if (Res.first) {
- // 'atomicrmw' instruction was generated.
- NewVVal = IsPostfixUpdate ? Res.second : ExprRValue;
- }
- }
- // Emit post-update store to 'v' of old/new 'x' value.
- CGF.emitOMPSimpleStore(VLValue, NewVVal, NewVValType, Loc);
- // OpenMP, 2.12.6, atomic Construct
- // Any atomic construct with a seq_cst clause forces the atomically
- // performed operation to include an implicit flush operation without a
- // list.
- if (IsSeqCst)
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
-}
-
-static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
- bool IsSeqCst, bool IsPostfixUpdate,
- const Expr *X, const Expr *V, const Expr *E,
- const Expr *UE, bool IsXLHSInRHSPart,
- SourceLocation Loc) {
- switch (Kind) {
- case OMPC_read:
- emitOMPAtomicReadExpr(CGF, IsSeqCst, X, V, Loc);
- break;
- case OMPC_write:
- emitOMPAtomicWriteExpr(CGF, IsSeqCst, X, E, Loc);
- break;
- case OMPC_unknown:
- case OMPC_update:
- emitOMPAtomicUpdateExpr(CGF, IsSeqCst, X, E, UE, IsXLHSInRHSPart, Loc);
- break;
- case OMPC_capture:
- emitOMPAtomicCaptureExpr(CGF, IsSeqCst, IsPostfixUpdate, V, X, E, UE,
- IsXLHSInRHSPart, Loc);
- break;
- case OMPC_if:
- case OMPC_final:
- case OMPC_num_threads:
- case OMPC_private:
- case OMPC_firstprivate:
- case OMPC_lastprivate:
- case OMPC_reduction:
- case OMPC_task_reduction:
- case OMPC_in_reduction:
- case OMPC_safelen:
- case OMPC_simdlen:
- case OMPC_collapse:
- case OMPC_default:
- case OMPC_seq_cst:
- case OMPC_shared:
- case OMPC_linear:
- case OMPC_aligned:
- case OMPC_copyin:
- case OMPC_copyprivate:
- case OMPC_flush:
- case OMPC_proc_bind:
- case OMPC_schedule:
- case OMPC_ordered:
- case OMPC_nowait:
- case OMPC_untied:
- case OMPC_threadprivate:
- case OMPC_depend:
- case OMPC_mergeable:
- case OMPC_device:
- case OMPC_threads:
- case OMPC_simd:
- case OMPC_map:
- case OMPC_num_teams:
- case OMPC_thread_limit:
- case OMPC_priority:
- case OMPC_grainsize:
- case OMPC_nogroup:
- case OMPC_num_tasks:
- case OMPC_hint:
- case OMPC_dist_schedule:
- case OMPC_defaultmap:
- case OMPC_uniform:
- case OMPC_to:
- case OMPC_from:
- case OMPC_use_device_ptr:
- case OMPC_is_device_ptr:
- case OMPC_unified_address:
- case OMPC_unified_shared_memory:
- case OMPC_reverse_offload:
- case OMPC_dynamic_allocators:
- case OMPC_atomic_default_mem_order:
- llvm_unreachable("Clause is not allowed in 'omp atomic'.");
- }
-}
-
-void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
- bool IsSeqCst = S.getSingleClause<OMPSeqCstClause>();
- OpenMPClauseKind Kind = OMPC_unknown;
- for (const OMPClause *C : S.clauses()) {
- // Find first clause (skip seq_cst clause, if it is first).
- if (C->getClauseKind() != OMPC_seq_cst) {
- Kind = C->getClauseKind();
- break;
- }
- }
-
- const Stmt *CS = S.getInnermostCapturedStmt()->IgnoreContainers();
- if (const auto *FE = dyn_cast<FullExpr>(CS))
- enterFullExpression(FE);
- // Processing for statements under 'atomic capture'.
- if (const auto *Compound = dyn_cast<CompoundStmt>(CS)) {
- for (const Stmt *C : Compound->body()) {
- if (const auto *FE = dyn_cast<FullExpr>(C))
- enterFullExpression(FE);
- }
- }
-
- auto &&CodeGen = [&S, Kind, IsSeqCst, CS](CodeGenFunction &CGF,
- PrePostActionTy &) {
- CGF.EmitStopPoint(CS);
- emitOMPAtomicExpr(CGF, Kind, IsSeqCst, S.isPostfixUpdate(), S.getX(),
- S.getV(), S.getExpr(), S.getUpdateExpr(),
- S.isXLHSInRHSPart(), S.getBeginLoc());
- };
- OMPLexicalScope Scope(*this, S, OMPD_unknown);
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_atomic, CodeGen);
-}
-
-static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
- const OMPExecutableDirective &S,
- const RegionCodeGenTy &CodeGen) {
- assert(isOpenMPTargetExecutionDirective(S.getDirectiveKind()));
- CodeGenModule &CGM = CGF.CGM;
-
- // On device emit this construct as inlined code.
- if (CGM.getLangOpts().OpenMPIsDevice) {
- OMPLexicalScope Scope(CGF, S, OMPD_target);
- CGM.getOpenMPRuntime().emitInlinedDirective(
- CGF, OMPD_target, [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
- });
- return;
- }
-
- llvm::Function *Fn = nullptr;
- llvm::Constant *FnID = nullptr;
-
- const Expr *IfCond = nullptr;
- // Check for the at most one if clause associated with the target region.
- for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
- if (C->getNameModifier() == OMPD_unknown ||
- C->getNameModifier() == OMPD_target) {
- IfCond = C->getCondition();
- break;
- }
- }
-
- // Check if we have any device clause associated with the directive.
- const Expr *Device = nullptr;
- if (auto *C = S.getSingleClause<OMPDeviceClause>())
- Device = C->getDevice();
-
- // Check if we have an if clause whose conditional always evaluates to false
- // or if we do not have any targets specified. If so the target region is not
- // an offload entry point.
- bool IsOffloadEntry = true;
- if (IfCond) {
- bool Val;
- if (CGF.ConstantFoldsToSimpleInteger(IfCond, Val) && !Val)
- IsOffloadEntry = false;
- }
- if (CGM.getLangOpts().OMPTargetTriples.empty())
- IsOffloadEntry = false;
-
- assert(CGF.CurFuncDecl && "No parent declaration for target region!");
- StringRef ParentName;
- // In case we have Ctors/Dtors we use the complete type variant to produce
- // the mangling of the device outlined kernel.
- if (const auto *D = dyn_cast<CXXConstructorDecl>(CGF.CurFuncDecl))
- ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete));
- else if (const auto *D = dyn_cast<CXXDestructorDecl>(CGF.CurFuncDecl))
- ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete));
- else
- ParentName =
- CGM.getMangledName(GlobalDecl(cast<FunctionDecl>(CGF.CurFuncDecl)));
-
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID,
- IsOffloadEntry, CodeGen);
- OMPLexicalScope Scope(CGF, S, OMPD_task);
- auto &&SizeEmitter = [](CodeGenFunction &CGF, const OMPLoopDirective &D) {
- OMPLoopScope(CGF, D);
- // Emit calculation of the iterations count.
- llvm::Value *NumIterations = CGF.EmitScalarExpr(D.getNumIterations());
- NumIterations = CGF.Builder.CreateIntCast(NumIterations, CGF.Int64Ty,
- /*IsSigned=*/false);
- return NumIterations;
- };
- CGM.getOpenMPRuntime().emitTargetNumIterationsCall(CGF, S, Device,
- SizeEmitter);
- CGM.getOpenMPRuntime().emitTargetCall(CGF, S, Fn, FnID, IfCond, Device);
-}
-
-static void emitTargetRegion(CodeGenFunction &CGF, const OMPTargetDirective &S,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- CGF.EmitOMPPrivateClause(S, PrivateScope);
- (void)PrivateScope.Privatize();
- if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
- CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
-
- CGF.EmitStmt(S.getCapturedStmt(OMPD_target)->getCapturedStmt());
-}
-
-void CodeGenFunction::EmitOMPTargetDeviceFunction(CodeGenModule &CGM,
- StringRef ParentName,
- const OMPTargetDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetRegion(CGF, S, Action);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetRegion(CGF, S, Action);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-static void emitCommonOMPTeamsDirective(CodeGenFunction &CGF,
- const OMPExecutableDirective &S,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) {
- const CapturedStmt *CS = S.getCapturedStmt(OMPD_teams);
- llvm::Value *OutlinedFn =
- CGF.CGM.getOpenMPRuntime().emitTeamsOutlinedFunction(
- S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
-
- const auto *NT = S.getSingleClause<OMPNumTeamsClause>();
- const auto *TL = S.getSingleClause<OMPThreadLimitClause>();
- if (NT || TL) {
- const Expr *NumTeams = NT ? NT->getNumTeams() : nullptr;
- const Expr *ThreadLimit = TL ? TL->getThreadLimit() : nullptr;
-
- CGF.CGM.getOpenMPRuntime().emitNumTeamsClause(CGF, NumTeams, ThreadLimit,
- S.getBeginLoc());
- }
-
- OMPTeamsScope Scope(CGF, S);
- llvm::SmallVector<llvm::Value *, 16> CapturedVars;
- CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
- CGF.CGM.getOpenMPRuntime().emitTeamsCall(CGF, S, S.getBeginLoc(), OutlinedFn,
- CapturedVars);
-}
-
-void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &S) {
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPPrivateScope PrivateScope(CGF);
- (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- CGF.EmitOMPPrivateClause(S, PrivateScope);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.EmitStmt(S.getCapturedStmt(OMPD_teams)->getCapturedStmt());
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
- emitPostUpdateForReductionClause(*this, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-static void emitTargetTeamsRegion(CodeGenFunction &CGF, PrePostActionTy &Action,
- const OMPTargetTeamsDirective &S) {
- auto *CS = S.getCapturedStmt(OMPD_teams);
- Action.Enter(CGF);
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- CGF.EmitOMPPrivateClause(S, PrivateScope);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
- CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
- CGF.EmitStmt(CS->getCapturedStmt());
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(CGF, S, OMPD_teams, CodeGen);
- emitPostUpdateForReductionClause(CGF, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsRegion(CGF, Action, S);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDirective(
- const OMPTargetTeamsDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsRegion(CGF, Action, S);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-static void
-emitTargetTeamsDistributeRegion(CodeGenFunction &CGF, PrePostActionTy &Action,
- const OMPTargetTeamsDistributeDirective &S) {
- Action.Enter(CGF);
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
- CodeGenDistribute);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
- emitPostUpdateForReductionClause(CGF, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeRegion(CGF, Action, S);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective(
- const OMPTargetTeamsDistributeDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeRegion(CGF, Action, S);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-static void emitTargetTeamsDistributeSimdRegion(
- CodeGenFunction &CGF, PrePostActionTy &Action,
- const OMPTargetTeamsDistributeSimdDirective &S) {
- Action.Enter(CGF);
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
- CodeGenDistribute);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_simd, CodeGen);
- emitPostUpdateForReductionClause(CGF, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeSimdRegion(CGF, Action, S);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective(
- const OMPTargetTeamsDistributeSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeSimdRegion(CGF, Action, S);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-void CodeGenFunction::EmitOMPTeamsDistributeDirective(
- const OMPTeamsDistributeDirective &S) {
-
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
- CodeGenDistribute);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
- emitPostUpdateForReductionClause(*this, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTeamsDistributeSimdDirective(
- const OMPTeamsDistributeSimdDirective &S) {
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_simd,
- CodeGenDistribute);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_simd, CodeGen);
- emitPostUpdateForReductionClause(*this, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTeamsDistributeParallelForDirective(
- const OMPTeamsDistributeParallelForDirective &S) {
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
- S.getDistInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
- CodeGenDistribute);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
- emitPostUpdateForReductionClause(*this, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTeamsDistributeParallelForSimdDirective(
- const OMPTeamsDistributeParallelForSimdDirective &S) {
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
- S.getDistInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
- CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
- emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
- emitPostUpdateForReductionClause(*this, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-static void emitTargetTeamsDistributeParallelForRegion(
- CodeGenFunction &CGF, const OMPTargetTeamsDistributeParallelForDirective &S,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
- S.getDistInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
- CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
-
- emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
- CodeGenTeams);
- emitPostUpdateForReductionClause(CGF, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeParallelForDirective &S) {
- // Emit SPMD target teams distribute parallel for region as a standalone
- // region.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeParallelForRegion(CGF, S, Action);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDirective(
- const OMPTargetTeamsDistributeParallelForDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeParallelForRegion(CGF, S, Action);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-static void emitTargetTeamsDistributeParallelForSimdRegion(
- CodeGenFunction &CGF,
- const OMPTargetTeamsDistributeParallelForSimdDirective &S,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
- S.getDistInc());
- };
-
- // Emit teams region as a standalone region.
- auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
- CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
- };
-
- emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for_simd,
- CodeGenTeams);
- emitPostUpdateForReductionClause(CGF, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeParallelForSimdDirective &S) {
- // Emit SPMD target teams distribute parallel for simd region as a standalone
- // region.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeParallelForSimdRegion(CGF, S, Action);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDirective(
- const OMPTargetTeamsDistributeParallelForSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsDistributeParallelForSimdRegion(CGF, S, Action);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-void CodeGenFunction::EmitOMPCancellationPointDirective(
- const OMPCancellationPointDirective &S) {
- CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getBeginLoc(),
- S.getCancelRegion());
-}
-
-void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) {
- const Expr *IfCond = nullptr;
- for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
- if (C->getNameModifier() == OMPD_unknown ||
- C->getNameModifier() == OMPD_cancel) {
- IfCond = C->getCondition();
- break;
- }
- }
- CGM.getOpenMPRuntime().emitCancelCall(*this, S.getBeginLoc(), IfCond,
- S.getCancelRegion());
-}
-
-CodeGenFunction::JumpDest
-CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) {
- if (Kind == OMPD_parallel || Kind == OMPD_task ||
- Kind == OMPD_target_parallel)
- return ReturnBlock;
- assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections ||
- Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for ||
- Kind == OMPD_distribute_parallel_for ||
- Kind == OMPD_target_parallel_for ||
- Kind == OMPD_teams_distribute_parallel_for ||
- Kind == OMPD_target_teams_distribute_parallel_for);
- return OMPCancelStack.getExitBlock();
-}
-
-void CodeGenFunction::EmitOMPUseDevicePtrClause(
- const OMPClause &NC, OMPPrivateScope &PrivateScope,
- const llvm::DenseMap<const ValueDecl *, Address> &CaptureDeviceAddrMap) {
- const auto &C = cast<OMPUseDevicePtrClause>(NC);
- auto OrigVarIt = C.varlist_begin();
- auto InitIt = C.inits().begin();
- for (const Expr *PvtVarIt : C.private_copies()) {
- const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*OrigVarIt)->getDecl());
- const auto *InitVD = cast<VarDecl>(cast<DeclRefExpr>(*InitIt)->getDecl());
- const auto *PvtVD = cast<VarDecl>(cast<DeclRefExpr>(PvtVarIt)->getDecl());
-
- // In order to identify the right initializer we need to match the
- // declaration used by the mapping logic. In some cases we may get
- // OMPCapturedExprDecl that refers to the original declaration.
- const ValueDecl *MatchingVD = OrigVD;
- if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(MatchingVD)) {
- // OMPCapturedExprDecl are used to privative fields of the current
- // structure.
- const auto *ME = cast<MemberExpr>(OED->getInit());
- assert(isa<CXXThisExpr>(ME->getBase()) &&
- "Base should be the current struct!");
- MatchingVD = ME->getMemberDecl();
- }
-
- // If we don't have information about the current list item, move on to
- // the next one.
- auto InitAddrIt = CaptureDeviceAddrMap.find(MatchingVD);
- if (InitAddrIt == CaptureDeviceAddrMap.end())
- continue;
-
- bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, OrigVD,
- InitAddrIt, InitVD,
- PvtVD]() {
- // Initialize the temporary initialization variable with the address we
- // get from the runtime library. We have to cast the source address
- // because it is always a void *. References are materialized in the
- // privatization scope, so the initialization here disregards the fact
- // the original variable is a reference.
- QualType AddrQTy =
- getContext().getPointerType(OrigVD->getType().getNonReferenceType());
- llvm::Type *AddrTy = ConvertTypeForMem(AddrQTy);
- Address InitAddr = Builder.CreateBitCast(InitAddrIt->second, AddrTy);
- setAddrOfLocalVar(InitVD, InitAddr);
-
- // Emit private declaration, it will be initialized by the value we
- // declaration we just added to the local declarations map.
- EmitDecl(*PvtVD);
-
- // The initialization variables reached its purpose in the emission
- // of the previous declaration, so we don't need it anymore.
- LocalDeclMap.erase(InitVD);
-
- // Return the address of the private variable.
- return GetAddrOfLocalVar(PvtVD);
- });
- assert(IsRegistered && "firstprivate var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
-
- ++OrigVarIt;
- ++InitIt;
- }
-}
-
-// Generate the instructions for '#pragma omp target data' directive.
-void CodeGenFunction::EmitOMPTargetDataDirective(
- const OMPTargetDataDirective &S) {
- CGOpenMPRuntime::TargetDataInfo Info(/*RequiresDevicePointerInfo=*/true);
-
- // Create a pre/post action to signal the privatization of the device pointer.
- // This action can be replaced by the OpenMP runtime code generation to
- // deactivate privatization.
- bool PrivatizeDevicePointers = false;
- class DevicePointerPrivActionTy : public PrePostActionTy {
- bool &PrivatizeDevicePointers;
-
- public:
- explicit DevicePointerPrivActionTy(bool &PrivatizeDevicePointers)
- : PrePostActionTy(), PrivatizeDevicePointers(PrivatizeDevicePointers) {}
- void Enter(CodeGenFunction &CGF) override {
- PrivatizeDevicePointers = true;
- }
- };
- DevicePointerPrivActionTy PrivAction(PrivatizeDevicePointers);
-
- auto &&CodeGen = [&S, &Info, &PrivatizeDevicePointers](
- CodeGenFunction &CGF, PrePostActionTy &Action) {
- auto &&InnermostCodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
- };
-
- // Codegen that selects whether to generate the privatization code or not.
- auto &&PrivCodeGen = [&S, &Info, &PrivatizeDevicePointers,
- &InnermostCodeGen](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- RegionCodeGenTy RCG(InnermostCodeGen);
- PrivatizeDevicePointers = false;
-
- // Call the pre-action to change the status of PrivatizeDevicePointers if
- // needed.
- Action.Enter(CGF);
-
- if (PrivatizeDevicePointers) {
- OMPPrivateScope PrivateScope(CGF);
- // Emit all instances of the use_device_ptr clause.
- for (const auto *C : S.getClausesOfKind<OMPUseDevicePtrClause>())
- CGF.EmitOMPUseDevicePtrClause(*C, PrivateScope,
- Info.CaptureDeviceAddrMap);
- (void)PrivateScope.Privatize();
- RCG(CGF);
- } else {
- RCG(CGF);
- }
- };
-
- // Forward the provided action to the privatization codegen.
- RegionCodeGenTy PrivRCG(PrivCodeGen);
- PrivRCG.setAction(Action);
-
- // Notwithstanding the body of the region is emitted as inlined directive,
- // we don't use an inline scope as changes in the references inside the
- // region are expected to be visible outside, so we do not privative them.
- OMPLexicalScope Scope(CGF, S);
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_target_data,
- PrivRCG);
- };
-
- RegionCodeGenTy RCG(CodeGen);
-
- // If we don't have target devices, don't bother emitting the data mapping
- // code.
- if (CGM.getLangOpts().OMPTargetTriples.empty()) {
- RCG(*this);
- return;
- }
-
- // Check if we have any if clause associated with the directive.
- const Expr *IfCond = nullptr;
- if (const auto *C = S.getSingleClause<OMPIfClause>())
- IfCond = C->getCondition();
-
- // Check if we have any device clause associated with the directive.
- const Expr *Device = nullptr;
- if (const auto *C = S.getSingleClause<OMPDeviceClause>())
- Device = C->getDevice();
-
- // Set the action to signal privatization of device pointers.
- RCG.setAction(PrivAction);
-
- // Emit region code.
- CGM.getOpenMPRuntime().emitTargetDataCalls(*this, S, IfCond, Device, RCG,
- Info);
-}
-
-void CodeGenFunction::EmitOMPTargetEnterDataDirective(
- const OMPTargetEnterDataDirective &S) {
- // If we don't have target devices, don't bother emitting the data mapping
- // code.
- if (CGM.getLangOpts().OMPTargetTriples.empty())
- return;
-
- // Check if we have any if clause associated with the directive.
- const Expr *IfCond = nullptr;
- if (const auto *C = S.getSingleClause<OMPIfClause>())
- IfCond = C->getCondition();
-
- // Check if we have any device clause associated with the directive.
- const Expr *Device = nullptr;
- if (const auto *C = S.getSingleClause<OMPDeviceClause>())
- Device = C->getDevice();
-
- OMPLexicalScope Scope(*this, S, OMPD_task);
- CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
-}
-
-void CodeGenFunction::EmitOMPTargetExitDataDirective(
- const OMPTargetExitDataDirective &S) {
- // If we don't have target devices, don't bother emitting the data mapping
- // code.
- if (CGM.getLangOpts().OMPTargetTriples.empty())
- return;
-
- // Check if we have any if clause associated with the directive.
- const Expr *IfCond = nullptr;
- if (const auto *C = S.getSingleClause<OMPIfClause>())
- IfCond = C->getCondition();
-
- // Check if we have any device clause associated with the directive.
- const Expr *Device = nullptr;
- if (const auto *C = S.getSingleClause<OMPDeviceClause>())
- Device = C->getDevice();
-
- OMPLexicalScope Scope(*this, S, OMPD_task);
- CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
-}
-
-static void emitTargetParallelRegion(CodeGenFunction &CGF,
- const OMPTargetParallelDirective &S,
- PrePostActionTy &Action) {
- // Get the captured statement associated with the 'parallel' region.
- const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
- Action.Enter(CGF);
- auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- CGF.EmitOMPPrivateClause(S, PrivateScope);
- CGF.EmitOMPReductionClauseInit(S, PrivateScope);
- (void)PrivateScope.Privatize();
- if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
- CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
- // TODO: Add support for clauses.
- CGF.EmitStmt(CS->getCapturedStmt());
- CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
- };
- emitCommonOMPParallelDirective(CGF, S, OMPD_parallel, CodeGen,
- emitEmptyBoundParameters);
- emitPostUpdateForReductionClause(CGF, S,
- [](CodeGenFunction &) { return nullptr; });
-}
-
-void CodeGenFunction::EmitOMPTargetParallelDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetParallelDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetParallelRegion(CGF, S, Action);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetParallelDirective(
- const OMPTargetParallelDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetParallelRegion(CGF, S, Action);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-static void emitTargetParallelForRegion(CodeGenFunction &CGF,
- const OMPTargetParallelForDirective &S,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- // Emit directive as a combined directive that consists of two implicit
- // directives: 'parallel' with 'for' directive.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CodeGenFunction::OMPCancelStackRAII CancelRegion(
- CGF, OMPD_target_parallel_for, S.hasCancel());
- CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
- emitDispatchForLoopBounds);
- };
- emitCommonOMPParallelDirective(CGF, S, OMPD_for, CodeGen,
- emitEmptyBoundParameters);
-}
-
-void CodeGenFunction::EmitOMPTargetParallelForDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetParallelForDirective &S) {
- // Emit SPMD target parallel for region as a standalone region.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetParallelForRegion(CGF, S, Action);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetParallelForDirective(
- const OMPTargetParallelForDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetParallelForRegion(CGF, S, Action);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-static void
-emitTargetParallelForSimdRegion(CodeGenFunction &CGF,
- const OMPTargetParallelForSimdDirective &S,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- // Emit directive as a combined directive that consists of two implicit
- // directives: 'parallel' with 'for' directive.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- Action.Enter(CGF);
- CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
- emitDispatchForLoopBounds);
- };
- emitCommonOMPParallelDirective(CGF, S, OMPD_simd, CodeGen,
- emitEmptyBoundParameters);
-}
-
-void CodeGenFunction::EmitOMPTargetParallelForSimdDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetParallelForSimdDirective &S) {
- // Emit SPMD target parallel for region as a standalone region.
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetParallelForSimdRegion(CGF, S, Action);
- };
- llvm::Function *Fn;
- llvm::Constant *Addr;
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
- assert(Fn && Addr && "Target device function emission failed.");
-}
-
-void CodeGenFunction::EmitOMPTargetParallelForSimdDirective(
- const OMPTargetParallelForSimdDirective &S) {
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetParallelForSimdRegion(CGF, S, Action);
- };
- emitCommonOMPTargetDirective(*this, S, CodeGen);
-}
-
-/// Emit a helper variable and return corresponding lvalue.
-static void mapParam(CodeGenFunction &CGF, const DeclRefExpr *Helper,
- const ImplicitParamDecl *PVD,
- CodeGenFunction::OMPPrivateScope &Privates) {
- const auto *VDecl = cast<VarDecl>(Helper->getDecl());
- Privates.addPrivate(VDecl,
- [&CGF, PVD]() { return CGF.GetAddrOfLocalVar(PVD); });
-}
-
-void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
- assert(isOpenMPTaskLoopDirective(S.getDirectiveKind()));
- // Emit outlined function for task construct.
- const CapturedStmt *CS = S.getCapturedStmt(OMPD_taskloop);
- Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
- QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
- const Expr *IfCond = nullptr;
- for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
- if (C->getNameModifier() == OMPD_unknown ||
- C->getNameModifier() == OMPD_taskloop) {
- IfCond = C->getCondition();
- break;
- }
- }
-
- OMPTaskDataTy Data;
- // Check if taskloop must be emitted without taskgroup.
- Data.Nogroup = S.getSingleClause<OMPNogroupClause>();
- // TODO: Check if we should emit tied or untied task.
- Data.Tied = true;
- // Set scheduling for taskloop
- if (const auto* Clause = S.getSingleClause<OMPGrainsizeClause>()) {
- // grainsize clause
- Data.Schedule.setInt(/*IntVal=*/false);
- Data.Schedule.setPointer(EmitScalarExpr(Clause->getGrainsize()));
- } else if (const auto* Clause = S.getSingleClause<OMPNumTasksClause>()) {
- // num_tasks clause
- Data.Schedule.setInt(/*IntVal=*/true);
- Data.Schedule.setPointer(EmitScalarExpr(Clause->getNumTasks()));
- }
-
- auto &&BodyGen = [CS, &S](CodeGenFunction &CGF, PrePostActionTy &) {
- // if (PreCond) {
- // for (IV in 0..LastIteration) BODY;
- // <Final counter/linear vars updates>;
- // }
- //
-
- // Emit: if (PreCond) - begin.
- // If the condition constant folds and can be elided, avoid emitting the
- // whole loop.
- bool CondConstant;
- llvm::BasicBlock *ContBlock = nullptr;
- OMPLoopScope PreInitScope(CGF, S);
- if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
- if (!CondConstant)
- return;
- } else {
- llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("taskloop.if.then");
- ContBlock = CGF.createBasicBlock("taskloop.if.end");
- emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
- CGF.getProfileCount(&S));
- CGF.EmitBlock(ThenBlock);
- CGF.incrementProfileCounter(&S);
- }
-
- if (isOpenMPSimdDirective(S.getDirectiveKind()))
- CGF.EmitOMPSimdInit(S);
-
- OMPPrivateScope LoopScope(CGF);
- // Emit helper vars inits.
- enum { LowerBound = 5, UpperBound, Stride, LastIter };
- auto *I = CS->getCapturedDecl()->param_begin();
- auto *LBP = std::next(I, LowerBound);
- auto *UBP = std::next(I, UpperBound);
- auto *STP = std::next(I, Stride);
- auto *LIP = std::next(I, LastIter);
- mapParam(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()), *LBP,
- LoopScope);
- mapParam(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()), *UBP,
- LoopScope);
- mapParam(CGF, cast<DeclRefExpr>(S.getStrideVariable()), *STP, LoopScope);
- mapParam(CGF, cast<DeclRefExpr>(S.getIsLastIterVariable()), *LIP,
- LoopScope);
- CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
- bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
- (void)LoopScope.Privatize();
- // Emit the loop iteration variable.
- const Expr *IVExpr = S.getIterationVariable();
- const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
- CGF.EmitVarDecl(*IVDecl);
- CGF.EmitIgnoredExpr(S.getInit());
-
- // Emit the iterations count variable.
- // If it is not a variable, Sema decided to calculate iterations count on
- // each iteration (e.g., it is foldable into a constant).
- if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
- CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
- // Emit calculation of the iterations count.
- CGF.EmitIgnoredExpr(S.getCalcLastIteration());
- }
-
- CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
- S.getInc(),
- [&S](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, JumpDest());
- CGF.EmitStopPoint(&S);
- },
- [](CodeGenFunction &) {});
- // Emit: if (PreCond) - end.
- if (ContBlock) {
- CGF.EmitBranch(ContBlock);
- CGF.EmitBlock(ContBlock, true);
- }
- // Emit final copy of the lastprivate variables if IsLastIter != 0.
- if (HasLastprivateClause) {
- CGF.EmitOMPLastprivateClauseFinal(
- S, isOpenMPSimdDirective(S.getDirectiveKind()),
- CGF.Builder.CreateIsNotNull(CGF.EmitLoadOfScalar(
- CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
- (*LIP)->getType(), S.getBeginLoc())));
- }
- };
- auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
- IfCond](CodeGenFunction &CGF, llvm::Value *OutlinedFn,
- const OMPTaskDataTy &Data) {
- auto &&CodeGen = [&S, OutlinedFn, SharedsTy, CapturedStruct, IfCond,
- &Data](CodeGenFunction &CGF, PrePostActionTy &) {
- OMPLoopScope PreInitScope(CGF, S);
- CGF.CGM.getOpenMPRuntime().emitTaskLoopCall(CGF, S.getBeginLoc(), S,
- OutlinedFn, SharedsTy,
- CapturedStruct, IfCond, Data);
- };
- CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop,
- CodeGen);
- };
- if (Data.Nogroup) {
- EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen, Data);
- } else {
- CGM.getOpenMPRuntime().emitTaskgroupRegion(
- *this,
- [&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
- Action.Enter(CGF);
- CGF.EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen,
- Data);
- },
- S.getBeginLoc());
- }
-}
-
-void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) {
- EmitOMPTaskLoopBasedDirective(S);
-}
-
-void CodeGenFunction::EmitOMPTaskLoopSimdDirective(
- const OMPTaskLoopSimdDirective &S) {
- EmitOMPTaskLoopBasedDirective(S);
-}
-
-// Generate the instructions for '#pragma omp target update' directive.
-void CodeGenFunction::EmitOMPTargetUpdateDirective(
- const OMPTargetUpdateDirective &S) {
- // If we don't have target devices, don't bother emitting the data mapping
- // code.
- if (CGM.getLangOpts().OMPTargetTriples.empty())
- return;
-
- // Check if we have any if clause associated with the directive.
- const Expr *IfCond = nullptr;
- if (const auto *C = S.getSingleClause<OMPIfClause>())
- IfCond = C->getCondition();
-
- // Check if we have any device clause associated with the directive.
- const Expr *Device = nullptr;
- if (const auto *C = S.getSingleClause<OMPDeviceClause>())
- Device = C->getDevice();
-
- OMPLexicalScope Scope(*this, S, OMPD_task);
- CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
-}
-
-void CodeGenFunction::EmitSimpleOMPExecutableDirective(
- const OMPExecutableDirective &D) {
- if (!D.hasAssociatedStmt() || !D.getAssociatedStmt())
- return;
- auto &&CodeGen = [&D](CodeGenFunction &CGF, PrePostActionTy &Action) {
- if (isOpenMPSimdDirective(D.getDirectiveKind())) {
- emitOMPSimdRegion(CGF, cast<OMPLoopDirective>(D), Action);
- } else {
- OMPPrivateScope LoopGlobals(CGF);
- if (const auto *LD = dyn_cast<OMPLoopDirective>(&D)) {
- for (const Expr *E : LD->counters()) {
- const auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
- if (!VD->hasLocalStorage() && !CGF.LocalDeclMap.count(VD)) {
- LValue GlobLVal = CGF.EmitLValue(E);
- LoopGlobals.addPrivate(
- VD, [&GlobLVal]() { return GlobLVal.getAddress(); });
- }
- if (isa<OMPCapturedExprDecl>(VD)) {
- // Emit only those that were not explicitly referenced in clauses.
- if (!CGF.LocalDeclMap.count(VD))
- CGF.EmitVarDecl(*VD);
- }
- }
- for (const auto *C : D.getClausesOfKind<OMPOrderedClause>()) {
- if (!C->getNumForLoops())
- continue;
- for (unsigned I = LD->getCollapsedNumber(),
- E = C->getLoopNumIterations().size();
- I < E; ++I) {
- if (const auto *VD = dyn_cast<OMPCapturedExprDecl>(
- cast<DeclRefExpr>(C->getLoopCounter(I))->getDecl())) {
- // Emit only those that were not explicitly referenced in clauses.
- if (!CGF.LocalDeclMap.count(VD))
- CGF.EmitVarDecl(*VD);
- }
- }
- }
- }
- LoopGlobals.Privatize();
- CGF.EmitStmt(D.getInnermostCapturedStmt()->getCapturedStmt());
- }
- };
- OMPSimdLexicalScope Scope(*this, D);
- CGM.getOpenMPRuntime().emitInlinedDirective(
- *this,
- isOpenMPSimdDirective(D.getDirectiveKind()) ? OMPD_simd
- : D.getDirectiveKind(),
- CodeGen);
-}
-
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGVTT.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGVTT.cpp
deleted file mode 100644
index fbd8146702a..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGVTT.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-//===--- CGVTT.cpp - Emit LLVM Code for C++ VTTs --------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of VTTs (vtable tables).
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenModule.h"
-#include "CGCXXABI.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/VTTBuilder.h"
-using namespace clang;
-using namespace CodeGen;
-
-static llvm::GlobalVariable *
-GetAddrOfVTTVTable(CodeGenVTables &CGVT, CodeGenModule &CGM,
- const CXXRecordDecl *MostDerivedClass,
- const VTTVTable &VTable,
- llvm::GlobalVariable::LinkageTypes Linkage,
- VTableLayout::AddressPointsMapTy &AddressPoints) {
- if (VTable.getBase() == MostDerivedClass) {
- assert(VTable.getBaseOffset().isZero() &&
- "Most derived class vtable must have a zero offset!");
- // This is a regular vtable.
- return CGM.getCXXABI().getAddrOfVTable(MostDerivedClass, CharUnits());
- }
-
- return CGVT.GenerateConstructionVTable(MostDerivedClass,
- VTable.getBaseSubobject(),
- VTable.isVirtual(),
- Linkage,
- AddressPoints);
-}
-
-void
-CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
- llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD) {
- VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/true);
-
- llvm::Type *Int8PtrTy = CGM.Int8PtrTy, *Int32Ty = CGM.Int32Ty;
- llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
-
- SmallVector<llvm::GlobalVariable *, 8> VTables;
- SmallVector<VTableAddressPointsMapTy, 8> VTableAddressPoints;
- for (const VTTVTable *i = Builder.getVTTVTables().begin(),
- *e = Builder.getVTTVTables().end(); i != e; ++i) {
- VTableAddressPoints.push_back(VTableAddressPointsMapTy());
- VTables.push_back(GetAddrOfVTTVTable(*this, CGM, RD, *i, Linkage,
- VTableAddressPoints.back()));
- }
-
- SmallVector<llvm::Constant *, 8> VTTComponents;
- for (const VTTComponent *i = Builder.getVTTComponents().begin(),
- *e = Builder.getVTTComponents().end(); i != e; ++i) {
- const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex];
- llvm::GlobalVariable *VTable = VTables[i->VTableIndex];
- VTableLayout::AddressPointLocation AddressPoint;
- if (VTTVT.getBase() == RD) {
- // Just get the address point for the regular vtable.
- AddressPoint =
- getItaniumVTableContext().getVTableLayout(RD).getAddressPoint(
- i->VTableBase);
- } else {
- AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
- assert(AddressPoint.AddressPointIndex != 0 &&
- "Did not find ctor vtable address point!");
- }
-
- llvm::Value *Idxs[] = {
- llvm::ConstantInt::get(Int32Ty, 0),
- llvm::ConstantInt::get(Int32Ty, AddressPoint.VTableIndex),
- llvm::ConstantInt::get(Int32Ty, AddressPoint.AddressPointIndex),
- };
-
- llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr(
- VTable->getValueType(), VTable, Idxs, /*InBounds=*/true,
- /*InRangeIndex=*/1);
-
- Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
-
- VTTComponents.push_back(Init);
- }
-
- llvm::Constant *Init = llvm::ConstantArray::get(ArrayType, VTTComponents);
-
- VTT->setInitializer(Init);
-
- // Set the correct linkage.
- VTT->setLinkage(Linkage);
-
- if (CGM.supportsCOMDAT() && VTT->isWeakForLinker())
- VTT->setComdat(CGM.getModule().getOrInsertComdat(VTT->getName()));
-
- // Set the right visibility.
- CGM.setGVProperties(VTT, RD);
-}
-
-llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
- assert(RD->getNumVBases() && "Only classes with virtual bases need a VTT");
-
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- cast<ItaniumMangleContext>(CGM.getCXXABI().getMangleContext())
- .mangleCXXVTT(RD, Out);
- StringRef Name = OutName.str();
-
- // This will also defer the definition of the VTT.
- (void) CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
-
- VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
-
- llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size());
- unsigned Align = CGM.getDataLayout().getABITypeAlignment(CGM.Int8PtrTy);
-
- llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name, ArrayType, llvm::GlobalValue::ExternalLinkage, Align);
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- return GV;
-}
-
-uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
- BaseSubobject Base) {
- BaseSubobjectPairTy ClassSubobjectPair(RD, Base);
-
- SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair);
- if (I != SubVTTIndicies.end())
- return I->second;
-
- VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
-
- for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
- Builder.getSubVTTIndicies().begin(),
- E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
- // Insert all indices.
- BaseSubobjectPairTy ClassSubobjectPair(RD, I->first);
-
- SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second));
- }
-
- I = SubVTTIndicies.find(ClassSubobjectPair);
- assert(I != SubVTTIndicies.end() && "Did not find index!");
-
- return I->second;
-}
-
-uint64_t
-CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
- BaseSubobject Base) {
- SecondaryVirtualPointerIndicesMapTy::iterator I =
- SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
-
- if (I != SecondaryVirtualPointerIndices.end())
- return I->second;
-
- VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
-
- // Insert all secondary vpointer indices.
- for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
- Builder.getSecondaryVirtualPointerIndices().begin(),
- E = Builder.getSecondaryVirtualPointerIndices().end(); I != E; ++I) {
- std::pair<const CXXRecordDecl *, BaseSubobject> Pair =
- std::make_pair(RD, I->first);
-
- SecondaryVirtualPointerIndices.insert(std::make_pair(Pair, I->second));
- }
-
- I = SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
- assert(I != SecondaryVirtualPointerIndices.end() && "Did not find index!");
-
- return I->second;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGVTables.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGVTables.cpp
deleted file mode 100644
index bfb089ff908..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGVTables.cpp
+++ /dev/null
@@ -1,1068 +0,0 @@
-//===--- CGVTables.cpp - Emit LLVM Code for C++ vtables -------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of virtual tables.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "clang/AST/CXXInheritance.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include <algorithm>
-#include <cstdio>
-
-using namespace clang;
-using namespace CodeGen;
-
-CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
- : CGM(CGM), VTContext(CGM.getContext().getVTableContext()) {}
-
-llvm::Constant *CodeGenModule::GetAddrOfThunk(StringRef Name, llvm::Type *FnTy,
- GlobalDecl GD) {
- return GetOrCreateLLVMFunction(Name, FnTy, GD, /*ForVTable=*/true,
- /*DontDefer=*/true, /*IsThunk=*/true);
-}
-
-static void setThunkProperties(CodeGenModule &CGM, const ThunkInfo &Thunk,
- llvm::Function *ThunkFn, bool ForVTable,
- GlobalDecl GD) {
- CGM.setFunctionLinkage(GD, ThunkFn);
- CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD,
- !Thunk.Return.isEmpty());
-
- // Set the right visibility.
- CGM.setGVProperties(ThunkFn, GD);
-
- if (!CGM.getCXXABI().exportThunk()) {
- ThunkFn->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
- ThunkFn->setDSOLocal(true);
- }
-
- if (CGM.supportsCOMDAT() && ThunkFn->isWeakForLinker())
- ThunkFn->setComdat(CGM.getModule().getOrInsertComdat(ThunkFn->getName()));
-}
-
-#ifndef NDEBUG
-static bool similar(const ABIArgInfo &infoL, CanQualType typeL,
- const ABIArgInfo &infoR, CanQualType typeR) {
- return (infoL.getKind() == infoR.getKind() &&
- (typeL == typeR ||
- (isa<PointerType>(typeL) && isa<PointerType>(typeR)) ||
- (isa<ReferenceType>(typeL) && isa<ReferenceType>(typeR))));
-}
-#endif
-
-static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
- QualType ResultType, RValue RV,
- const ThunkInfo &Thunk) {
- // Emit the return adjustment.
- bool NullCheckValue = !ResultType->isReferenceType();
-
- llvm::BasicBlock *AdjustNull = nullptr;
- llvm::BasicBlock *AdjustNotNull = nullptr;
- llvm::BasicBlock *AdjustEnd = nullptr;
-
- llvm::Value *ReturnValue = RV.getScalarVal();
-
- if (NullCheckValue) {
- AdjustNull = CGF.createBasicBlock("adjust.null");
- AdjustNotNull = CGF.createBasicBlock("adjust.notnull");
- AdjustEnd = CGF.createBasicBlock("adjust.end");
-
- llvm::Value *IsNull = CGF.Builder.CreateIsNull(ReturnValue);
- CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
- CGF.EmitBlock(AdjustNotNull);
- }
-
- auto ClassDecl = ResultType->getPointeeType()->getAsCXXRecordDecl();
- auto ClassAlign = CGF.CGM.getClassPointerAlignment(ClassDecl);
- ReturnValue = CGF.CGM.getCXXABI().performReturnAdjustment(CGF,
- Address(ReturnValue, ClassAlign),
- Thunk.Return);
-
- if (NullCheckValue) {
- CGF.Builder.CreateBr(AdjustEnd);
- CGF.EmitBlock(AdjustNull);
- CGF.Builder.CreateBr(AdjustEnd);
- CGF.EmitBlock(AdjustEnd);
-
- llvm::PHINode *PHI = CGF.Builder.CreatePHI(ReturnValue->getType(), 2);
- PHI->addIncoming(ReturnValue, AdjustNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
- AdjustNull);
- ReturnValue = PHI;
- }
-
- return RValue::get(ReturnValue);
-}
-
-/// This function clones a function's DISubprogram node and enters it into
-/// a value map with the intent that the map can be utilized by the cloner
-/// to short-circuit Metadata node mapping.
-/// Furthermore, the function resolves any DILocalVariable nodes referenced
-/// by dbg.value intrinsics so they can be properly mapped during cloning.
-static void resolveTopLevelMetadata(llvm::Function *Fn,
- llvm::ValueToValueMapTy &VMap) {
- // Clone the DISubprogram node and put it into the Value map.
- auto *DIS = Fn->getSubprogram();
- if (!DIS)
- return;
- auto *NewDIS = DIS->replaceWithDistinct(DIS->clone());
- VMap.MD()[DIS].reset(NewDIS);
-
- // Find all llvm.dbg.declare intrinsics and resolve the DILocalVariable nodes
- // they are referencing.
- for (auto &BB : Fn->getBasicBlockList()) {
- for (auto &I : BB) {
- if (auto *DII = dyn_cast<llvm::DbgVariableIntrinsic>(&I)) {
- auto *DILocal = DII->getVariable();
- if (!DILocal->isResolved())
- DILocal->resolve();
- }
- }
- }
-}
-
-// This function does roughly the same thing as GenerateThunk, but in a
-// very different way, so that va_start and va_end work correctly.
-// FIXME: This function assumes "this" is the first non-sret LLVM argument of
-// a function, and that there is an alloca built in the entry block
-// for all accesses to "this".
-// FIXME: This function assumes there is only one "ret" statement per function.
-// FIXME: Cloning isn't correct in the presence of indirect goto!
-// FIXME: This implementation of thunks bloats codesize by duplicating the
-// function definition. There are alternatives:
-// 1. Add some sort of stub support to LLVM for cases where we can
-// do a this adjustment, then a sibcall.
-// 2. We could transform the definition to take a va_list instead of an
-// actual variable argument list, then have the thunks (including a
-// no-op thunk for the regular definition) call va_start/va_end.
-// There's a bit of per-call overhead for this solution, but it's
-// better for codesize if the definition is long.
-llvm::Function *
-CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
- const CGFunctionInfo &FnInfo,
- GlobalDecl GD, const ThunkInfo &Thunk) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType = FPT->getReturnType();
-
- // Get the original function
- assert(FnInfo.isVariadic());
- llvm::Type *Ty = CGM.getTypes().GetFunctionType(FnInfo);
- llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
- llvm::Function *BaseFn = cast<llvm::Function>(Callee);
-
- // Clone to thunk.
- llvm::ValueToValueMapTy VMap;
-
- // We are cloning a function while some Metadata nodes are still unresolved.
- // Ensure that the value mapper does not encounter any of them.
- resolveTopLevelMetadata(BaseFn, VMap);
- llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap);
- Fn->replaceAllUsesWith(NewFn);
- NewFn->takeName(Fn);
- Fn->eraseFromParent();
- Fn = NewFn;
-
- // "Initialize" CGF (minimally).
- CurFn = Fn;
-
- // Get the "this" value
- llvm::Function::arg_iterator AI = Fn->arg_begin();
- if (CGM.ReturnTypeUsesSRet(FnInfo))
- ++AI;
-
- // Find the first store of "this", which will be to the alloca associated
- // with "this".
- Address ThisPtr(&*AI, CGM.getClassPointerAlignment(MD->getParent()));
- llvm::BasicBlock *EntryBB = &Fn->front();
- llvm::BasicBlock::iterator ThisStore =
- std::find_if(EntryBB->begin(), EntryBB->end(), [&](llvm::Instruction &I) {
- return isa<llvm::StoreInst>(I) &&
- I.getOperand(0) == ThisPtr.getPointer();
- });
- assert(ThisStore != EntryBB->end() &&
- "Store of this should be in entry block?");
- // Adjust "this", if necessary.
- Builder.SetInsertPoint(&*ThisStore);
- llvm::Value *AdjustedThisPtr =
- CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This);
- ThisStore->setOperand(0, AdjustedThisPtr);
-
- if (!Thunk.Return.isEmpty()) {
- // Fix up the returned value, if necessary.
- for (llvm::BasicBlock &BB : *Fn) {
- llvm::Instruction *T = BB.getTerminator();
- if (isa<llvm::ReturnInst>(T)) {
- RValue RV = RValue::get(T->getOperand(0));
- T->eraseFromParent();
- Builder.SetInsertPoint(&BB);
- RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk);
- Builder.CreateRet(RV.getScalarVal());
- break;
- }
- }
- }
-
- return Fn;
-}
-
-void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
- const CGFunctionInfo &FnInfo,
- bool IsUnprototyped) {
- assert(!CurGD.getDecl() && "CurGD was already set!");
- CurGD = GD;
- CurFuncIsThunk = true;
-
- // Build FunctionArgs.
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- QualType ThisType = MD->getThisType();
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType;
- if (IsUnprototyped)
- ResultType = CGM.getContext().VoidTy;
- else if (CGM.getCXXABI().HasThisReturn(GD))
- ResultType = ThisType;
- else if (CGM.getCXXABI().hasMostDerivedReturn(GD))
- ResultType = CGM.getContext().VoidPtrTy;
- else
- ResultType = FPT->getReturnType();
- FunctionArgList FunctionArgs;
-
- // Create the implicit 'this' parameter declaration.
- CGM.getCXXABI().buildThisParam(*this, FunctionArgs);
-
- // Add the rest of the parameters, if we have a prototype to work with.
- if (!IsUnprototyped) {
- FunctionArgs.append(MD->param_begin(), MD->param_end());
-
- if (isa<CXXDestructorDecl>(MD))
- CGM.getCXXABI().addImplicitStructorParams(*this, ResultType,
- FunctionArgs);
- }
-
- // Start defining the function.
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
- StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
- MD->getLocation());
- // Create a scope with an artificial location for the body of this function.
- auto AL = ApplyDebugLocation::CreateArtificial(*this);
-
- // Since we didn't pass a GlobalDecl to StartFunction, do this ourselves.
- CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
- CXXThisValue = CXXABIThisValue;
- CurCodeDecl = MD;
- CurFuncDecl = MD;
-}
-
-void CodeGenFunction::FinishThunk() {
- // Clear these to restore the invariants expected by
- // StartFunction/FinishFunction.
- CurCodeDecl = nullptr;
- CurFuncDecl = nullptr;
-
- FinishFunction();
-}
-
-void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Constant *CalleePtr,
- const ThunkInfo *Thunk,
- bool IsUnprototyped) {
- assert(isa<CXXMethodDecl>(CurGD.getDecl()) &&
- "Please use a new CGF for this thunk");
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(CurGD.getDecl());
-
- // Adjust the 'this' pointer if necessary
- llvm::Value *AdjustedThisPtr =
- Thunk ? CGM.getCXXABI().performThisAdjustment(
- *this, LoadCXXThisAddress(), Thunk->This)
- : LoadCXXThis();
-
- if (CurFnInfo->usesInAlloca() || IsUnprototyped) {
- // We don't handle return adjusting thunks, because they require us to call
- // the copy constructor. For now, fall through and pretend the return
- // adjustment was empty so we don't crash.
- if (Thunk && !Thunk->Return.isEmpty()) {
- if (IsUnprototyped)
- CGM.ErrorUnsupported(
- MD, "return-adjusting thunk with incomplete parameter type");
- else
- CGM.ErrorUnsupported(
- MD, "non-trivial argument copy for return-adjusting thunk");
- }
- EmitMustTailThunk(CurGD, AdjustedThisPtr, CalleePtr);
- return;
- }
-
- // Start building CallArgs.
- CallArgList CallArgs;
- QualType ThisType = MD->getThisType();
- CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
-
- if (isa<CXXDestructorDecl>(MD))
- CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, CurGD, CallArgs);
-
-#ifndef NDEBUG
- unsigned PrefixArgs = CallArgs.size() - 1;
-#endif
- // Add the rest of the arguments.
- for (const ParmVarDecl *PD : MD->parameters())
- EmitDelegateCallArg(CallArgs, PD, SourceLocation());
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-
-#ifndef NDEBUG
- const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall(
- CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1, MD), PrefixArgs);
- assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() &&
- CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() &&
- CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention());
- assert(isa<CXXDestructorDecl>(MD) || // ignore dtor return types
- similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(),
- CurFnInfo->getReturnInfo(), CurFnInfo->getReturnType()));
- assert(CallFnInfo.arg_size() == CurFnInfo->arg_size());
- for (unsigned i = 0, e = CurFnInfo->arg_size(); i != e; ++i)
- assert(similar(CallFnInfo.arg_begin()[i].info,
- CallFnInfo.arg_begin()[i].type,
- CurFnInfo->arg_begin()[i].info,
- CurFnInfo->arg_begin()[i].type));
-#endif
-
- // Determine whether we have a return value slot to use.
- QualType ResultType = CGM.getCXXABI().HasThisReturn(CurGD)
- ? ThisType
- : CGM.getCXXABI().hasMostDerivedReturn(CurGD)
- ? CGM.getContext().VoidPtrTy
- : FPT->getReturnType();
- ReturnValueSlot Slot;
- if (!ResultType->isVoidType() &&
- CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect)
- Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
-
- // Now emit our call.
- llvm::Instruction *CallOrInvoke;
- CGCallee Callee = CGCallee::forDirect(CalleePtr, CurGD);
- RValue RV = EmitCall(*CurFnInfo, Callee, Slot, CallArgs, &CallOrInvoke);
-
- // Consider return adjustment if we have ThunkInfo.
- if (Thunk && !Thunk->Return.isEmpty())
- RV = PerformReturnAdjustment(*this, ResultType, RV, *Thunk);
- else if (llvm::CallInst* Call = dyn_cast<llvm::CallInst>(CallOrInvoke))
- Call->setTailCallKind(llvm::CallInst::TCK_Tail);
-
- // Emit return.
- if (!ResultType->isVoidType() && Slot.isNull())
- CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType);
-
- // Disable the final ARC autorelease.
- AutoreleaseResult = false;
-
- FinishThunk();
-}
-
-void CodeGenFunction::EmitMustTailThunk(GlobalDecl GD,
- llvm::Value *AdjustedThisPtr,
- llvm::Value *CalleePtr) {
- // Emitting a musttail call thunk doesn't use any of the CGCall.cpp machinery
- // to translate AST arguments into LLVM IR arguments. For thunks, we know
- // that the caller prototype more or less matches the callee prototype with
- // the exception of 'this'.
- SmallVector<llvm::Value *, 8> Args;
- for (llvm::Argument &A : CurFn->args())
- Args.push_back(&A);
-
- // Set the adjusted 'this' pointer.
- const ABIArgInfo &ThisAI = CurFnInfo->arg_begin()->info;
- if (ThisAI.isDirect()) {
- const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
- int ThisArgNo = RetAI.isIndirect() && !RetAI.isSRetAfterThis() ? 1 : 0;
- llvm::Type *ThisType = Args[ThisArgNo]->getType();
- if (ThisType != AdjustedThisPtr->getType())
- AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisType);
- Args[ThisArgNo] = AdjustedThisPtr;
- } else {
- assert(ThisAI.isInAlloca() && "this is passed directly or inalloca");
- Address ThisAddr = GetAddrOfLocalVar(CXXABIThisDecl);
- llvm::Type *ThisType = ThisAddr.getElementType();
- if (ThisType != AdjustedThisPtr->getType())
- AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisType);
- Builder.CreateStore(AdjustedThisPtr, ThisAddr);
- }
-
- // Emit the musttail call manually. Even if the prologue pushed cleanups, we
- // don't actually want to run them.
- llvm::CallInst *Call = Builder.CreateCall(CalleePtr, Args);
- Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
-
- // Apply the standard set of call attributes.
- unsigned CallingConv;
- llvm::AttributeList Attrs;
- CGM.ConstructAttributeList(CalleePtr->getName(), *CurFnInfo, GD, Attrs,
- CallingConv, /*AttrOnCallSite=*/true);
- Call->setAttributes(Attrs);
- Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
-
- if (Call->getType()->isVoidTy())
- Builder.CreateRetVoid();
- else
- Builder.CreateRet(Call);
-
- // Finish the function to maintain CodeGenFunction invariants.
- // FIXME: Don't emit unreachable code.
- EmitBlock(createBasicBlock());
- FinishFunction();
-}
-
-void CodeGenFunction::generateThunk(llvm::Function *Fn,
- const CGFunctionInfo &FnInfo, GlobalDecl GD,
- const ThunkInfo &Thunk,
- bool IsUnprototyped) {
- StartThunk(Fn, GD, FnInfo, IsUnprototyped);
- // Create a scope with an artificial location for the body of this function.
- auto AL = ApplyDebugLocation::CreateArtificial(*this);
-
- // Get our callee. Use a placeholder type if this method is unprototyped so
- // that CodeGenModule doesn't try to set attributes.
- llvm::Type *Ty;
- if (IsUnprototyped)
- Ty = llvm::StructType::get(getLLVMContext());
- else
- Ty = CGM.getTypes().GetFunctionType(FnInfo);
-
- llvm::Constant *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
-
- // Fix up the function type for an unprototyped musttail call.
- if (IsUnprototyped)
- Callee = llvm::ConstantExpr::getBitCast(Callee, Fn->getType());
-
- // Make the call and return the result.
- EmitCallAndReturnForThunk(Callee, &Thunk, IsUnprototyped);
-}
-
-static bool shouldEmitVTableThunk(CodeGenModule &CGM, const CXXMethodDecl *MD,
- bool IsUnprototyped, bool ForVTable) {
- // Always emit thunks in the MS C++ ABI. We cannot rely on other TUs to
- // provide thunks for us.
- if (CGM.getTarget().getCXXABI().isMicrosoft())
- return true;
-
- // In the Itanium C++ ABI, vtable thunks are provided by TUs that provide
- // definitions of the main method. Therefore, emitting thunks with the vtable
- // is purely an optimization. Emit the thunk if optimizations are enabled and
- // all of the parameter types are complete.
- if (ForVTable)
- return CGM.getCodeGenOpts().OptimizationLevel && !IsUnprototyped;
-
- // Always emit thunks along with the method definition.
- return true;
-}
-
-llvm::Constant *CodeGenVTables::maybeEmitThunk(GlobalDecl GD,
- const ThunkInfo &TI,
- bool ForVTable) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // First, get a declaration. Compute the mangled name. Don't worry about
- // getting the function prototype right, since we may only need this
- // declaration to fill in a vtable slot.
- SmallString<256> Name;
- MangleContext &MCtx = CGM.getCXXABI().getMangleContext();
- llvm::raw_svector_ostream Out(Name);
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD))
- MCtx.mangleCXXDtorThunk(DD, GD.getDtorType(), TI.This, Out);
- else
- MCtx.mangleThunk(MD, TI, Out);
- llvm::Type *ThunkVTableTy = CGM.getTypes().GetFunctionTypeForVTable(GD);
- llvm::Constant *Thunk = CGM.GetAddrOfThunk(Name, ThunkVTableTy, GD);
-
- // If we don't need to emit a definition, return this declaration as is.
- bool IsUnprototyped = !CGM.getTypes().isFuncTypeConvertible(
- MD->getType()->castAs<FunctionType>());
- if (!shouldEmitVTableThunk(CGM, MD, IsUnprototyped, ForVTable))
- return Thunk;
-
- // Arrange a function prototype appropriate for a function definition. In some
- // cases in the MS ABI, we may need to build an unprototyped musttail thunk.
- const CGFunctionInfo &FnInfo =
- IsUnprototyped ? CGM.getTypes().arrangeUnprototypedMustTailThunk(MD)
- : CGM.getTypes().arrangeGlobalDeclaration(GD);
- llvm::FunctionType *ThunkFnTy = CGM.getTypes().GetFunctionType(FnInfo);
-
- // If the type of the underlying GlobalValue is wrong, we'll have to replace
- // it. It should be a declaration.
- llvm::Function *ThunkFn = cast<llvm::Function>(Thunk->stripPointerCasts());
- if (ThunkFn->getFunctionType() != ThunkFnTy) {
- llvm::GlobalValue *OldThunkFn = ThunkFn;
-
- assert(OldThunkFn->isDeclaration() && "Shouldn't replace non-declaration");
-
- // Remove the name from the old thunk function and get a new thunk.
- OldThunkFn->setName(StringRef());
- ThunkFn = llvm::Function::Create(ThunkFnTy, llvm::Function::ExternalLinkage,
- Name.str(), &CGM.getModule());
- CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
-
- // If needed, replace the old thunk with a bitcast.
- if (!OldThunkFn->use_empty()) {
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(ThunkFn, OldThunkFn->getType());
- OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl);
- }
-
- // Remove the old thunk.
- OldThunkFn->eraseFromParent();
- }
-
- bool ABIHasKeyFunctions = CGM.getTarget().getCXXABI().hasKeyFunctions();
- bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions;
-
- if (!ThunkFn->isDeclaration()) {
- if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) {
- // There is already a thunk emitted for this function, do nothing.
- return ThunkFn;
- }
-
- setThunkProperties(CGM, TI, ThunkFn, ForVTable, GD);
- return ThunkFn;
- }
-
- // If this will be unprototyped, add the "thunk" attribute so that LLVM knows
- // that the return type is meaningless. These thunks can be used to call
- // functions with differing return types, and the caller is required to cast
- // the prototype appropriately to extract the correct value.
- if (IsUnprototyped)
- ThunkFn->addFnAttr("thunk");
-
- CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn);
-
- if (!IsUnprototyped && ThunkFn->isVarArg()) {
- // Varargs thunks are special; we can't just generate a call because
- // we can't copy the varargs. Our implementation is rather
- // expensive/sucky at the moment, so don't generate the thunk unless
- // we have to.
- // FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly.
- if (UseAvailableExternallyLinkage)
- return ThunkFn;
- ThunkFn = CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD,
- TI);
- } else {
- // Normal thunk body generation.
- CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, TI, IsUnprototyped);
- }
-
- setThunkProperties(CGM, TI, ThunkFn, ForVTable, GD);
- return ThunkFn;
-}
-
-void CodeGenVTables::EmitThunks(GlobalDecl GD) {
- const CXXMethodDecl *MD =
- cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl();
-
- // We don't need to generate thunks for the base destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
- return;
-
- const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector =
- VTContext->getThunkInfo(GD);
-
- if (!ThunkInfoVector)
- return;
-
- for (const ThunkInfo& Thunk : *ThunkInfoVector)
- maybeEmitThunk(GD, Thunk, /*ForVTable=*/false);
-}
-
-void CodeGenVTables::addVTableComponent(
- ConstantArrayBuilder &builder, const VTableLayout &layout,
- unsigned idx, llvm::Constant *rtti, unsigned &nextVTableThunkIndex) {
- auto &component = layout.vtable_components()[idx];
-
- auto addOffsetConstant = [&](CharUnits offset) {
- builder.add(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()),
- CGM.Int8PtrTy));
- };
-
- switch (component.getKind()) {
- case VTableComponent::CK_VCallOffset:
- return addOffsetConstant(component.getVCallOffset());
-
- case VTableComponent::CK_VBaseOffset:
- return addOffsetConstant(component.getVBaseOffset());
-
- case VTableComponent::CK_OffsetToTop:
- return addOffsetConstant(component.getOffsetToTop());
-
- case VTableComponent::CK_RTTI:
- return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy));
-
- case VTableComponent::CK_FunctionPointer:
- case VTableComponent::CK_CompleteDtorPointer:
- case VTableComponent::CK_DeletingDtorPointer: {
- GlobalDecl GD;
-
- // Get the right global decl.
- switch (component.getKind()) {
- default:
- llvm_unreachable("Unexpected vtable component kind");
- case VTableComponent::CK_FunctionPointer:
- GD = component.getFunctionDecl();
- break;
- case VTableComponent::CK_CompleteDtorPointer:
- GD = GlobalDecl(component.getDestructorDecl(), Dtor_Complete);
- break;
- case VTableComponent::CK_DeletingDtorPointer:
- GD = GlobalDecl(component.getDestructorDecl(), Dtor_Deleting);
- break;
- }
-
- if (CGM.getLangOpts().CUDA) {
- // Emit NULL for methods we can't codegen on this
- // side. Otherwise we'd end up with vtable with unresolved
- // references.
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- // OK on device side: functions w/ __device__ attribute
- // OK on host side: anything except __device__-only functions.
- bool CanEmitMethod =
- CGM.getLangOpts().CUDAIsDevice
- ? MD->hasAttr<CUDADeviceAttr>()
- : (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>());
- if (!CanEmitMethod)
- return builder.addNullPointer(CGM.Int8PtrTy);
- // Method is acceptable, continue processing as usual.
- }
-
- auto getSpecialVirtualFn = [&](StringRef name) {
- llvm::FunctionType *fnTy =
- llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
- llvm::Constant *fn = CGM.CreateRuntimeFunction(fnTy, name);
- if (auto f = dyn_cast<llvm::Function>(fn))
- f->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- return llvm::ConstantExpr::getBitCast(fn, CGM.Int8PtrTy);
- };
-
- llvm::Constant *fnPtr;
-
- // Pure virtual member functions.
- if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
- if (!PureVirtualFn)
- PureVirtualFn =
- getSpecialVirtualFn(CGM.getCXXABI().GetPureVirtualCallName());
- fnPtr = PureVirtualFn;
-
- // Deleted virtual member functions.
- } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) {
- if (!DeletedVirtualFn)
- DeletedVirtualFn =
- getSpecialVirtualFn(CGM.getCXXABI().GetDeletedVirtualCallName());
- fnPtr = DeletedVirtualFn;
-
- // Thunks.
- } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
- layout.vtable_thunks()[nextVTableThunkIndex].first == idx) {
- auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second;
-
- nextVTableThunkIndex++;
- fnPtr = maybeEmitThunk(GD, thunkInfo, /*ForVTable=*/true);
-
- // Otherwise we can use the method definition directly.
- } else {
- llvm::Type *fnTy = CGM.getTypes().GetFunctionTypeForVTable(GD);
- fnPtr = CGM.GetAddrOfFunction(GD, fnTy, /*ForVTable=*/true);
- }
-
- fnPtr = llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy);
- builder.add(fnPtr);
- return;
- }
-
- case VTableComponent::CK_UnusedFunctionPointer:
- return builder.addNullPointer(CGM.Int8PtrTy);
- }
-
- llvm_unreachable("Unexpected vtable component kind");
-}
-
-llvm::Type *CodeGenVTables::getVTableType(const VTableLayout &layout) {
- SmallVector<llvm::Type *, 4> tys;
- for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) {
- tys.push_back(llvm::ArrayType::get(CGM.Int8PtrTy, layout.getVTableSize(i)));
- }
-
- return llvm::StructType::get(CGM.getLLVMContext(), tys);
-}
-
-void CodeGenVTables::createVTableInitializer(ConstantStructBuilder &builder,
- const VTableLayout &layout,
- llvm::Constant *rtti) {
- unsigned nextVTableThunkIndex = 0;
- for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) {
- auto vtableElem = builder.beginArray(CGM.Int8PtrTy);
- size_t thisIndex = layout.getVTableOffset(i);
- size_t nextIndex = thisIndex + layout.getVTableSize(i);
- for (unsigned i = thisIndex; i != nextIndex; ++i) {
- addVTableComponent(vtableElem, layout, i, rtti, nextVTableThunkIndex);
- }
- vtableElem.finishAndAddTo(builder);
- }
-}
-
-llvm::GlobalVariable *
-CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
- const BaseSubobject &Base,
- bool BaseIsVirtual,
- llvm::GlobalVariable::LinkageTypes Linkage,
- VTableAddressPointsMapTy& AddressPoints) {
- if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
- DI->completeClassData(Base.getBase());
-
- std::unique_ptr<VTableLayout> VTLayout(
- getItaniumVTableContext().createConstructionVTableLayout(
- Base.getBase(), Base.getBaseOffset(), BaseIsVirtual, RD));
-
- // Add the address points.
- AddressPoints = VTLayout->getAddressPoints();
-
- // Get the mangled construction vtable name.
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- cast<ItaniumMangleContext>(CGM.getCXXABI().getMangleContext())
- .mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(),
- Base.getBase(), Out);
- StringRef Name = OutName.str();
-
- llvm::Type *VTType = getVTableType(*VTLayout);
-
- // Construction vtable symbols are not part of the Itanium ABI, so we cannot
- // guarantee that they actually will be available externally. Instead, when
- // emitting an available_externally VTT, we provide references to an internal
- // linkage construction vtable. The ABI only requires complete-object vtables
- // to be the same for all instances of a type, not construction vtables.
- if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
- Linkage = llvm::GlobalVariable::InternalLinkage;
-
- unsigned Align = CGM.getDataLayout().getABITypeAlignment(VTType);
-
- // Create the variable that will hold the construction vtable.
- llvm::GlobalVariable *VTable =
- CGM.CreateOrReplaceCXXRuntimeVariable(Name, VTType, Linkage, Align);
- CGM.setGVProperties(VTable, RD);
-
- // V-tables are always unnamed_addr.
- VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(
- CGM.getContext().getTagDeclType(Base.getBase()));
-
- // Create and set the initializer.
- ConstantInitBuilder builder(CGM);
- auto components = builder.beginStruct();
- createVTableInitializer(components, *VTLayout, RTTI);
- components.finishAndSetAsInitializer(VTable);
-
- CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get());
-
- return VTable;
-}
-
-static bool shouldEmitAvailableExternallyVTable(const CodeGenModule &CGM,
- const CXXRecordDecl *RD) {
- return CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- CGM.getCXXABI().canSpeculativelyEmitVTable(RD);
-}
-
-/// Compute the required linkage of the vtable for the given class.
-///
-/// Note that we only call this at the end of the translation unit.
-llvm::GlobalVariable::LinkageTypes
-CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
- if (!RD->isExternallyVisible())
- return llvm::GlobalVariable::InternalLinkage;
-
- // We're at the end of the translation unit, so the current key
- // function is fully correct.
- const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD);
- if (keyFunction && !RD->hasAttr<DLLImportAttr>()) {
- // If this class has a key function, use that to determine the
- // linkage of the vtable.
- const FunctionDecl *def = nullptr;
- if (keyFunction->hasBody(def))
- keyFunction = cast<CXXMethodDecl>(def);
-
- switch (keyFunction->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- assert((def || CodeGenOpts.OptimizationLevel > 0 ||
- CodeGenOpts.getDebugInfo() != codegenoptions::NoDebugInfo) &&
- "Shouldn't query vtable linkage without key function, "
- "optimizations, or debug info");
- if (!def && CodeGenOpts.OptimizationLevel > 0)
- return llvm::GlobalVariable::AvailableExternallyLinkage;
-
- if (keyFunction->isInlined())
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
-
- return llvm::GlobalVariable::ExternalLinkage;
-
- case TSK_ImplicitInstantiation:
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::WeakODRLinkage :
- llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDeclaration:
- llvm_unreachable("Should not have been asked to emit this");
- }
- }
-
- // -fapple-kext mode does not support weak linkage, so we must use
- // internal linkage.
- if (Context.getLangOpts().AppleKext)
- return llvm::Function::InternalLinkage;
-
- llvm::GlobalVariable::LinkageTypes DiscardableODRLinkage =
- llvm::GlobalValue::LinkOnceODRLinkage;
- llvm::GlobalVariable::LinkageTypes NonDiscardableODRLinkage =
- llvm::GlobalValue::WeakODRLinkage;
- if (RD->hasAttr<DLLExportAttr>()) {
- // Cannot discard exported vtables.
- DiscardableODRLinkage = NonDiscardableODRLinkage;
- } else if (RD->hasAttr<DLLImportAttr>()) {
- // Imported vtables are available externally.
- DiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage;
- NonDiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage;
- }
-
- switch (RD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- case TSK_ImplicitInstantiation:
- return DiscardableODRLinkage;
-
- case TSK_ExplicitInstantiationDeclaration:
- // Explicit instantiations in MSVC do not provide vtables, so we must emit
- // our own.
- if (getTarget().getCXXABI().isMicrosoft())
- return DiscardableODRLinkage;
- return shouldEmitAvailableExternallyVTable(*this, RD)
- ? llvm::GlobalVariable::AvailableExternallyLinkage
- : llvm::GlobalVariable::ExternalLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return NonDiscardableODRLinkage;
- }
-
- llvm_unreachable("Invalid TemplateSpecializationKind!");
-}
-
-/// This is a callback from Sema to tell us that a particular vtable is
-/// required to be emitted in this translation unit.
-///
-/// This is only called for vtables that _must_ be emitted (mainly due to key
-/// functions). For weak vtables, CodeGen tracks when they are needed and
-/// emits them as-needed.
-void CodeGenModule::EmitVTable(CXXRecordDecl *theClass) {
- VTables.GenerateClassData(theClass);
-}
-
-void
-CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
- if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
- DI->completeClassData(RD);
-
- if (RD->getNumVBases())
- CGM.getCXXABI().emitVirtualInheritanceTables(RD);
-
- CGM.getCXXABI().emitVTableDefinitions(*this, RD);
-}
-
-/// At this point in the translation unit, does it appear that can we
-/// rely on the vtable being defined elsewhere in the program?
-///
-/// The response is really only definitive when called at the end of
-/// the translation unit.
-///
-/// The only semantic restriction here is that the object file should
-/// not contain a vtable definition when that vtable is defined
-/// strongly elsewhere. Otherwise, we'd just like to avoid emitting
-/// vtables when unnecessary.
-bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
- assert(RD->isDynamicClass() && "Non-dynamic classes have no VTable.");
-
- // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't
- // emit them even if there is an explicit template instantiation.
- if (CGM.getTarget().getCXXABI().isMicrosoft())
- return false;
-
- // If we have an explicit instantiation declaration (and not a
- // definition), the vtable is defined elsewhere.
- TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
- if (TSK == TSK_ExplicitInstantiationDeclaration)
- return true;
-
- // Otherwise, if the class is an instantiated template, the
- // vtable must be defined here.
- if (TSK == TSK_ImplicitInstantiation ||
- TSK == TSK_ExplicitInstantiationDefinition)
- return false;
-
- // Otherwise, if the class doesn't have a key function (possibly
- // anymore), the vtable must be defined here.
- const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD);
- if (!keyFunction)
- return false;
-
- // Otherwise, if we don't have a definition of the key function, the
- // vtable must be defined somewhere else.
- return !keyFunction->hasBody();
-}
-
-/// Given that we're currently at the end of the translation unit, and
-/// we've emitted a reference to the vtable for this class, should
-/// we define that vtable?
-static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM,
- const CXXRecordDecl *RD) {
- // If vtable is internal then it has to be done.
- if (!CGM.getVTables().isVTableExternal(RD))
- return true;
-
- // If it's external then maybe we will need it as available_externally.
- return shouldEmitAvailableExternallyVTable(CGM, RD);
-}
-
-/// Given that at some point we emitted a reference to one or more
-/// vtables, and that we are now at the end of the translation unit,
-/// decide whether we should emit them.
-void CodeGenModule::EmitDeferredVTables() {
-#ifndef NDEBUG
- // Remember the size of DeferredVTables, because we're going to assume
- // that this entire operation doesn't modify it.
- size_t savedSize = DeferredVTables.size();
-#endif
-
- for (const CXXRecordDecl *RD : DeferredVTables)
- if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD))
- VTables.GenerateClassData(RD);
- else if (shouldOpportunisticallyEmitVTables())
- OpportunisticVTables.push_back(RD);
-
- assert(savedSize == DeferredVTables.size() &&
- "deferred extra vtables during vtable emission?");
- DeferredVTables.clear();
-}
-
-bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
- LinkageInfo LV = RD->getLinkageAndVisibility();
- if (!isExternallyVisible(LV.getLinkage()))
- return true;
-
- if (RD->hasAttr<LTOVisibilityPublicAttr>() || RD->hasAttr<UuidAttr>())
- return false;
-
- if (getTriple().isOSBinFormatCOFF()) {
- if (RD->hasAttr<DLLExportAttr>() || RD->hasAttr<DLLImportAttr>())
- return false;
- } else {
- if (LV.getVisibility() != HiddenVisibility)
- return false;
- }
-
- if (getCodeGenOpts().LTOVisibilityPublicStd) {
- const DeclContext *DC = RD;
- while (1) {
- auto *D = cast<Decl>(DC);
- DC = DC->getParent();
- if (isa<TranslationUnitDecl>(DC->getRedeclContext())) {
- if (auto *ND = dyn_cast<NamespaceDecl>(D))
- if (const IdentifierInfo *II = ND->getIdentifier())
- if (II->isStr("std") || II->isStr("stdext"))
- return false;
- break;
- }
- }
- }
-
- return true;
-}
-
-void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
- const VTableLayout &VTLayout) {
- if (!getCodeGenOpts().LTOUnit)
- return;
-
- CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
-
- typedef std::pair<const CXXRecordDecl *, unsigned> AddressPoint;
- std::vector<AddressPoint> AddressPoints;
- for (auto &&AP : VTLayout.getAddressPoints())
- AddressPoints.push_back(std::make_pair(
- AP.first.getBase(), VTLayout.getVTableOffset(AP.second.VTableIndex) +
- AP.second.AddressPointIndex));
-
- // Sort the address points for determinism.
- llvm::sort(AddressPoints, [this](const AddressPoint &AP1,
- const AddressPoint &AP2) {
- if (&AP1 == &AP2)
- return false;
-
- std::string S1;
- llvm::raw_string_ostream O1(S1);
- getCXXABI().getMangleContext().mangleTypeName(
- QualType(AP1.first->getTypeForDecl(), 0), O1);
- O1.flush();
-
- std::string S2;
- llvm::raw_string_ostream O2(S2);
- getCXXABI().getMangleContext().mangleTypeName(
- QualType(AP2.first->getTypeForDecl(), 0), O2);
- O2.flush();
-
- if (S1 < S2)
- return true;
- if (S1 != S2)
- return false;
-
- return AP1.second < AP2.second;
- });
-
- ArrayRef<VTableComponent> Comps = VTLayout.vtable_components();
- for (auto AP : AddressPoints) {
- // Create type metadata for the address point.
- AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first);
-
- // The class associated with each address point could also potentially be
- // used for indirect calls via a member function pointer, so we need to
- // annotate the address of each function pointer with the appropriate member
- // function pointer type.
- for (unsigned I = 0; I != Comps.size(); ++I) {
- if (Comps[I].getKind() != VTableComponent::CK_FunctionPointer)
- continue;
- llvm::Metadata *MD = CreateMetadataIdentifierForVirtualMemPtrType(
- Context.getMemberPointerType(
- Comps[I].getFunctionDecl()->getType(),
- Context.getRecordType(AP.first).getTypePtr()));
- VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD);
- }
- }
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGVTables.h b/gnu/llvm/tools/clang/lib/CodeGen/CGVTables.h
deleted file mode 100644
index 6377659e4cb..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGVTables.h
+++ /dev/null
@@ -1,132 +0,0 @@
-//===--- CGVTables.h - Emit LLVM Code for C++ vtables -----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of virtual tables.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGVTABLES_H
-#define LLVM_CLANG_LIB_CODEGEN_CGVTABLES_H
-
-#include "clang/AST/BaseSubobject.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/GlobalDecl.h"
-#include "clang/AST/VTableBuilder.h"
-#include "clang/Basic/ABI.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/GlobalVariable.h"
-
-namespace clang {
- class CXXRecordDecl;
-
-namespace CodeGen {
- class CodeGenModule;
- class ConstantArrayBuilder;
- class ConstantStructBuilder;
-
-class CodeGenVTables {
- CodeGenModule &CGM;
-
- VTableContextBase *VTContext;
-
- /// VTableAddressPointsMapTy - Address points for a single vtable.
- typedef VTableLayout::AddressPointsMapTy VTableAddressPointsMapTy;
-
- typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy;
- typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy;
-
- /// SubVTTIndicies - Contains indices into the various sub-VTTs.
- SubVTTIndiciesMapTy SubVTTIndicies;
-
- typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t>
- SecondaryVirtualPointerIndicesMapTy;
-
- /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer
- /// indices.
- SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
-
- /// Cache for the pure virtual member call function.
- llvm::Constant *PureVirtualFn = nullptr;
-
- /// Cache for the deleted virtual member call function.
- llvm::Constant *DeletedVirtualFn = nullptr;
-
- /// Get the address of a thunk and emit it if necessary.
- llvm::Constant *maybeEmitThunk(GlobalDecl GD,
- const ThunkInfo &ThunkAdjustments,
- bool ForVTable);
-
- void addVTableComponent(ConstantArrayBuilder &builder,
- const VTableLayout &layout, unsigned idx,
- llvm::Constant *rtti,
- unsigned &nextVTableThunkIndex);
-
-public:
- /// Add vtable components for the given vtable layout to the given
- /// global initializer.
- void createVTableInitializer(ConstantStructBuilder &builder,
- const VTableLayout &layout,
- llvm::Constant *rtti);
-
- CodeGenVTables(CodeGenModule &CGM);
-
- ItaniumVTableContext &getItaniumVTableContext() {
- return *cast<ItaniumVTableContext>(VTContext);
- }
-
- MicrosoftVTableContext &getMicrosoftVTableContext() {
- return *cast<MicrosoftVTableContext>(VTContext);
- }
-
- /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
- /// given record decl.
- uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base);
-
- /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the
- /// virtual pointer for the given subobject is located.
- uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
- BaseSubobject Base);
-
- /// GenerateConstructionVTable - Generate a construction vtable for the given
- /// base subobject.
- llvm::GlobalVariable *
- GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base,
- bool BaseIsVirtual,
- llvm::GlobalVariable::LinkageTypes Linkage,
- VTableAddressPointsMapTy& AddressPoints);
-
-
- /// GetAddrOfVTT - Get the address of the VTT for the given record decl.
- llvm::GlobalVariable *GetAddrOfVTT(const CXXRecordDecl *RD);
-
- /// EmitVTTDefinition - Emit the definition of the given vtable.
- void EmitVTTDefinition(llvm::GlobalVariable *VTT,
- llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD);
-
- /// EmitThunks - Emit the associated thunks for the given global decl.
- void EmitThunks(GlobalDecl GD);
-
- /// GenerateClassData - Generate all the class data required to be
- /// generated upon definition of a KeyFunction. This includes the
- /// vtable, the RTTI data structure (if RTTI is enabled) and the VTT
- /// (if the class has virtual bases).
- void GenerateClassData(const CXXRecordDecl *RD);
-
- bool isVTableExternal(const CXXRecordDecl *RD);
-
- /// Returns the type of a vtable with the given layout. Normally a struct of
- /// arrays of pointers, with one struct element for each vtable in the vtable
- /// group.
- llvm::Type *getVTableType(const VTableLayout &layout);
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGValue.h b/gnu/llvm/tools/clang/lib/CodeGen/CGValue.h
deleted file mode 100644
index da8a8efb840..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CGValue.h
+++ /dev/null
@@ -1,632 +0,0 @@
-//===-- CGValue.h - LLVM CodeGen wrappers for llvm::Value* ------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes implement wrappers around llvm::Value in order to
-// fully represent the range of values for C L- and R- values.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CGVALUE_H
-#define LLVM_CLANG_LIB_CODEGEN_CGVALUE_H
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
-#include "llvm/IR/Value.h"
-#include "llvm/IR/Type.h"
-#include "Address.h"
-#include "CodeGenTBAA.h"
-
-namespace llvm {
- class Constant;
- class MDNode;
-}
-
-namespace clang {
-namespace CodeGen {
- class AggValueSlot;
- struct CGBitFieldInfo;
-
-/// RValue - This trivial value class is used to represent the result of an
-/// expression that is evaluated. It can be one of three things: either a
-/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the
-/// address of an aggregate value in memory.
-class RValue {
- enum Flavor { Scalar, Complex, Aggregate };
-
- // The shift to make to an aggregate's alignment to make it look
- // like a pointer.
- enum { AggAlignShift = 4 };
-
- // Stores first value and flavor.
- llvm::PointerIntPair<llvm::Value *, 2, Flavor> V1;
- // Stores second value and volatility.
- llvm::PointerIntPair<llvm::Value *, 1, bool> V2;
-
-public:
- bool isScalar() const { return V1.getInt() == Scalar; }
- bool isComplex() const { return V1.getInt() == Complex; }
- bool isAggregate() const { return V1.getInt() == Aggregate; }
-
- bool isVolatileQualified() const { return V2.getInt(); }
-
- /// getScalarVal() - Return the Value* of this scalar value.
- llvm::Value *getScalarVal() const {
- assert(isScalar() && "Not a scalar!");
- return V1.getPointer();
- }
-
- /// getComplexVal - Return the real/imag components of this complex value.
- ///
- std::pair<llvm::Value *, llvm::Value *> getComplexVal() const {
- return std::make_pair(V1.getPointer(), V2.getPointer());
- }
-
- /// getAggregateAddr() - Return the Value* of the address of the aggregate.
- Address getAggregateAddress() const {
- assert(isAggregate() && "Not an aggregate!");
- auto align = reinterpret_cast<uintptr_t>(V2.getPointer()) >> AggAlignShift;
- return Address(V1.getPointer(), CharUnits::fromQuantity(align));
- }
- llvm::Value *getAggregatePointer() const {
- assert(isAggregate() && "Not an aggregate!");
- return V1.getPointer();
- }
-
- static RValue getIgnored() {
- // FIXME: should we make this a more explicit state?
- return get(nullptr);
- }
-
- static RValue get(llvm::Value *V) {
- RValue ER;
- ER.V1.setPointer(V);
- ER.V1.setInt(Scalar);
- ER.V2.setInt(false);
- return ER;
- }
- static RValue getComplex(llvm::Value *V1, llvm::Value *V2) {
- RValue ER;
- ER.V1.setPointer(V1);
- ER.V2.setPointer(V2);
- ER.V1.setInt(Complex);
- ER.V2.setInt(false);
- return ER;
- }
- static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) {
- return getComplex(C.first, C.second);
- }
- // FIXME: Aggregate rvalues need to retain information about whether they are
- // volatile or not. Remove default to find all places that probably get this
- // wrong.
- static RValue getAggregate(Address addr, bool isVolatile = false) {
- RValue ER;
- ER.V1.setPointer(addr.getPointer());
- ER.V1.setInt(Aggregate);
-
- auto align = static_cast<uintptr_t>(addr.getAlignment().getQuantity());
- ER.V2.setPointer(reinterpret_cast<llvm::Value*>(align << AggAlignShift));
- ER.V2.setInt(isVolatile);
- return ER;
- }
-};
-
-/// Does an ARC strong l-value have precise lifetime?
-enum ARCPreciseLifetime_t {
- ARCImpreciseLifetime, ARCPreciseLifetime
-};
-
-/// The source of the alignment of an l-value; an expression of
-/// confidence in the alignment actually matching the estimate.
-enum class AlignmentSource {
- /// The l-value was an access to a declared entity or something
- /// equivalently strong, like the address of an array allocated by a
- /// language runtime.
- Decl,
-
- /// The l-value was considered opaque, so the alignment was
- /// determined from a type, but that type was an explicitly-aligned
- /// typedef.
- AttributedType,
-
- /// The l-value was considered opaque, so the alignment was
- /// determined from a type.
- Type
-};
-
-/// Given that the base address has the given alignment source, what's
-/// our confidence in the alignment of the field?
-static inline AlignmentSource getFieldAlignmentSource(AlignmentSource Source) {
- // For now, we don't distinguish fields of opaque pointers from
- // top-level declarations, but maybe we should.
- return AlignmentSource::Decl;
-}
-
-class LValueBaseInfo {
- AlignmentSource AlignSource;
-
-public:
- explicit LValueBaseInfo(AlignmentSource Source = AlignmentSource::Type)
- : AlignSource(Source) {}
- AlignmentSource getAlignmentSource() const { return AlignSource; }
- void setAlignmentSource(AlignmentSource Source) { AlignSource = Source; }
-
- void mergeForCast(const LValueBaseInfo &Info) {
- setAlignmentSource(Info.getAlignmentSource());
- }
-};
-
-/// LValue - This represents an lvalue references. Because C/C++ allow
-/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
-/// bitrange.
-class LValue {
- enum {
- Simple, // This is a normal l-value, use getAddress().
- VectorElt, // This is a vector element l-value (V[i]), use getVector*
- BitField, // This is a bitfield l-value, use getBitfield*.
- ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
- GlobalReg // This is a register l-value, use getGlobalReg()
- } LVType;
-
- llvm::Value *V;
-
- union {
- // Index into a vector subscript: V[i]
- llvm::Value *VectorIdx;
-
- // ExtVector element subset: V.xyx
- llvm::Constant *VectorElts;
-
- // BitField start bit and size
- const CGBitFieldInfo *BitFieldInfo;
- };
-
- QualType Type;
-
- // 'const' is unused here
- Qualifiers Quals;
-
- // The alignment to use when accessing this lvalue. (For vector elements,
- // this is the alignment of the whole vector.)
- unsigned Alignment;
-
- // objective-c's ivar
- bool Ivar:1;
-
- // objective-c's ivar is an array
- bool ObjIsArray:1;
-
- // LValue is non-gc'able for any reason, including being a parameter or local
- // variable.
- bool NonGC: 1;
-
- // Lvalue is a global reference of an objective-c object
- bool GlobalObjCRef : 1;
-
- // Lvalue is a thread local reference
- bool ThreadLocalRef : 1;
-
- // Lvalue has ARC imprecise lifetime. We store this inverted to try
- // to make the default bitfield pattern all-zeroes.
- bool ImpreciseLifetime : 1;
-
- // This flag shows if a nontemporal load/stores should be used when accessing
- // this lvalue.
- bool Nontemporal : 1;
-
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
-
- Expr *BaseIvarExp;
-
-private:
- void Initialize(QualType Type, Qualifiers Quals, CharUnits Alignment,
- LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) {
- assert((!Alignment.isZero() || Type->isIncompleteType()) &&
- "initializing l-value with zero alignment!");
- this->Type = Type;
- this->Quals = Quals;
- const unsigned MaxAlign = 1U << 31;
- this->Alignment = Alignment.getQuantity() <= MaxAlign
- ? Alignment.getQuantity()
- : MaxAlign;
- assert(this->Alignment == Alignment.getQuantity() &&
- "Alignment exceeds allowed max!");
- this->BaseInfo = BaseInfo;
- this->TBAAInfo = TBAAInfo;
-
- // Initialize Objective-C flags.
- this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
- this->ImpreciseLifetime = false;
- this->Nontemporal = false;
- this->ThreadLocalRef = false;
- this->BaseIvarExp = nullptr;
- }
-
-public:
- bool isSimple() const { return LVType == Simple; }
- bool isVectorElt() const { return LVType == VectorElt; }
- bool isBitField() const { return LVType == BitField; }
- bool isExtVectorElt() const { return LVType == ExtVectorElt; }
- bool isGlobalReg() const { return LVType == GlobalReg; }
-
- bool isVolatileQualified() const { return Quals.hasVolatile(); }
- bool isRestrictQualified() const { return Quals.hasRestrict(); }
- unsigned getVRQualifiers() const {
- return Quals.getCVRQualifiers() & ~Qualifiers::Const;
- }
-
- QualType getType() const { return Type; }
-
- Qualifiers::ObjCLifetime getObjCLifetime() const {
- return Quals.getObjCLifetime();
- }
-
- bool isObjCIvar() const { return Ivar; }
- void setObjCIvar(bool Value) { Ivar = Value; }
-
- bool isObjCArray() const { return ObjIsArray; }
- void setObjCArray(bool Value) { ObjIsArray = Value; }
-
- bool isNonGC () const { return NonGC; }
- void setNonGC(bool Value) { NonGC = Value; }
-
- bool isGlobalObjCRef() const { return GlobalObjCRef; }
- void setGlobalObjCRef(bool Value) { GlobalObjCRef = Value; }
-
- bool isThreadLocalRef() const { return ThreadLocalRef; }
- void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;}
-
- ARCPreciseLifetime_t isARCPreciseLifetime() const {
- return ARCPreciseLifetime_t(!ImpreciseLifetime);
- }
- void setARCPreciseLifetime(ARCPreciseLifetime_t value) {
- ImpreciseLifetime = (value == ARCImpreciseLifetime);
- }
- bool isNontemporal() const { return Nontemporal; }
- void setNontemporal(bool Value) { Nontemporal = Value; }
-
- bool isObjCWeak() const {
- return Quals.getObjCGCAttr() == Qualifiers::Weak;
- }
- bool isObjCStrong() const {
- return Quals.getObjCGCAttr() == Qualifiers::Strong;
- }
-
- bool isVolatile() const {
- return Quals.hasVolatile();
- }
-
- Expr *getBaseIvarExp() const { return BaseIvarExp; }
- void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
-
- TBAAAccessInfo getTBAAInfo() const { return TBAAInfo; }
- void setTBAAInfo(TBAAAccessInfo Info) { TBAAInfo = Info; }
-
- const Qualifiers &getQuals() const { return Quals; }
- Qualifiers &getQuals() { return Quals; }
-
- LangAS getAddressSpace() const { return Quals.getAddressSpace(); }
-
- CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); }
- void setAlignment(CharUnits A) { Alignment = A.getQuantity(); }
-
- LValueBaseInfo getBaseInfo() const { return BaseInfo; }
- void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; }
-
- // simple lvalue
- llvm::Value *getPointer() const {
- assert(isSimple());
- return V;
- }
- Address getAddress() const { return Address(getPointer(), getAlignment()); }
- void setAddress(Address address) {
- assert(isSimple());
- V = address.getPointer();
- Alignment = address.getAlignment().getQuantity();
- }
-
- // vector elt lvalue
- Address getVectorAddress() const {
- return Address(getVectorPointer(), getAlignment());
- }
- llvm::Value *getVectorPointer() const { assert(isVectorElt()); return V; }
- llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; }
-
- // extended vector elements.
- Address getExtVectorAddress() const {
- return Address(getExtVectorPointer(), getAlignment());
- }
- llvm::Value *getExtVectorPointer() const {
- assert(isExtVectorElt());
- return V;
- }
- llvm::Constant *getExtVectorElts() const {
- assert(isExtVectorElt());
- return VectorElts;
- }
-
- // bitfield lvalue
- Address getBitFieldAddress() const {
- return Address(getBitFieldPointer(), getAlignment());
- }
- llvm::Value *getBitFieldPointer() const { assert(isBitField()); return V; }
- const CGBitFieldInfo &getBitFieldInfo() const {
- assert(isBitField());
- return *BitFieldInfo;
- }
-
- // global register lvalue
- llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; }
-
- static LValue MakeAddr(Address address, QualType type, ASTContext &Context,
- LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) {
- Qualifiers qs = type.getQualifiers();
- qs.setObjCGCAttr(Context.getObjCGCAttrKind(type));
-
- LValue R;
- R.LVType = Simple;
- assert(address.getPointer()->getType()->isPointerTy());
- R.V = address.getPointer();
- R.Initialize(type, qs, address.getAlignment(), BaseInfo, TBAAInfo);
- return R;
- }
-
- static LValue MakeVectorElt(Address vecAddress, llvm::Value *Idx,
- QualType type, LValueBaseInfo BaseInfo,
- TBAAAccessInfo TBAAInfo) {
- LValue R;
- R.LVType = VectorElt;
- R.V = vecAddress.getPointer();
- R.VectorIdx = Idx;
- R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
- BaseInfo, TBAAInfo);
- return R;
- }
-
- static LValue MakeExtVectorElt(Address vecAddress, llvm::Constant *Elts,
- QualType type, LValueBaseInfo BaseInfo,
- TBAAAccessInfo TBAAInfo) {
- LValue R;
- R.LVType = ExtVectorElt;
- R.V = vecAddress.getPointer();
- R.VectorElts = Elts;
- R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
- BaseInfo, TBAAInfo);
- return R;
- }
-
- /// Create a new object to represent a bit-field access.
- ///
- /// \param Addr - The base address of the bit-field sequence this
- /// bit-field refers to.
- /// \param Info - The information describing how to perform the bit-field
- /// access.
- static LValue MakeBitfield(Address Addr, const CGBitFieldInfo &Info,
- QualType type, LValueBaseInfo BaseInfo,
- TBAAAccessInfo TBAAInfo) {
- LValue R;
- R.LVType = BitField;
- R.V = Addr.getPointer();
- R.BitFieldInfo = &Info;
- R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), BaseInfo,
- TBAAInfo);
- return R;
- }
-
- static LValue MakeGlobalReg(Address Reg, QualType type) {
- LValue R;
- R.LVType = GlobalReg;
- R.V = Reg.getPointer();
- R.Initialize(type, type.getQualifiers(), Reg.getAlignment(),
- LValueBaseInfo(AlignmentSource::Decl), TBAAAccessInfo());
- return R;
- }
-
- RValue asAggregateRValue() const {
- return RValue::getAggregate(getAddress(), isVolatileQualified());
- }
-};
-
-/// An aggregate value slot.
-class AggValueSlot {
- /// The address.
- llvm::Value *Addr;
-
- // Qualifiers
- Qualifiers Quals;
-
- unsigned Alignment;
-
- /// DestructedFlag - This is set to true if some external code is
- /// responsible for setting up a destructor for the slot. Otherwise
- /// the code which constructs it should push the appropriate cleanup.
- bool DestructedFlag : 1;
-
- /// ObjCGCFlag - This is set to true if writing to the memory in the
- /// slot might require calling an appropriate Objective-C GC
- /// barrier. The exact interaction here is unnecessarily mysterious.
- bool ObjCGCFlag : 1;
-
- /// ZeroedFlag - This is set to true if the memory in the slot is
- /// known to be zero before the assignment into it. This means that
- /// zero fields don't need to be set.
- bool ZeroedFlag : 1;
-
- /// AliasedFlag - This is set to true if the slot might be aliased
- /// and it's not undefined behavior to access it through such an
- /// alias. Note that it's always undefined behavior to access a C++
- /// object that's under construction through an alias derived from
- /// outside the construction process.
- ///
- /// This flag controls whether calls that produce the aggregate
- /// value may be evaluated directly into the slot, or whether they
- /// must be evaluated into an unaliased temporary and then memcpy'ed
- /// over. Since it's invalid in general to memcpy a non-POD C++
- /// object, it's important that this flag never be set when
- /// evaluating an expression which constructs such an object.
- bool AliasedFlag : 1;
-
- /// This is set to true if the tail padding of this slot might overlap
- /// another object that may have already been initialized (and whose
- /// value must be preserved by this initialization). If so, we may only
- /// store up to the dsize of the type. Otherwise we can widen stores to
- /// the size of the type.
- bool OverlapFlag : 1;
-
- /// If is set to true, sanitizer checks are already generated for this address
- /// or not required. For instance, if this address represents an object
- /// created in 'new' expression, sanitizer checks for memory is made as a part
- /// of 'operator new' emission and object constructor should not generate
- /// them.
- bool SanitizerCheckedFlag : 1;
-
-public:
- enum IsAliased_t { IsNotAliased, IsAliased };
- enum IsDestructed_t { IsNotDestructed, IsDestructed };
- enum IsZeroed_t { IsNotZeroed, IsZeroed };
- enum Overlap_t { DoesNotOverlap, MayOverlap };
- enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
- enum IsSanitizerChecked_t { IsNotSanitizerChecked, IsSanitizerChecked };
-
- /// ignored - Returns an aggregate value slot indicating that the
- /// aggregate value is being ignored.
- static AggValueSlot ignored() {
- return forAddr(Address::invalid(), Qualifiers(), IsNotDestructed,
- DoesNotNeedGCBarriers, IsNotAliased, DoesNotOverlap);
- }
-
- /// forAddr - Make a slot for an aggregate value.
- ///
- /// \param quals - The qualifiers that dictate how the slot should
- /// be initialied. Only 'volatile' and the Objective-C lifetime
- /// qualifiers matter.
- ///
- /// \param isDestructed - true if something else is responsible
- /// for calling destructors on this object
- /// \param needsGC - true if the slot is potentially located
- /// somewhere that ObjC GC calls should be emitted for
- static AggValueSlot forAddr(Address addr,
- Qualifiers quals,
- IsDestructed_t isDestructed,
- NeedsGCBarriers_t needsGC,
- IsAliased_t isAliased,
- Overlap_t mayOverlap,
- IsZeroed_t isZeroed = IsNotZeroed,
- IsSanitizerChecked_t isChecked = IsNotSanitizerChecked) {
- AggValueSlot AV;
- if (addr.isValid()) {
- AV.Addr = addr.getPointer();
- AV.Alignment = addr.getAlignment().getQuantity();
- } else {
- AV.Addr = nullptr;
- AV.Alignment = 0;
- }
- AV.Quals = quals;
- AV.DestructedFlag = isDestructed;
- AV.ObjCGCFlag = needsGC;
- AV.ZeroedFlag = isZeroed;
- AV.AliasedFlag = isAliased;
- AV.OverlapFlag = mayOverlap;
- AV.SanitizerCheckedFlag = isChecked;
- return AV;
- }
-
- static AggValueSlot forLValue(const LValue &LV,
- IsDestructed_t isDestructed,
- NeedsGCBarriers_t needsGC,
- IsAliased_t isAliased,
- Overlap_t mayOverlap,
- IsZeroed_t isZeroed = IsNotZeroed,
- IsSanitizerChecked_t isChecked = IsNotSanitizerChecked) {
- return forAddr(LV.getAddress(), LV.getQuals(), isDestructed, needsGC,
- isAliased, mayOverlap, isZeroed, isChecked);
- }
-
- IsDestructed_t isExternallyDestructed() const {
- return IsDestructed_t(DestructedFlag);
- }
- void setExternallyDestructed(bool destructed = true) {
- DestructedFlag = destructed;
- }
-
- Qualifiers getQualifiers() const { return Quals; }
-
- bool isVolatile() const {
- return Quals.hasVolatile();
- }
-
- void setVolatile(bool flag) {
- if (flag)
- Quals.addVolatile();
- else
- Quals.removeVolatile();
- }
-
- Qualifiers::ObjCLifetime getObjCLifetime() const {
- return Quals.getObjCLifetime();
- }
-
- NeedsGCBarriers_t requiresGCollection() const {
- return NeedsGCBarriers_t(ObjCGCFlag);
- }
-
- llvm::Value *getPointer() const {
- return Addr;
- }
-
- Address getAddress() const {
- return Address(Addr, getAlignment());
- }
-
- bool isIgnored() const {
- return Addr == nullptr;
- }
-
- CharUnits getAlignment() const {
- return CharUnits::fromQuantity(Alignment);
- }
-
- IsAliased_t isPotentiallyAliased() const {
- return IsAliased_t(AliasedFlag);
- }
-
- Overlap_t mayOverlap() const {
- return Overlap_t(OverlapFlag);
- }
-
- bool isSanitizerChecked() const {
- return SanitizerCheckedFlag;
- }
-
- RValue asRValue() const {
- if (isIgnored()) {
- return RValue::getIgnored();
- } else {
- return RValue::getAggregate(getAddress(), isVolatile());
- }
- }
-
- void setZeroed(bool V = true) { ZeroedFlag = V; }
- IsZeroed_t isZeroed() const {
- return IsZeroed_t(ZeroedFlag);
- }
-
- /// Get the preferred size to use when storing a value to this slot. This
- /// is the type size unless that might overlap another object, in which
- /// case it's the dsize.
- CharUnits getPreferredSize(ASTContext &Ctx, QualType Type) const {
- return mayOverlap() ? Ctx.getTypeInfoDataSizeInChars(Type).first
- : Ctx.getTypeSizeInChars(Type);
- }
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CMakeLists.txt b/gnu/llvm/tools/clang/lib/CodeGen/CMakeLists.txt
deleted file mode 100644
index 29c6793c601..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CMakeLists.txt
+++ /dev/null
@@ -1,106 +0,0 @@
-set(LLVM_LINK_COMPONENTS
- Analysis
- BitReader
- BitWriter
- Core
- Coroutines
- Coverage
- IPO
- IRReader
- AggressiveInstCombine
- InstCombine
- Instrumentation
- LTO
- Linker
- MC
- ObjCARCOpts
- Object
- Passes
- ProfileData
- ScalarOpts
- Support
- Target
- TransformUtils
- )
-
-# In a standard Clang+LLVM build, we need to generate intrinsics before
-# building codegen. In a standalone build, LLVM is already built and we don't
-# need this dependency. Furthermore, LLVM doesn't export it so we can't have
-# this dependency.
-set(codegen_deps intrinsics_gen)
-if (CLANG_BUILT_STANDALONE)
- set(codegen_deps)
-endif()
-
-if (MSVC)
- set_source_files_properties(CodeGenModule.cpp PROPERTIES COMPILE_FLAGS /bigobj)
-endif()
-
-add_clang_library(clangCodeGen
- BackendUtil.cpp
- CGAtomic.cpp
- CGBlocks.cpp
- CGBuiltin.cpp
- CGCUDANV.cpp
- CGCUDARuntime.cpp
- CGCXX.cpp
- CGCXXABI.cpp
- CGCall.cpp
- CGClass.cpp
- CGCleanup.cpp
- CGCoroutine.cpp
- CGDebugInfo.cpp
- CGDecl.cpp
- CGDeclCXX.cpp
- CGException.cpp
- CGExpr.cpp
- CGExprAgg.cpp
- CGExprCXX.cpp
- CGExprComplex.cpp
- CGExprConstant.cpp
- CGExprScalar.cpp
- CGGPUBuiltin.cpp
- CGLoopInfo.cpp
- CGNonTrivialStruct.cpp
- CGObjC.cpp
- CGObjCGNU.cpp
- CGObjCMac.cpp
- CGObjCRuntime.cpp
- CGOpenCLRuntime.cpp
- CGOpenMPRuntime.cpp
- CGOpenMPRuntimeNVPTX.cpp
- CGRecordLayoutBuilder.cpp
- CGStmt.cpp
- CGStmtOpenMP.cpp
- CGVTT.cpp
- CGVTables.cpp
- CodeGenABITypes.cpp
- CodeGenAction.cpp
- CodeGenFunction.cpp
- CodeGenModule.cpp
- CodeGenPGO.cpp
- CodeGenTBAA.cpp
- CodeGenTypes.cpp
- ConstantInitBuilder.cpp
- CoverageMappingGen.cpp
- ItaniumCXXABI.cpp
- MacroPPCallbacks.cpp
- MicrosoftCXXABI.cpp
- ModuleBuilder.cpp
- ObjectFilePCHContainerOperations.cpp
- SanitizerMetadata.cpp
- SwiftCallingConv.cpp
- TargetInfo.cpp
- VarBypassDetector.cpp
-
- DEPENDS
- ${codegen_deps}
-
- LINK_LIBS
- clangAnalysis
- clangAST
- clangBasic
- clangFrontend
- clangLex
- clangSerialization
- )
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp
deleted file mode 100644
index 27f5d53ffe1..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-//==--- CodeGenABITypes.cpp - Convert Clang types to LLVM types for ABI ----==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// CodeGenABITypes is a simple interface for getting LLVM types for
-// the parameters and the return value of a function given the Clang
-// types.
-//
-// The class is implemented as a public wrapper around the private
-// CodeGenTypes class in lib/CodeGen.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CodeGen/CodeGenABITypes.h"
-#include "CGRecordLayout.h"
-#include "CodeGenModule.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/PreprocessorOptions.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-const CGFunctionInfo &
-CodeGen::arrangeObjCMessageSendSignature(CodeGenModule &CGM,
- const ObjCMethodDecl *MD,
- QualType receiverType) {
- return CGM.getTypes().arrangeObjCMessageSendSignature(MD, receiverType);
-}
-
-const CGFunctionInfo &
-CodeGen::arrangeFreeFunctionType(CodeGenModule &CGM,
- CanQual<FunctionProtoType> Ty,
- const FunctionDecl *FD) {
- return CGM.getTypes().arrangeFreeFunctionType(Ty, FD);
-}
-
-const CGFunctionInfo &
-CodeGen::arrangeFreeFunctionType(CodeGenModule &CGM,
- CanQual<FunctionNoProtoType> Ty) {
- return CGM.getTypes().arrangeFreeFunctionType(Ty);
-}
-
-const CGFunctionInfo &
-CodeGen::arrangeCXXMethodType(CodeGenModule &CGM,
- const CXXRecordDecl *RD,
- const FunctionProtoType *FTP,
- const CXXMethodDecl *MD) {
- return CGM.getTypes().arrangeCXXMethodType(RD, FTP, MD);
-}
-
-const CGFunctionInfo &
-CodeGen::arrangeFreeFunctionCall(CodeGenModule &CGM,
- CanQualType returnType,
- ArrayRef<CanQualType> argTypes,
- FunctionType::ExtInfo info,
- RequiredArgs args) {
- return CGM.getTypes().arrangeLLVMFunctionInfo(
- returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes,
- info, {}, args);
-}
-
-llvm::FunctionType *
-CodeGen::convertFreeFunctionType(CodeGenModule &CGM, const FunctionDecl *FD) {
- assert(FD != nullptr && "Expected a non-null function declaration!");
- llvm::Type *T = CGM.getTypes().ConvertFunctionType(FD->getType(), FD);
-
- if (auto FT = dyn_cast<llvm::FunctionType>(T))
- return FT;
-
- return nullptr;
-}
-
-llvm::Type *
-CodeGen::convertTypeForMemory(CodeGenModule &CGM, QualType T) {
- return CGM.getTypes().ConvertTypeForMem(T);
-}
-
-unsigned CodeGen::getLLVMFieldNumber(CodeGenModule &CGM,
- const RecordDecl *RD,
- const FieldDecl *FD) {
- return CGM.getTypes().getCGRecordLayout(RD).getLLVMFieldNo(FD);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp
deleted file mode 100644
index fd4506f2d19..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp
+++ /dev/null
@@ -1,1075 +0,0 @@
-//===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CodeGen/CodeGenAction.h"
-#include "CodeGenModule.h"
-#include "CoverageMappingGen.h"
-#include "MacroPPCallbacks.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclGroup.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/CodeGen/BackendUtil.h"
-#include "clang/CodeGen/ModuleBuilder.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/DiagnosticInfo.h"
-#include "llvm/IR/DiagnosticPrinter.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IRReader/IRReader.h"
-#include "llvm/Linker/Linker.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/Timer.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/YAMLTraits.h"
-#include "llvm/Transforms/IPO/Internalize.h"
-
-#include <memory>
-using namespace clang;
-using namespace llvm;
-
-namespace clang {
- class BackendConsumer;
- class ClangDiagnosticHandler final : public DiagnosticHandler {
- public:
- ClangDiagnosticHandler(const CodeGenOptions &CGOpts, BackendConsumer *BCon)
- : CodeGenOpts(CGOpts), BackendCon(BCon) {}
-
- bool handleDiagnostics(const DiagnosticInfo &DI) override;
-
- bool isAnalysisRemarkEnabled(StringRef PassName) const override {
- return (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
- CodeGenOpts.OptimizationRemarkAnalysisPattern->match(PassName));
- }
- bool isMissedOptRemarkEnabled(StringRef PassName) const override {
- return (CodeGenOpts.OptimizationRemarkMissedPattern &&
- CodeGenOpts.OptimizationRemarkMissedPattern->match(PassName));
- }
- bool isPassedOptRemarkEnabled(StringRef PassName) const override {
- return (CodeGenOpts.OptimizationRemarkPattern &&
- CodeGenOpts.OptimizationRemarkPattern->match(PassName));
- }
-
- bool isAnyRemarkEnabled() const override {
- return (CodeGenOpts.OptimizationRemarkAnalysisPattern ||
- CodeGenOpts.OptimizationRemarkMissedPattern ||
- CodeGenOpts.OptimizationRemarkPattern);
- }
-
- private:
- const CodeGenOptions &CodeGenOpts;
- BackendConsumer *BackendCon;
- };
-
- class BackendConsumer : public ASTConsumer {
- using LinkModule = CodeGenAction::LinkModule;
-
- virtual void anchor();
- DiagnosticsEngine &Diags;
- BackendAction Action;
- const HeaderSearchOptions &HeaderSearchOpts;
- const CodeGenOptions &CodeGenOpts;
- const TargetOptions &TargetOpts;
- const LangOptions &LangOpts;
- std::unique_ptr<raw_pwrite_stream> AsmOutStream;
- ASTContext *Context;
-
- Timer LLVMIRGeneration;
- unsigned LLVMIRGenerationRefCount;
-
- /// True if we've finished generating IR. This prevents us from generating
- /// additional LLVM IR after emitting output in HandleTranslationUnit. This
- /// can happen when Clang plugins trigger additional AST deserialization.
- bool IRGenFinished = false;
-
- std::unique_ptr<CodeGenerator> Gen;
-
- SmallVector<LinkModule, 4> LinkModules;
-
- // This is here so that the diagnostic printer knows the module a diagnostic
- // refers to.
- llvm::Module *CurLinkModule = nullptr;
-
- public:
- BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PPOpts,
- const CodeGenOptions &CodeGenOpts,
- const TargetOptions &TargetOpts,
- const LangOptions &LangOpts, bool TimePasses,
- const std::string &InFile,
- SmallVector<LinkModule, 4> LinkModules,
- std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C,
- CoverageSourceInfo *CoverageInfo = nullptr)
- : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
- CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
- AsmOutStream(std::move(OS)), Context(nullptr),
- LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
- LLVMIRGenerationRefCount(0),
- Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts,
- CodeGenOpts, C, CoverageInfo)),
- LinkModules(std::move(LinkModules)) {
- FrontendTimesIsEnabled = TimePasses;
- llvm::TimePassesIsEnabled = TimePasses;
- }
- llvm::Module *getModule() const { return Gen->GetModule(); }
- std::unique_ptr<llvm::Module> takeModule() {
- return std::unique_ptr<llvm::Module>(Gen->ReleaseModule());
- }
-
- CodeGenerator *getCodeGenerator() { return Gen.get(); }
-
- void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
- Gen->HandleCXXStaticMemberVarInstantiation(VD);
- }
-
- void Initialize(ASTContext &Ctx) override {
- assert(!Context && "initialized multiple times");
-
- Context = &Ctx;
-
- if (FrontendTimesIsEnabled)
- LLVMIRGeneration.startTimer();
-
- Gen->Initialize(Ctx);
-
- if (FrontendTimesIsEnabled)
- LLVMIRGeneration.stopTimer();
- }
-
- bool HandleTopLevelDecl(DeclGroupRef D) override {
- PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
- Context->getSourceManager(),
- "LLVM IR generation of declaration");
-
- // Recurse.
- if (FrontendTimesIsEnabled) {
- LLVMIRGenerationRefCount += 1;
- if (LLVMIRGenerationRefCount == 1)
- LLVMIRGeneration.startTimer();
- }
-
- Gen->HandleTopLevelDecl(D);
-
- if (FrontendTimesIsEnabled) {
- LLVMIRGenerationRefCount -= 1;
- if (LLVMIRGenerationRefCount == 0)
- LLVMIRGeneration.stopTimer();
- }
-
- return true;
- }
-
- void HandleInlineFunctionDefinition(FunctionDecl *D) override {
- PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
- Context->getSourceManager(),
- "LLVM IR generation of inline function");
- if (FrontendTimesIsEnabled)
- LLVMIRGeneration.startTimer();
-
- Gen->HandleInlineFunctionDefinition(D);
-
- if (FrontendTimesIsEnabled)
- LLVMIRGeneration.stopTimer();
- }
-
- void HandleInterestingDecl(DeclGroupRef D) override {
- // Ignore interesting decls from the AST reader after IRGen is finished.
- if (!IRGenFinished)
- HandleTopLevelDecl(D);
- }
-
- // Links each entry in LinkModules into our module. Returns true on error.
- bool LinkInModules() {
- for (auto &LM : LinkModules) {
- if (LM.PropagateAttrs)
- for (Function &F : *LM.Module)
- Gen->CGM().AddDefaultFnAttrs(F);
-
- CurLinkModule = LM.Module.get();
-
- bool Err;
- if (LM.Internalize) {
- Err = Linker::linkModules(
- *getModule(), std::move(LM.Module), LM.LinkFlags,
- [](llvm::Module &M, const llvm::StringSet<> &GVS) {
- internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
- return !GV.hasName() || (GVS.count(GV.getName()) == 0);
- });
- });
- } else {
- Err = Linker::linkModules(*getModule(), std::move(LM.Module),
- LM.LinkFlags);
- }
-
- if (Err)
- return true;
- }
- return false; // success
- }
-
- void HandleTranslationUnit(ASTContext &C) override {
- {
- PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
- if (FrontendTimesIsEnabled) {
- LLVMIRGenerationRefCount += 1;
- if (LLVMIRGenerationRefCount == 1)
- LLVMIRGeneration.startTimer();
- }
-
- Gen->HandleTranslationUnit(C);
-
- if (FrontendTimesIsEnabled) {
- LLVMIRGenerationRefCount -= 1;
- if (LLVMIRGenerationRefCount == 0)
- LLVMIRGeneration.stopTimer();
- }
-
- IRGenFinished = true;
- }
-
- // Silently ignore if we weren't initialized for some reason.
- if (!getModule())
- return;
-
- // Install an inline asm handler so that diagnostics get printed through
- // our diagnostics hooks.
- LLVMContext &Ctx = getModule()->getContext();
- LLVMContext::InlineAsmDiagHandlerTy OldHandler =
- Ctx.getInlineAsmDiagnosticHandler();
- void *OldContext = Ctx.getInlineAsmDiagnosticContext();
- Ctx.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, this);
-
- std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler =
- Ctx.getDiagnosticHandler();
- Ctx.setDiagnosticHandler(llvm::make_unique<ClangDiagnosticHandler>(
- CodeGenOpts, this));
- Ctx.setDiagnosticsHotnessRequested(CodeGenOpts.DiagnosticsWithHotness);
- if (CodeGenOpts.DiagnosticsHotnessThreshold != 0)
- Ctx.setDiagnosticsHotnessThreshold(
- CodeGenOpts.DiagnosticsHotnessThreshold);
-
- std::unique_ptr<llvm::ToolOutputFile> OptRecordFile;
- if (!CodeGenOpts.OptRecordFile.empty()) {
- std::error_code EC;
- OptRecordFile = llvm::make_unique<llvm::ToolOutputFile>(
- CodeGenOpts.OptRecordFile, EC, sys::fs::F_None);
- if (EC) {
- Diags.Report(diag::err_cannot_open_file) <<
- CodeGenOpts.OptRecordFile << EC.message();
- return;
- }
-
- Ctx.setDiagnosticsOutputFile(
- llvm::make_unique<yaml::Output>(OptRecordFile->os()));
-
- if (CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone)
- Ctx.setDiagnosticsHotnessRequested(true);
- }
-
- // Link each LinkModule into our module.
- if (LinkInModules())
- return;
-
- EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef());
-
- EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts,
- LangOpts, C.getTargetInfo().getDataLayout(),
- getModule(), Action, std::move(AsmOutStream));
-
- Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext);
-
- Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler));
-
- if (OptRecordFile)
- OptRecordFile->keep();
- }
-
- void HandleTagDeclDefinition(TagDecl *D) override {
- PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
- Context->getSourceManager(),
- "LLVM IR generation of declaration");
- Gen->HandleTagDeclDefinition(D);
- }
-
- void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
- Gen->HandleTagDeclRequiredDefinition(D);
- }
-
- void CompleteTentativeDefinition(VarDecl *D) override {
- Gen->CompleteTentativeDefinition(D);
- }
-
- void AssignInheritanceModel(CXXRecordDecl *RD) override {
- Gen->AssignInheritanceModel(RD);
- }
-
- void HandleVTable(CXXRecordDecl *RD) override {
- Gen->HandleVTable(RD);
- }
-
- static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
- unsigned LocCookie) {
- SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
- ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
- }
-
- /// Get the best possible source location to represent a diagnostic that
- /// may have associated debug info.
- const FullSourceLoc
- getBestLocationFromDebugLoc(const llvm::DiagnosticInfoWithLocationBase &D,
- bool &BadDebugInfo, StringRef &Filename,
- unsigned &Line, unsigned &Column) const;
-
- void InlineAsmDiagHandler2(const llvm::SMDiagnostic &,
- SourceLocation LocCookie);
-
- void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI);
- /// Specialized handler for InlineAsm diagnostic.
- /// \return True if the diagnostic has been successfully reported, false
- /// otherwise.
- bool InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D);
- /// Specialized handler for StackSize diagnostic.
- /// \return True if the diagnostic has been successfully reported, false
- /// otherwise.
- bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
- /// Specialized handler for unsupported backend feature diagnostic.
- void UnsupportedDiagHandler(const llvm::DiagnosticInfoUnsupported &D);
- /// Specialized handlers for optimization remarks.
- /// Note that these handlers only accept remarks and they always handle
- /// them.
- void EmitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &D,
- unsigned DiagID);
- void
- OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationBase &D);
- void OptimizationRemarkHandler(
- const llvm::OptimizationRemarkAnalysisFPCommute &D);
- void OptimizationRemarkHandler(
- const llvm::OptimizationRemarkAnalysisAliasing &D);
- void OptimizationFailureHandler(
- const llvm::DiagnosticInfoOptimizationFailure &D);
- };
-
- void BackendConsumer::anchor() {}
-}
-
-bool ClangDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) {
- BackendCon->DiagnosticHandlerImpl(DI);
- return true;
-}
-
-/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr
-/// buffer to be a valid FullSourceLoc.
-static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
- SourceManager &CSM) {
- // Get both the clang and llvm source managers. The location is relative to
- // a memory buffer that the LLVM Source Manager is handling, we need to add
- // a copy to the Clang source manager.
- const llvm::SourceMgr &LSM = *D.getSourceMgr();
-
- // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr
- // already owns its one and clang::SourceManager wants to own its one.
- const MemoryBuffer *LBuf =
- LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
-
- // Create the copy and transfer ownership to clang::SourceManager.
- // TODO: Avoid copying files into memory.
- std::unique_ptr<llvm::MemoryBuffer> CBuf =
- llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
- LBuf->getBufferIdentifier());
- // FIXME: Keep a file ID map instead of creating new IDs for each location.
- FileID FID = CSM.createFileID(std::move(CBuf));
-
- // Translate the offset into the file.
- unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
- SourceLocation NewLoc =
- CSM.getLocForStartOfFile(FID).getLocWithOffset(Offset);
- return FullSourceLoc(NewLoc, CSM);
-}
-
-
-/// InlineAsmDiagHandler2 - This function is invoked when the backend hits an
-/// error parsing inline asm. The SMDiagnostic indicates the error relative to
-/// the temporary memory buffer that the inline asm parser has set up.
-void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
- SourceLocation LocCookie) {
- // There are a couple of different kinds of errors we could get here. First,
- // we re-format the SMDiagnostic in terms of a clang diagnostic.
-
- // Strip "error: " off the start of the message string.
- StringRef Message = D.getMessage();
- if (Message.startswith("error: "))
- Message = Message.substr(7);
-
- // If the SMDiagnostic has an inline asm source location, translate it.
- FullSourceLoc Loc;
- if (D.getLoc() != SMLoc())
- Loc = ConvertBackendLocation(D, Context->getSourceManager());
-
- unsigned DiagID;
- switch (D.getKind()) {
- case llvm::SourceMgr::DK_Error:
- DiagID = diag::err_fe_inline_asm;
- break;
- case llvm::SourceMgr::DK_Warning:
- DiagID = diag::warn_fe_inline_asm;
- break;
- case llvm::SourceMgr::DK_Note:
- DiagID = diag::note_fe_inline_asm;
- break;
- case llvm::SourceMgr::DK_Remark:
- llvm_unreachable("remarks unexpected");
- }
- // If this problem has clang-level source location information, report the
- // issue in the source with a note showing the instantiated
- // code.
- if (LocCookie.isValid()) {
- Diags.Report(LocCookie, DiagID).AddString(Message);
-
- if (D.getLoc().isValid()) {
- DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here);
- // Convert the SMDiagnostic ranges into SourceRange and attach them
- // to the diagnostic.
- for (const std::pair<unsigned, unsigned> &Range : D.getRanges()) {
- unsigned Column = D.getColumnNo();
- B << SourceRange(Loc.getLocWithOffset(Range.first - Column),
- Loc.getLocWithOffset(Range.second - Column));
- }
- }
- return;
- }
-
- // Otherwise, report the backend issue as occurring in the generated .s file.
- // If Loc is invalid, we still need to report the issue, it just gets no
- // location info.
- Diags.Report(Loc, DiagID).AddString(Message);
-}
-
-#define ComputeDiagID(Severity, GroupName, DiagID) \
- do { \
- switch (Severity) { \
- case llvm::DS_Error: \
- DiagID = diag::err_fe_##GroupName; \
- break; \
- case llvm::DS_Warning: \
- DiagID = diag::warn_fe_##GroupName; \
- break; \
- case llvm::DS_Remark: \
- llvm_unreachable("'remark' severity not expected"); \
- break; \
- case llvm::DS_Note: \
- DiagID = diag::note_fe_##GroupName; \
- break; \
- } \
- } while (false)
-
-#define ComputeDiagRemarkID(Severity, GroupName, DiagID) \
- do { \
- switch (Severity) { \
- case llvm::DS_Error: \
- DiagID = diag::err_fe_##GroupName; \
- break; \
- case llvm::DS_Warning: \
- DiagID = diag::warn_fe_##GroupName; \
- break; \
- case llvm::DS_Remark: \
- DiagID = diag::remark_fe_##GroupName; \
- break; \
- case llvm::DS_Note: \
- DiagID = diag::note_fe_##GroupName; \
- break; \
- } \
- } while (false)
-
-bool
-BackendConsumer::InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D) {
- unsigned DiagID;
- ComputeDiagID(D.getSeverity(), inline_asm, DiagID);
- std::string Message = D.getMsgStr().str();
-
- // If this problem has clang-level source location information, report the
- // issue as being a problem in the source with a note showing the instantiated
- // code.
- SourceLocation LocCookie =
- SourceLocation::getFromRawEncoding(D.getLocCookie());
- if (LocCookie.isValid())
- Diags.Report(LocCookie, DiagID).AddString(Message);
- else {
- // Otherwise, report the backend diagnostic as occurring in the generated
- // .s file.
- // If Loc is invalid, we still need to report the diagnostic, it just gets
- // no location info.
- FullSourceLoc Loc;
- Diags.Report(Loc, DiagID).AddString(Message);
- }
- // We handled all the possible severities.
- return true;
-}
-
-bool
-BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) {
- if (D.getSeverity() != llvm::DS_Warning)
- // For now, the only support we have for StackSize diagnostic is warning.
- // We do not know how to format other severities.
- return false;
-
- if (const Decl *ND = Gen->GetDeclForMangledName(D.getFunction().getName())) {
- // FIXME: Shouldn't need to truncate to uint32_t
- Diags.Report(ND->getASTContext().getFullLoc(ND->getLocation()),
- diag::warn_fe_frame_larger_than)
- << static_cast<uint32_t>(D.getStackSize()) << Decl::castToDeclContext(ND);
- return true;
- }
-
- return false;
-}
-
-const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc(
- const llvm::DiagnosticInfoWithLocationBase &D, bool &BadDebugInfo,
- StringRef &Filename, unsigned &Line, unsigned &Column) const {
- SourceManager &SourceMgr = Context->getSourceManager();
- FileManager &FileMgr = SourceMgr.getFileManager();
- SourceLocation DILoc;
-
- if (D.isLocationAvailable()) {
- D.getLocation(Filename, Line, Column);
- if (Line > 0) {
- const FileEntry *FE = FileMgr.getFile(Filename);
- if (!FE)
- FE = FileMgr.getFile(D.getAbsolutePath());
- if (FE) {
- // If -gcolumn-info was not used, Column will be 0. This upsets the
- // source manager, so pass 1 if Column is not set.
- DILoc = SourceMgr.translateFileLineCol(FE, Line, Column ? Column : 1);
- }
- }
- BadDebugInfo = DILoc.isInvalid();
- }
-
- // If a location isn't available, try to approximate it using the associated
- // function definition. We use the definition's right brace to differentiate
- // from diagnostics that genuinely relate to the function itself.
- FullSourceLoc Loc(DILoc, SourceMgr);
- if (Loc.isInvalid())
- if (const Decl *FD = Gen->GetDeclForMangledName(D.getFunction().getName()))
- Loc = FD->getASTContext().getFullLoc(FD->getLocation());
-
- if (DILoc.isInvalid() && D.isLocationAvailable())
- // If we were not able to translate the file:line:col information
- // back to a SourceLocation, at least emit a note stating that
- // we could not translate this location. This can happen in the
- // case of #line directives.
- Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
- << Filename << Line << Column;
-
- return Loc;
-}
-
-void BackendConsumer::UnsupportedDiagHandler(
- const llvm::DiagnosticInfoUnsupported &D) {
- // We only support errors.
- assert(D.getSeverity() == llvm::DS_Error);
-
- StringRef Filename;
- unsigned Line, Column;
- bool BadDebugInfo = false;
- FullSourceLoc Loc =
- getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
-
- Diags.Report(Loc, diag::err_fe_backend_unsupported) << D.getMessage().str();
-
- if (BadDebugInfo)
- // If we were not able to translate the file:line:col information
- // back to a SourceLocation, at least emit a note stating that
- // we could not translate this location. This can happen in the
- // case of #line directives.
- Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
- << Filename << Line << Column;
-}
-
-void BackendConsumer::EmitOptimizationMessage(
- const llvm::DiagnosticInfoOptimizationBase &D, unsigned DiagID) {
- // We only support warnings and remarks.
- assert(D.getSeverity() == llvm::DS_Remark ||
- D.getSeverity() == llvm::DS_Warning);
-
- StringRef Filename;
- unsigned Line, Column;
- bool BadDebugInfo = false;
- FullSourceLoc Loc =
- getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
-
- std::string Msg;
- raw_string_ostream MsgStream(Msg);
- MsgStream << D.getMsg();
-
- if (D.getHotness())
- MsgStream << " (hotness: " << *D.getHotness() << ")";
-
- Diags.Report(Loc, DiagID)
- << AddFlagValue(D.getPassName())
- << MsgStream.str();
-
- if (BadDebugInfo)
- // If we were not able to translate the file:line:col information
- // back to a SourceLocation, at least emit a note stating that
- // we could not translate this location. This can happen in the
- // case of #line directives.
- Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
- << Filename << Line << Column;
-}
-
-void BackendConsumer::OptimizationRemarkHandler(
- const llvm::DiagnosticInfoOptimizationBase &D) {
- // Without hotness information, don't show noisy remarks.
- if (D.isVerbose() && !D.getHotness())
- return;
-
- if (D.isPassed()) {
- // Optimization remarks are active only if the -Rpass flag has a regular
- // expression that matches the name of the pass name in \p D.
- if (CodeGenOpts.OptimizationRemarkPattern &&
- CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName()))
- EmitOptimizationMessage(D, diag::remark_fe_backend_optimization_remark);
- } else if (D.isMissed()) {
- // Missed optimization remarks are active only if the -Rpass-missed
- // flag has a regular expression that matches the name of the pass
- // name in \p D.
- if (CodeGenOpts.OptimizationRemarkMissedPattern &&
- CodeGenOpts.OptimizationRemarkMissedPattern->match(D.getPassName()))
- EmitOptimizationMessage(
- D, diag::remark_fe_backend_optimization_remark_missed);
- } else {
- assert(D.isAnalysis() && "Unknown remark type");
-
- bool ShouldAlwaysPrint = false;
- if (auto *ORA = dyn_cast<llvm::OptimizationRemarkAnalysis>(&D))
- ShouldAlwaysPrint = ORA->shouldAlwaysPrint();
-
- if (ShouldAlwaysPrint ||
- (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
- CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName())))
- EmitOptimizationMessage(
- D, diag::remark_fe_backend_optimization_remark_analysis);
- }
-}
-
-void BackendConsumer::OptimizationRemarkHandler(
- const llvm::OptimizationRemarkAnalysisFPCommute &D) {
- // Optimization analysis remarks are active if the pass name is set to
- // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a
- // regular expression that matches the name of the pass name in \p D.
-
- if (D.shouldAlwaysPrint() ||
- (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
- CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName())))
- EmitOptimizationMessage(
- D, diag::remark_fe_backend_optimization_remark_analysis_fpcommute);
-}
-
-void BackendConsumer::OptimizationRemarkHandler(
- const llvm::OptimizationRemarkAnalysisAliasing &D) {
- // Optimization analysis remarks are active if the pass name is set to
- // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a
- // regular expression that matches the name of the pass name in \p D.
-
- if (D.shouldAlwaysPrint() ||
- (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
- CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName())))
- EmitOptimizationMessage(
- D, diag::remark_fe_backend_optimization_remark_analysis_aliasing);
-}
-
-void BackendConsumer::OptimizationFailureHandler(
- const llvm::DiagnosticInfoOptimizationFailure &D) {
- EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure);
-}
-
-/// This function is invoked when the backend needs
-/// to report something to the user.
-void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
- unsigned DiagID = diag::err_fe_inline_asm;
- llvm::DiagnosticSeverity Severity = DI.getSeverity();
- // Get the diagnostic ID based.
- switch (DI.getKind()) {
- case llvm::DK_InlineAsm:
- if (InlineAsmDiagHandler(cast<DiagnosticInfoInlineAsm>(DI)))
- return;
- ComputeDiagID(Severity, inline_asm, DiagID);
- break;
- case llvm::DK_StackSize:
- if (StackSizeDiagHandler(cast<DiagnosticInfoStackSize>(DI)))
- return;
- ComputeDiagID(Severity, backend_frame_larger_than, DiagID);
- break;
- case DK_Linker:
- assert(CurLinkModule);
- // FIXME: stop eating the warnings and notes.
- if (Severity != DS_Error)
- return;
- DiagID = diag::err_fe_cannot_link_module;
- break;
- case llvm::DK_OptimizationRemark:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<OptimizationRemark>(DI));
- return;
- case llvm::DK_OptimizationRemarkMissed:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<OptimizationRemarkMissed>(DI));
- return;
- case llvm::DK_OptimizationRemarkAnalysis:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<OptimizationRemarkAnalysis>(DI));
- return;
- case llvm::DK_OptimizationRemarkAnalysisFPCommute:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<OptimizationRemarkAnalysisFPCommute>(DI));
- return;
- case llvm::DK_OptimizationRemarkAnalysisAliasing:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<OptimizationRemarkAnalysisAliasing>(DI));
- return;
- case llvm::DK_MachineOptimizationRemark:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<MachineOptimizationRemark>(DI));
- return;
- case llvm::DK_MachineOptimizationRemarkMissed:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<MachineOptimizationRemarkMissed>(DI));
- return;
- case llvm::DK_MachineOptimizationRemarkAnalysis:
- // Optimization remarks are always handled completely by this
- // handler. There is no generic way of emitting them.
- OptimizationRemarkHandler(cast<MachineOptimizationRemarkAnalysis>(DI));
- return;
- case llvm::DK_OptimizationFailure:
- // Optimization failures are always handled completely by this
- // handler.
- OptimizationFailureHandler(cast<DiagnosticInfoOptimizationFailure>(DI));
- return;
- case llvm::DK_Unsupported:
- UnsupportedDiagHandler(cast<DiagnosticInfoUnsupported>(DI));
- return;
- default:
- // Plugin IDs are not bound to any value as they are set dynamically.
- ComputeDiagRemarkID(Severity, backend_plugin, DiagID);
- break;
- }
- std::string MsgStorage;
- {
- raw_string_ostream Stream(MsgStorage);
- DiagnosticPrinterRawOStream DP(Stream);
- DI.print(DP);
- }
-
- if (DiagID == diag::err_fe_cannot_link_module) {
- Diags.Report(diag::err_fe_cannot_link_module)
- << CurLinkModule->getModuleIdentifier() << MsgStorage;
- return;
- }
-
- // Report the backend message using the usual diagnostic mechanism.
- FullSourceLoc Loc;
- Diags.Report(Loc, DiagID).AddString(MsgStorage);
-}
-#undef ComputeDiagID
-
-CodeGenAction::CodeGenAction(unsigned _Act, LLVMContext *_VMContext)
- : Act(_Act), VMContext(_VMContext ? _VMContext : new LLVMContext),
- OwnsVMContext(!_VMContext) {}
-
-CodeGenAction::~CodeGenAction() {
- TheModule.reset();
- if (OwnsVMContext)
- delete VMContext;
-}
-
-bool CodeGenAction::hasIRSupport() const { return true; }
-
-void CodeGenAction::EndSourceFileAction() {
- // If the consumer creation failed, do nothing.
- if (!getCompilerInstance().hasASTConsumer())
- return;
-
- // Steal the module from the consumer.
- TheModule = BEConsumer->takeModule();
-}
-
-std::unique_ptr<llvm::Module> CodeGenAction::takeModule() {
- return std::move(TheModule);
-}
-
-llvm::LLVMContext *CodeGenAction::takeLLVMContext() {
- OwnsVMContext = false;
- return VMContext;
-}
-
-static std::unique_ptr<raw_pwrite_stream>
-GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) {
- switch (Action) {
- case Backend_EmitAssembly:
- return CI.createDefaultOutputFile(false, InFile, "s");
- case Backend_EmitLL:
- return CI.createDefaultOutputFile(false, InFile, "ll");
- case Backend_EmitBC:
- return CI.createDefaultOutputFile(true, InFile, "bc");
- case Backend_EmitNothing:
- return nullptr;
- case Backend_EmitMCNull:
- return CI.createNullOutputFile();
- case Backend_EmitObj:
- return CI.createDefaultOutputFile(true, InFile, "o");
- }
-
- llvm_unreachable("Invalid action!");
-}
-
-std::unique_ptr<ASTConsumer>
-CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- BackendAction BA = static_cast<BackendAction>(Act);
- std::unique_ptr<raw_pwrite_stream> OS = CI.takeOutputStream();
- if (!OS)
- OS = GetOutputStream(CI, InFile, BA);
-
- if (BA != Backend_EmitNothing && !OS)
- return nullptr;
-
- // Load bitcode modules to link with, if we need to.
- if (LinkModules.empty())
- for (const CodeGenOptions::BitcodeFileToLink &F :
- CI.getCodeGenOpts().LinkBitcodeFiles) {
- auto BCBuf = CI.getFileManager().getBufferForFile(F.Filename);
- if (!BCBuf) {
- CI.getDiagnostics().Report(diag::err_cannot_open_file)
- << F.Filename << BCBuf.getError().message();
- LinkModules.clear();
- return nullptr;
- }
-
- Expected<std::unique_ptr<llvm::Module>> ModuleOrErr =
- getOwningLazyBitcodeModule(std::move(*BCBuf), *VMContext);
- if (!ModuleOrErr) {
- handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
- CI.getDiagnostics().Report(diag::err_cannot_open_file)
- << F.Filename << EIB.message();
- });
- LinkModules.clear();
- return nullptr;
- }
- LinkModules.push_back({std::move(ModuleOrErr.get()), F.PropagateAttrs,
- F.Internalize, F.LinkFlags});
- }
-
- CoverageSourceInfo *CoverageInfo = nullptr;
- // Add the preprocessor callback only when the coverage mapping is generated.
- if (CI.getCodeGenOpts().CoverageMapping) {
- CoverageInfo = new CoverageSourceInfo;
- CI.getPreprocessor().addPPCallbacks(
- std::unique_ptr<PPCallbacks>(CoverageInfo));
- }
-
- std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
- BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
- CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
- CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile,
- std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
- BEConsumer = Result.get();
-
- // Enable generating macro debug info only when debug info is not disabled and
- // also macro debug info is enabled.
- if (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo &&
- CI.getCodeGenOpts().MacroDebugInfo) {
- std::unique_ptr<PPCallbacks> Callbacks =
- llvm::make_unique<MacroPPCallbacks>(BEConsumer->getCodeGenerator(),
- CI.getPreprocessor());
- CI.getPreprocessor().addPPCallbacks(std::move(Callbacks));
- }
-
- return std::move(Result);
-}
-
-static void BitcodeInlineAsmDiagHandler(const llvm::SMDiagnostic &SM,
- void *Context,
- unsigned LocCookie) {
- SM.print(nullptr, llvm::errs());
-
- auto Diags = static_cast<DiagnosticsEngine *>(Context);
- unsigned DiagID;
- switch (SM.getKind()) {
- case llvm::SourceMgr::DK_Error:
- DiagID = diag::err_fe_inline_asm;
- break;
- case llvm::SourceMgr::DK_Warning:
- DiagID = diag::warn_fe_inline_asm;
- break;
- case llvm::SourceMgr::DK_Note:
- DiagID = diag::note_fe_inline_asm;
- break;
- case llvm::SourceMgr::DK_Remark:
- llvm_unreachable("remarks unexpected");
- }
-
- Diags->Report(DiagID).AddString("cannot compile inline asm");
-}
-
-std::unique_ptr<llvm::Module> CodeGenAction::loadModule(MemoryBufferRef MBRef) {
- CompilerInstance &CI = getCompilerInstance();
- SourceManager &SM = CI.getSourceManager();
-
- // For ThinLTO backend invocations, ensure that the context
- // merges types based on ODR identifiers. We also need to read
- // the correct module out of a multi-module bitcode file.
- if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) {
- VMContext->enableDebugTypeODRUniquing();
-
- auto DiagErrors = [&](Error E) -> std::unique_ptr<llvm::Module> {
- unsigned DiagID =
- CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
- handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
- CI.getDiagnostics().Report(DiagID) << EIB.message();
- });
- return {};
- };
-
- Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef);
- if (!BMsOrErr)
- return DiagErrors(BMsOrErr.takeError());
- BitcodeModule *Bm = FindThinLTOModule(*BMsOrErr);
- // We have nothing to do if the file contains no ThinLTO module. This is
- // possible if ThinLTO compilation was not able to split module. Content of
- // the file was already processed by indexing and will be passed to the
- // linker using merged object file.
- if (!Bm) {
- auto M = llvm::make_unique<llvm::Module>("empty", *VMContext);
- M->setTargetTriple(CI.getTargetOpts().Triple);
- return M;
- }
- Expected<std::unique_ptr<llvm::Module>> MOrErr =
- Bm->parseModule(*VMContext);
- if (!MOrErr)
- return DiagErrors(MOrErr.takeError());
- return std::move(*MOrErr);
- }
-
- llvm::SMDiagnostic Err;
- if (std::unique_ptr<llvm::Module> M = parseIR(MBRef, Err, *VMContext))
- return M;
-
- // Translate from the diagnostic info to the SourceManager location if
- // available.
- // TODO: Unify this with ConvertBackendLocation()
- SourceLocation Loc;
- if (Err.getLineNo() > 0) {
- assert(Err.getColumnNo() >= 0);
- Loc = SM.translateFileLineCol(SM.getFileEntryForID(SM.getMainFileID()),
- Err.getLineNo(), Err.getColumnNo() + 1);
- }
-
- // Strip off a leading diagnostic code if there is one.
- StringRef Msg = Err.getMessage();
- if (Msg.startswith("error: "))
- Msg = Msg.substr(7);
-
- unsigned DiagID =
- CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
-
- CI.getDiagnostics().Report(Loc, DiagID) << Msg;
- return {};
-}
-
-void CodeGenAction::ExecuteAction() {
- // If this is an IR file, we have to treat it specially.
- if (getCurrentFileKind().getLanguage() == InputKind::LLVM_IR) {
- BackendAction BA = static_cast<BackendAction>(Act);
- CompilerInstance &CI = getCompilerInstance();
- std::unique_ptr<raw_pwrite_stream> OS =
- GetOutputStream(CI, getCurrentFile(), BA);
- if (BA != Backend_EmitNothing && !OS)
- return;
-
- bool Invalid;
- SourceManager &SM = CI.getSourceManager();
- FileID FID = SM.getMainFileID();
- llvm::MemoryBuffer *MainFile = SM.getBuffer(FID, &Invalid);
- if (Invalid)
- return;
-
- TheModule = loadModule(*MainFile);
- if (!TheModule)
- return;
-
- const TargetOptions &TargetOpts = CI.getTargetOpts();
- if (TheModule->getTargetTriple() != TargetOpts.Triple) {
- CI.getDiagnostics().Report(SourceLocation(),
- diag::warn_fe_override_module)
- << TargetOpts.Triple;
- TheModule->setTargetTriple(TargetOpts.Triple);
- }
-
- EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(),
- MainFile->getMemBufferRef());
-
- LLVMContext &Ctx = TheModule->getContext();
- Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler,
- &CI.getDiagnostics());
-
- EmitBackendOutput(CI.getDiagnostics(), CI.getHeaderSearchOpts(),
- CI.getCodeGenOpts(), TargetOpts, CI.getLangOpts(),
- CI.getTarget().getDataLayout(), TheModule.get(), BA,
- std::move(OS));
- return;
- }
-
- // Otherwise follow the normal AST path.
- this->ASTFrontendAction::ExecuteAction();
-}
-
-//
-
-void EmitAssemblyAction::anchor() { }
-EmitAssemblyAction::EmitAssemblyAction(llvm::LLVMContext *_VMContext)
- : CodeGenAction(Backend_EmitAssembly, _VMContext) {}
-
-void EmitBCAction::anchor() { }
-EmitBCAction::EmitBCAction(llvm::LLVMContext *_VMContext)
- : CodeGenAction(Backend_EmitBC, _VMContext) {}
-
-void EmitLLVMAction::anchor() { }
-EmitLLVMAction::EmitLLVMAction(llvm::LLVMContext *_VMContext)
- : CodeGenAction(Backend_EmitLL, _VMContext) {}
-
-void EmitLLVMOnlyAction::anchor() { }
-EmitLLVMOnlyAction::EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext)
- : CodeGenAction(Backend_EmitNothing, _VMContext) {}
-
-void EmitCodeGenOnlyAction::anchor() { }
-EmitCodeGenOnlyAction::EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext)
- : CodeGenAction(Backend_EmitMCNull, _VMContext) {}
-
-void EmitObjAction::anchor() { }
-EmitObjAction::EmitObjAction(llvm::LLVMContext *_VMContext)
- : CodeGenAction(Backend_EmitObj, _VMContext) {}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp
deleted file mode 100644
index 1713e40c312..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp
+++ /dev/null
@@ -1,2565 +0,0 @@
-//===--- CodeGenFunction.cpp - Emit LLVM Code from ASTs for a Function ----===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This coordinates the per-function state used while generating code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-#include "CGBlocks.h"
-#include "CGCleanup.h"
-#include "CGCUDARuntime.h"
-#include "CGCXXABI.h"
-#include "CGDebugInfo.h"
-#include "CGOpenMPRuntime.h"
-#include "CodeGenModule.h"
-#include "CodeGenPGO.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTLambda.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/IR/Operator.h"
-#include "llvm/Transforms/Utils/PromoteMemToReg.h"
-using namespace clang;
-using namespace CodeGen;
-
-/// shouldEmitLifetimeMarkers - Decide whether we need emit the life-time
-/// markers.
-static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
- const LangOptions &LangOpts) {
- if (CGOpts.DisableLifetimeMarkers)
- return false;
-
- // Disable lifetime markers in msan builds.
- // FIXME: Remove this when msan works with lifetime markers.
- if (LangOpts.Sanitize.has(SanitizerKind::Memory))
- return false;
-
- // Asan uses markers for use-after-scope checks.
- if (CGOpts.SanitizeAddressUseAfterScope)
- return true;
-
- // For now, only in optimized builds.
- return CGOpts.OptimizationLevel != 0;
-}
-
-CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
- : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
- Builder(cgm, cgm.getModule().getContext(), llvm::ConstantFolder(),
- CGBuilderInserterTy(this)),
- SanOpts(CGM.getLangOpts().Sanitize), DebugInfo(CGM.getModuleDebugInfo()),
- PGO(cgm), ShouldEmitLifetimeMarkers(shouldEmitLifetimeMarkers(
- CGM.getCodeGenOpts(), CGM.getLangOpts())) {
- if (!suppressNewContext)
- CGM.getCXXABI().getMangleContext().startNewFunction();
-
- llvm::FastMathFlags FMF;
- if (CGM.getLangOpts().FastMath)
- FMF.setFast();
- if (CGM.getLangOpts().FiniteMathOnly) {
- FMF.setNoNaNs();
- FMF.setNoInfs();
- }
- if (CGM.getCodeGenOpts().NoNaNsFPMath) {
- FMF.setNoNaNs();
- }
- if (CGM.getCodeGenOpts().NoSignedZeros) {
- FMF.setNoSignedZeros();
- }
- if (CGM.getCodeGenOpts().ReciprocalMath) {
- FMF.setAllowReciprocal();
- }
- if (CGM.getCodeGenOpts().Reassociate) {
- FMF.setAllowReassoc();
- }
- Builder.setFastMathFlags(FMF);
-}
-
-CodeGenFunction::~CodeGenFunction() {
- assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup");
-
- // If there are any unclaimed block infos, go ahead and destroy them
- // now. This can happen if IR-gen gets clever and skips evaluating
- // something.
- if (FirstBlockInfo)
- destroyBlockInfos(FirstBlockInfo);
-
- if (getLangOpts().OpenMP && CurFn)
- CGM.getOpenMPRuntime().functionFinished(*this);
-}
-
-CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
- LValueBaseInfo *BaseInfo,
- TBAAAccessInfo *TBAAInfo) {
- return getNaturalTypeAlignment(T->getPointeeType(), BaseInfo, TBAAInfo,
- /* forPointeeType= */ true);
-}
-
-CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T,
- LValueBaseInfo *BaseInfo,
- TBAAAccessInfo *TBAAInfo,
- bool forPointeeType) {
- if (TBAAInfo)
- *TBAAInfo = CGM.getTBAAAccessInfo(T);
-
- // Honor alignment typedef attributes even on incomplete types.
- // We also honor them straight for C++ class types, even as pointees;
- // there's an expressivity gap here.
- if (auto TT = T->getAs<TypedefType>()) {
- if (auto Align = TT->getDecl()->getMaxAlignment()) {
- if (BaseInfo)
- *BaseInfo = LValueBaseInfo(AlignmentSource::AttributedType);
- return getContext().toCharUnitsFromBits(Align);
- }
- }
-
- if (BaseInfo)
- *BaseInfo = LValueBaseInfo(AlignmentSource::Type);
-
- CharUnits Alignment;
- if (T->isIncompleteType()) {
- Alignment = CharUnits::One(); // Shouldn't be used, but pessimistic is best.
- } else {
- // For C++ class pointees, we don't know whether we're pointing at a
- // base or a complete object, so we generally need to use the
- // non-virtual alignment.
- const CXXRecordDecl *RD;
- if (forPointeeType && (RD = T->getAsCXXRecordDecl())) {
- Alignment = CGM.getClassPointerAlignment(RD);
- } else {
- Alignment = getContext().getTypeAlignInChars(T);
- if (T.getQualifiers().hasUnaligned())
- Alignment = CharUnits::One();
- }
-
- // Cap to the global maximum type alignment unless the alignment
- // was somehow explicit on the type.
- if (unsigned MaxAlign = getLangOpts().MaxTypeAlign) {
- if (Alignment.getQuantity() > MaxAlign &&
- !getContext().isAlignmentRequired(T))
- Alignment = CharUnits::fromQuantity(MaxAlign);
- }
- }
- return Alignment;
-}
-
-LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- CharUnits Alignment = getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo);
- return LValue::MakeAddr(Address(V, Alignment), T, getContext(), BaseInfo,
- TBAAInfo);
-}
-
-/// Given a value of type T* that may not be to a complete object,
-/// construct an l-value with the natural pointee alignment of T.
-LValue
-CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) {
- LValueBaseInfo BaseInfo;
- TBAAAccessInfo TBAAInfo;
- CharUnits Align = getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo,
- /* forPointeeType= */ true);
- return MakeAddrLValue(Address(V, Align), T, BaseInfo, TBAAInfo);
-}
-
-
-llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
- return CGM.getTypes().ConvertTypeForMem(T);
-}
-
-llvm::Type *CodeGenFunction::ConvertType(QualType T) {
- return CGM.getTypes().ConvertType(T);
-}
-
-TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
- type = type.getCanonicalType();
- while (true) {
- switch (type->getTypeClass()) {
-#define TYPE(name, parent)
-#define ABSTRACT_TYPE(name, parent)
-#define NON_CANONICAL_TYPE(name, parent) case Type::name:
-#define DEPENDENT_TYPE(name, parent) case Type::name:
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("non-canonical or dependent type in IR-generation");
-
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- llvm_unreachable("undeduced type in IR-generation");
-
- // Various scalar types.
- case Type::Builtin:
- case Type::Pointer:
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- case Type::Enum:
- case Type::ObjCObjectPointer:
- case Type::Pipe:
- return TEK_Scalar;
-
- // Complexes.
- case Type::Complex:
- return TEK_Complex;
-
- // Arrays, records, and Objective-C objects.
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- case Type::Record:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- return TEK_Aggregate;
-
- // We operate on atomic values according to their underlying type.
- case Type::Atomic:
- type = cast<AtomicType>(type)->getValueType();
- continue;
- }
- llvm_unreachable("unknown type kind!");
- }
-}
-
-llvm::DebugLoc CodeGenFunction::EmitReturnBlock() {
- // For cleanliness, we try to avoid emitting the return block for
- // simple cases.
- llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
-
- if (CurBB) {
- assert(!CurBB->getTerminator() && "Unexpected terminated block.");
-
- // We have a valid insert point, reuse it if it is empty or there are no
- // explicit jumps to the return block.
- if (CurBB->empty() || ReturnBlock.getBlock()->use_empty()) {
- ReturnBlock.getBlock()->replaceAllUsesWith(CurBB);
- delete ReturnBlock.getBlock();
- } else
- EmitBlock(ReturnBlock.getBlock());
- return llvm::DebugLoc();
- }
-
- // Otherwise, if the return block is the target of a single direct
- // branch then we can just put the code in that block instead. This
- // cleans up functions which started with a unified return block.
- if (ReturnBlock.getBlock()->hasOneUse()) {
- llvm::BranchInst *BI =
- dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->user_begin());
- if (BI && BI->isUnconditional() &&
- BI->getSuccessor(0) == ReturnBlock.getBlock()) {
- // Record/return the DebugLoc of the simple 'return' expression to be used
- // later by the actual 'ret' instruction.
- llvm::DebugLoc Loc = BI->getDebugLoc();
- Builder.SetInsertPoint(BI->getParent());
- BI->eraseFromParent();
- delete ReturnBlock.getBlock();
- return Loc;
- }
- }
-
- // FIXME: We are at an unreachable point, there is no reason to emit the block
- // unless it has uses. However, we still need a place to put the debug
- // region.end for now.
-
- EmitBlock(ReturnBlock.getBlock());
- return llvm::DebugLoc();
-}
-
-static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
- if (!BB) return;
- if (!BB->use_empty())
- return CGF.CurFn->getBasicBlockList().push_back(BB);
- delete BB;
-}
-
-void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
- assert(BreakContinueStack.empty() &&
- "mismatched push/pop in break/continue stack!");
-
- bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0
- && NumSimpleReturnExprs == NumReturnExprs
- && ReturnBlock.getBlock()->use_empty();
- // Usually the return expression is evaluated before the cleanup
- // code. If the function contains only a simple return statement,
- // such as a constant, the location before the cleanup code becomes
- // the last useful breakpoint in the function, because the simple
- // return expression will be evaluated after the cleanup code. To be
- // safe, set the debug location for cleanup code to the location of
- // the return statement. Otherwise the cleanup code should be at the
- // end of the function's lexical scope.
- //
- // If there are multiple branches to the return block, the branch
- // instructions will get the location of the return statements and
- // all will be fine.
- if (CGDebugInfo *DI = getDebugInfo()) {
- if (OnlySimpleReturnStmts)
- DI->EmitLocation(Builder, LastStopPoint);
- else
- DI->EmitLocation(Builder, EndLoc);
- }
-
- // Pop any cleanups that might have been associated with the
- // parameters. Do this in whatever block we're currently in; it's
- // important to do this before we enter the return block or return
- // edges will be *really* confused.
- bool HasCleanups = EHStack.stable_begin() != PrologueCleanupDepth;
- bool HasOnlyLifetimeMarkers =
- HasCleanups && EHStack.containsOnlyLifetimeMarkers(PrologueCleanupDepth);
- bool EmitRetDbgLoc = !HasCleanups || HasOnlyLifetimeMarkers;
- if (HasCleanups) {
- // Make sure the line table doesn't jump back into the body for
- // the ret after it's been at EndLoc.
- if (CGDebugInfo *DI = getDebugInfo())
- if (OnlySimpleReturnStmts)
- DI->EmitLocation(Builder, EndLoc);
-
- PopCleanupBlocks(PrologueCleanupDepth);
- }
-
- // Emit function epilog (to return).
- llvm::DebugLoc Loc = EmitReturnBlock();
-
- if (ShouldInstrumentFunction()) {
- if (CGM.getCodeGenOpts().InstrumentFunctions)
- CurFn->addFnAttr("instrument-function-exit", "__cyg_profile_func_exit");
- if (CGM.getCodeGenOpts().InstrumentFunctionsAfterInlining)
- CurFn->addFnAttr("instrument-function-exit-inlined",
- "__cyg_profile_func_exit");
- }
-
- // Emit debug descriptor for function end.
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitFunctionEnd(Builder, CurFn);
-
- // Reset the debug location to that of the simple 'return' expression, if any
- // rather than that of the end of the function's scope '}'.
- ApplyDebugLocation AL(*this, Loc);
- EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc, EndLoc);
- EmitEndEHSpec(CurCodeDecl);
-
- assert(EHStack.empty() &&
- "did not remove all scopes from cleanup stack!");
-
- // If someone did an indirect goto, emit the indirect goto block at the end of
- // the function.
- if (IndirectBranch) {
- EmitBlock(IndirectBranch->getParent());
- Builder.ClearInsertionPoint();
- }
-
- // If some of our locals escaped, insert a call to llvm.localescape in the
- // entry block.
- if (!EscapedLocals.empty()) {
- // Invert the map from local to index into a simple vector. There should be
- // no holes.
- SmallVector<llvm::Value *, 4> EscapeArgs;
- EscapeArgs.resize(EscapedLocals.size());
- for (auto &Pair : EscapedLocals)
- EscapeArgs[Pair.second] = Pair.first;
- llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration(
- &CGM.getModule(), llvm::Intrinsic::localescape);
- CGBuilderTy(*this, AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs);
- }
-
- // Remove the AllocaInsertPt instruction, which is just a convenience for us.
- llvm::Instruction *Ptr = AllocaInsertPt;
- AllocaInsertPt = nullptr;
- Ptr->eraseFromParent();
-
- // If someone took the address of a label but never did an indirect goto, we
- // made a zero entry PHI node, which is illegal, zap it now.
- if (IndirectBranch) {
- llvm::PHINode *PN = cast<llvm::PHINode>(IndirectBranch->getAddress());
- if (PN->getNumIncomingValues() == 0) {
- PN->replaceAllUsesWith(llvm::UndefValue::get(PN->getType()));
- PN->eraseFromParent();
- }
- }
-
- EmitIfUsed(*this, EHResumeBlock);
- EmitIfUsed(*this, TerminateLandingPad);
- EmitIfUsed(*this, TerminateHandler);
- EmitIfUsed(*this, UnreachableBlock);
-
- for (const auto &FuncletAndParent : TerminateFunclets)
- EmitIfUsed(*this, FuncletAndParent.second);
-
- if (CGM.getCodeGenOpts().EmitDeclMetadata)
- EmitDeclMetadata();
-
- for (SmallVectorImpl<std::pair<llvm::Instruction *, llvm::Value *> >::iterator
- I = DeferredReplacements.begin(),
- E = DeferredReplacements.end();
- I != E; ++I) {
- I->first->replaceAllUsesWith(I->second);
- I->first->eraseFromParent();
- }
-
- // Eliminate CleanupDestSlot alloca by replacing it with SSA values and
- // PHIs if the current function is a coroutine. We don't do it for all
- // functions as it may result in slight increase in numbers of instructions
- // if compiled with no optimizations. We do it for coroutine as the lifetime
- // of CleanupDestSlot alloca make correct coroutine frame building very
- // difficult.
- if (NormalCleanupDest.isValid() && isCoroutine()) {
- llvm::DominatorTree DT(*CurFn);
- llvm::PromoteMemToReg(
- cast<llvm::AllocaInst>(NormalCleanupDest.getPointer()), DT);
- NormalCleanupDest = Address::invalid();
- }
-
- // Scan function arguments for vector width.
- for (llvm::Argument &A : CurFn->args())
- if (auto *VT = dyn_cast<llvm::VectorType>(A.getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
-
- // Update vector width based on return type.
- if (auto *VT = dyn_cast<llvm::VectorType>(CurFn->getReturnType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
-
- // Add the required-vector-width attribute. This contains the max width from:
- // 1. min-vector-width attribute used in the source program.
- // 2. Any builtins used that have a vector width specified.
- // 3. Values passed in and out of inline assembly.
- // 4. Width of vector arguments and return types for this function.
- // 5. Width of vector aguments and return types for functions called by this
- // function.
- CurFn->addFnAttr("min-legal-vector-width", llvm::utostr(LargestVectorWidth));
-}
-
-/// ShouldInstrumentFunction - Return true if the current function should be
-/// instrumented with __cyg_profile_func_* calls
-bool CodeGenFunction::ShouldInstrumentFunction() {
- if (!CGM.getCodeGenOpts().InstrumentFunctions &&
- !CGM.getCodeGenOpts().InstrumentFunctionsAfterInlining &&
- !CGM.getCodeGenOpts().InstrumentFunctionEntryBare)
- return false;
- if (!CurFuncDecl || CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
- return false;
- return true;
-}
-
-/// ShouldXRayInstrument - Return true if the current function should be
-/// instrumented with XRay nop sleds.
-bool CodeGenFunction::ShouldXRayInstrumentFunction() const {
- return CGM.getCodeGenOpts().XRayInstrumentFunctions;
-}
-
-/// AlwaysEmitXRayCustomEvents - Return true if we should emit IR for calls to
-/// the __xray_customevent(...) builtin calls, when doing XRay instrumentation.
-bool CodeGenFunction::AlwaysEmitXRayCustomEvents() const {
- return CGM.getCodeGenOpts().XRayInstrumentFunctions &&
- (CGM.getCodeGenOpts().XRayAlwaysEmitCustomEvents ||
- CGM.getCodeGenOpts().XRayInstrumentationBundle.Mask ==
- XRayInstrKind::Custom);
-}
-
-bool CodeGenFunction::AlwaysEmitXRayTypedEvents() const {
- return CGM.getCodeGenOpts().XRayInstrumentFunctions &&
- (CGM.getCodeGenOpts().XRayAlwaysEmitTypedEvents ||
- CGM.getCodeGenOpts().XRayInstrumentationBundle.Mask ==
- XRayInstrKind::Typed);
-}
-
-llvm::Constant *
-CodeGenFunction::EncodeAddrForUseInPrologue(llvm::Function *F,
- llvm::Constant *Addr) {
- // Addresses stored in prologue data can't require run-time fixups and must
- // be PC-relative. Run-time fixups are undesirable because they necessitate
- // writable text segments, which are unsafe. And absolute addresses are
- // undesirable because they break PIE mode.
-
- // Add a layer of indirection through a private global. Taking its address
- // won't result in a run-time fixup, even if Addr has linkonce_odr linkage.
- auto *GV = new llvm::GlobalVariable(CGM.getModule(), Addr->getType(),
- /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Addr);
-
- // Create a PC-relative address.
- auto *GOTAsInt = llvm::ConstantExpr::getPtrToInt(GV, IntPtrTy);
- auto *FuncAsInt = llvm::ConstantExpr::getPtrToInt(F, IntPtrTy);
- auto *PCRelAsInt = llvm::ConstantExpr::getSub(GOTAsInt, FuncAsInt);
- return (IntPtrTy == Int32Ty)
- ? PCRelAsInt
- : llvm::ConstantExpr::getTrunc(PCRelAsInt, Int32Ty);
-}
-
-llvm::Value *
-CodeGenFunction::DecodeAddrUsedInPrologue(llvm::Value *F,
- llvm::Value *EncodedAddr) {
- // Reconstruct the address of the global.
- auto *PCRelAsInt = Builder.CreateSExt(EncodedAddr, IntPtrTy);
- auto *FuncAsInt = Builder.CreatePtrToInt(F, IntPtrTy, "func_addr.int");
- auto *GOTAsInt = Builder.CreateAdd(PCRelAsInt, FuncAsInt, "global_addr.int");
- auto *GOTAddr = Builder.CreateIntToPtr(GOTAsInt, Int8PtrPtrTy, "global_addr");
-
- // Load the original pointer through the global.
- return Builder.CreateLoad(Address(GOTAddr, getPointerAlign()),
- "decoded_addr");
-}
-
-static void removeImageAccessQualifier(std::string& TyName) {
- std::string ReadOnlyQual("__read_only");
- std::string::size_type ReadOnlyPos = TyName.find(ReadOnlyQual);
- if (ReadOnlyPos != std::string::npos)
- // "+ 1" for the space after access qualifier.
- TyName.erase(ReadOnlyPos, ReadOnlyQual.size() + 1);
- else {
- std::string WriteOnlyQual("__write_only");
- std::string::size_type WriteOnlyPos = TyName.find(WriteOnlyQual);
- if (WriteOnlyPos != std::string::npos)
- TyName.erase(WriteOnlyPos, WriteOnlyQual.size() + 1);
- else {
- std::string ReadWriteQual("__read_write");
- std::string::size_type ReadWritePos = TyName.find(ReadWriteQual);
- if (ReadWritePos != std::string::npos)
- TyName.erase(ReadWritePos, ReadWriteQual.size() + 1);
- }
- }
-}
-
-// Returns the address space id that should be produced to the
-// kernel_arg_addr_space metadata. This is always fixed to the ids
-// as specified in the SPIR 2.0 specification in order to differentiate
-// for example in clGetKernelArgInfo() implementation between the address
-// spaces with targets without unique mapping to the OpenCL address spaces
-// (basically all single AS CPUs).
-static unsigned ArgInfoAddressSpace(LangAS AS) {
- switch (AS) {
- case LangAS::opencl_global: return 1;
- case LangAS::opencl_constant: return 2;
- case LangAS::opencl_local: return 3;
- case LangAS::opencl_generic: return 4; // Not in SPIR 2.0 specs.
- default:
- return 0; // Assume private.
- }
-}
-
-// OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument
-// information in the program executable. The argument information stored
-// includes the argument name, its type, the address and access qualifiers used.
-static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
- CodeGenModule &CGM, llvm::LLVMContext &Context,
- CGBuilderTy &Builder, ASTContext &ASTCtx) {
- // Create MDNodes that represent the kernel arg metadata.
- // Each MDNode is a list in the form of "key", N number of values which is
- // the same number of values as their are kernel arguments.
-
- const PrintingPolicy &Policy = ASTCtx.getPrintingPolicy();
-
- // MDNode for the kernel argument address space qualifiers.
- SmallVector<llvm::Metadata *, 8> addressQuals;
-
- // MDNode for the kernel argument access qualifiers (images only).
- SmallVector<llvm::Metadata *, 8> accessQuals;
-
- // MDNode for the kernel argument type names.
- SmallVector<llvm::Metadata *, 8> argTypeNames;
-
- // MDNode for the kernel argument base type names.
- SmallVector<llvm::Metadata *, 8> argBaseTypeNames;
-
- // MDNode for the kernel argument type qualifiers.
- SmallVector<llvm::Metadata *, 8> argTypeQuals;
-
- // MDNode for the kernel argument names.
- SmallVector<llvm::Metadata *, 8> argNames;
-
- for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
- const ParmVarDecl *parm = FD->getParamDecl(i);
- QualType ty = parm->getType();
- std::string typeQuals;
-
- if (ty->isPointerType()) {
- QualType pointeeTy = ty->getPointeeType();
-
- // Get address qualifier.
- addressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(
- ArgInfoAddressSpace(pointeeTy.getAddressSpace()))));
-
- // Get argument type name.
- std::string typeName =
- pointeeTy.getUnqualifiedType().getAsString(Policy) + "*";
-
- // Turn "unsigned type" to "utype"
- std::string::size_type pos = typeName.find("unsigned");
- if (pointeeTy.isCanonical() && pos != std::string::npos)
- typeName.erase(pos+1, 8);
-
- argTypeNames.push_back(llvm::MDString::get(Context, typeName));
-
- std::string baseTypeName =
- pointeeTy.getUnqualifiedType().getCanonicalType().getAsString(
- Policy) +
- "*";
-
- // Turn "unsigned type" to "utype"
- pos = baseTypeName.find("unsigned");
- if (pos != std::string::npos)
- baseTypeName.erase(pos+1, 8);
-
- argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName));
-
- // Get argument type qualifiers:
- if (ty.isRestrictQualified())
- typeQuals = "restrict";
- if (pointeeTy.isConstQualified() ||
- (pointeeTy.getAddressSpace() == LangAS::opencl_constant))
- typeQuals += typeQuals.empty() ? "const" : " const";
- if (pointeeTy.isVolatileQualified())
- typeQuals += typeQuals.empty() ? "volatile" : " volatile";
- } else {
- uint32_t AddrSpc = 0;
- bool isPipe = ty->isPipeType();
- if (ty->isImageType() || isPipe)
- AddrSpc = ArgInfoAddressSpace(LangAS::opencl_global);
-
- addressQuals.push_back(
- llvm::ConstantAsMetadata::get(Builder.getInt32(AddrSpc)));
-
- // Get argument type name.
- std::string typeName;
- if (isPipe)
- typeName = ty.getCanonicalType()->getAs<PipeType>()->getElementType()
- .getAsString(Policy);
- else
- typeName = ty.getUnqualifiedType().getAsString(Policy);
-
- // Turn "unsigned type" to "utype"
- std::string::size_type pos = typeName.find("unsigned");
- if (ty.isCanonical() && pos != std::string::npos)
- typeName.erase(pos+1, 8);
-
- std::string baseTypeName;
- if (isPipe)
- baseTypeName = ty.getCanonicalType()->getAs<PipeType>()
- ->getElementType().getCanonicalType()
- .getAsString(Policy);
- else
- baseTypeName =
- ty.getUnqualifiedType().getCanonicalType().getAsString(Policy);
-
- // Remove access qualifiers on images
- // (as they are inseparable from type in clang implementation,
- // but OpenCL spec provides a special query to get access qualifier
- // via clGetKernelArgInfo with CL_KERNEL_ARG_ACCESS_QUALIFIER):
- if (ty->isImageType()) {
- removeImageAccessQualifier(typeName);
- removeImageAccessQualifier(baseTypeName);
- }
-
- argTypeNames.push_back(llvm::MDString::get(Context, typeName));
-
- // Turn "unsigned type" to "utype"
- pos = baseTypeName.find("unsigned");
- if (pos != std::string::npos)
- baseTypeName.erase(pos+1, 8);
-
- argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName));
-
- if (isPipe)
- typeQuals = "pipe";
- }
-
- argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals));
-
- // Get image and pipe access qualifier:
- if (ty->isImageType()|| ty->isPipeType()) {
- const Decl *PDecl = parm;
- if (auto *TD = dyn_cast<TypedefType>(ty))
- PDecl = TD->getDecl();
- const OpenCLAccessAttr *A = PDecl->getAttr<OpenCLAccessAttr>();
- if (A && A->isWriteOnly())
- accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
- else if (A && A->isReadWrite())
- accessQuals.push_back(llvm::MDString::get(Context, "read_write"));
- else
- accessQuals.push_back(llvm::MDString::get(Context, "read_only"));
- } else
- accessQuals.push_back(llvm::MDString::get(Context, "none"));
-
- // Get argument name.
- argNames.push_back(llvm::MDString::get(Context, parm->getName()));
- }
-
- Fn->setMetadata("kernel_arg_addr_space",
- llvm::MDNode::get(Context, addressQuals));
- Fn->setMetadata("kernel_arg_access_qual",
- llvm::MDNode::get(Context, accessQuals));
- Fn->setMetadata("kernel_arg_type",
- llvm::MDNode::get(Context, argTypeNames));
- Fn->setMetadata("kernel_arg_base_type",
- llvm::MDNode::get(Context, argBaseTypeNames));
- Fn->setMetadata("kernel_arg_type_qual",
- llvm::MDNode::get(Context, argTypeQuals));
- if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
- Fn->setMetadata("kernel_arg_name",
- llvm::MDNode::get(Context, argNames));
-}
-
-void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
- llvm::Function *Fn)
-{
- if (!FD->hasAttr<OpenCLKernelAttr>())
- return;
-
- llvm::LLVMContext &Context = getLLVMContext();
-
- GenOpenCLArgMetadata(FD, Fn, CGM, Context, Builder, getContext());
-
- if (const VecTypeHintAttr *A = FD->getAttr<VecTypeHintAttr>()) {
- QualType HintQTy = A->getTypeHint();
- const ExtVectorType *HintEltQTy = HintQTy->getAs<ExtVectorType>();
- bool IsSignedInteger =
- HintQTy->isSignedIntegerType() ||
- (HintEltQTy && HintEltQTy->getElementType()->isSignedIntegerType());
- llvm::Metadata *AttrMDArgs[] = {
- llvm::ConstantAsMetadata::get(llvm::UndefValue::get(
- CGM.getTypes().ConvertType(A->getTypeHint()))),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::IntegerType::get(Context, 32),
- llvm::APInt(32, (uint64_t)(IsSignedInteger ? 1 : 0))))};
- Fn->setMetadata("vec_type_hint", llvm::MDNode::get(Context, AttrMDArgs));
- }
-
- if (const WorkGroupSizeHintAttr *A = FD->getAttr<WorkGroupSizeHintAttr>()) {
- llvm::Metadata *AttrMDArgs[] = {
- llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())),
- llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())),
- llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))};
- Fn->setMetadata("work_group_size_hint", llvm::MDNode::get(Context, AttrMDArgs));
- }
-
- if (const ReqdWorkGroupSizeAttr *A = FD->getAttr<ReqdWorkGroupSizeAttr>()) {
- llvm::Metadata *AttrMDArgs[] = {
- llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())),
- llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())),
- llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))};
- Fn->setMetadata("reqd_work_group_size", llvm::MDNode::get(Context, AttrMDArgs));
- }
-
- if (const OpenCLIntelReqdSubGroupSizeAttr *A =
- FD->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) {
- llvm::Metadata *AttrMDArgs[] = {
- llvm::ConstantAsMetadata::get(Builder.getInt32(A->getSubGroupSize()))};
- Fn->setMetadata("intel_reqd_sub_group_size",
- llvm::MDNode::get(Context, AttrMDArgs));
- }
-}
-
-/// Determine whether the function F ends with a return stmt.
-static bool endsWithReturn(const Decl* F) {
- const Stmt *Body = nullptr;
- if (auto *FD = dyn_cast_or_null<FunctionDecl>(F))
- Body = FD->getBody();
- else if (auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(F))
- Body = OMD->getBody();
-
- if (auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
- auto LastStmt = CS->body_rbegin();
- if (LastStmt != CS->body_rend())
- return isa<ReturnStmt>(*LastStmt);
- }
- return false;
-}
-
-void CodeGenFunction::markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) {
- if (SanOpts.has(SanitizerKind::Thread)) {
- Fn->addFnAttr("sanitize_thread_no_checking_at_run_time");
- Fn->removeFnAttr(llvm::Attribute::SanitizeThread);
- }
-}
-
-static bool matchesStlAllocatorFn(const Decl *D, const ASTContext &Ctx) {
- auto *MD = dyn_cast_or_null<CXXMethodDecl>(D);
- if (!MD || !MD->getDeclName().getAsIdentifierInfo() ||
- !MD->getDeclName().getAsIdentifierInfo()->isStr("allocate") ||
- (MD->getNumParams() != 1 && MD->getNumParams() != 2))
- return false;
-
- if (MD->parameters()[0]->getType().getCanonicalType() != Ctx.getSizeType())
- return false;
-
- if (MD->getNumParams() == 2) {
- auto *PT = MD->parameters()[1]->getType()->getAs<PointerType>();
- if (!PT || !PT->isVoidPointerType() ||
- !PT->getPointeeType().isConstQualified())
- return false;
- }
-
- return true;
-}
-
-/// Return the UBSan prologue signature for \p FD if one is available.
-static llvm::Constant *getPrologueSignature(CodeGenModule &CGM,
- const FunctionDecl *FD) {
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
- if (!MD->isStatic())
- return nullptr;
- return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM);
-}
-
-void CodeGenFunction::StartFunction(GlobalDecl GD,
- QualType RetTy,
- llvm::Function *Fn,
- const CGFunctionInfo &FnInfo,
- const FunctionArgList &Args,
- SourceLocation Loc,
- SourceLocation StartLoc) {
- assert(!CurFn &&
- "Do not use a CodeGenFunction object for more than one function");
-
- const Decl *D = GD.getDecl();
-
- DidCallStackSave = false;
- CurCodeDecl = D;
- if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
- if (FD->usesSEHTry())
- CurSEHParent = FD;
- CurFuncDecl = (D ? D->getNonClosureContext() : nullptr);
- FnRetTy = RetTy;
- CurFn = Fn;
- CurFnInfo = &FnInfo;
- assert(CurFn->isDeclaration() && "Function already has body?");
-
- // If this function has been blacklisted for any of the enabled sanitizers,
- // disable the sanitizer for the function.
- do {
-#define SANITIZER(NAME, ID) \
- if (SanOpts.empty()) \
- break; \
- if (SanOpts.has(SanitizerKind::ID)) \
- if (CGM.isInSanitizerBlacklist(SanitizerKind::ID, Fn, Loc)) \
- SanOpts.set(SanitizerKind::ID, false);
-
-#include "clang/Basic/Sanitizers.def"
-#undef SANITIZER
- } while (0);
-
- if (D) {
- // Apply the no_sanitize* attributes to SanOpts.
- for (auto Attr : D->specific_attrs<NoSanitizeAttr>()) {
- SanitizerMask mask = Attr->getMask();
- SanOpts.Mask &= ~mask;
- if (mask & SanitizerKind::Address)
- SanOpts.set(SanitizerKind::KernelAddress, false);
- if (mask & SanitizerKind::KernelAddress)
- SanOpts.set(SanitizerKind::Address, false);
- if (mask & SanitizerKind::HWAddress)
- SanOpts.set(SanitizerKind::KernelHWAddress, false);
- if (mask & SanitizerKind::KernelHWAddress)
- SanOpts.set(SanitizerKind::HWAddress, false);
- }
- }
-
- // Apply sanitizer attributes to the function.
- if (SanOpts.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress))
- Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
- if (SanOpts.hasOneOf(SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress))
- Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
- if (SanOpts.has(SanitizerKind::Thread))
- Fn->addFnAttr(llvm::Attribute::SanitizeThread);
- if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
- Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
- if (SanOpts.has(SanitizerKind::SafeStack))
- Fn->addFnAttr(llvm::Attribute::SafeStack);
- if (SanOpts.has(SanitizerKind::ShadowCallStack))
- Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
-
- // Apply fuzzing attribute to the function.
- if (SanOpts.hasOneOf(SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink))
- Fn->addFnAttr(llvm::Attribute::OptForFuzzing);
-
- // Ignore TSan memory acesses from within ObjC/ObjC++ dealloc, initialize,
- // .cxx_destruct, __destroy_helper_block_ and all of their calees at run time.
- if (SanOpts.has(SanitizerKind::Thread)) {
- if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
- IdentifierInfo *II = OMD->getSelector().getIdentifierInfoForSlot(0);
- if (OMD->getMethodFamily() == OMF_dealloc ||
- OMD->getMethodFamily() == OMF_initialize ||
- (OMD->getSelector().isUnarySelector() && II->isStr(".cxx_destruct"))) {
- markAsIgnoreThreadCheckingAtRuntime(Fn);
- }
- }
- }
-
- // Ignore unrelated casts in STL allocate() since the allocator must cast
- // from void* to T* before object initialization completes. Don't match on the
- // namespace because not all allocators are in std::
- if (D && SanOpts.has(SanitizerKind::CFIUnrelatedCast)) {
- if (matchesStlAllocatorFn(D, getContext()))
- SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast;
- }
-
- // Apply xray attributes to the function (as a string, for now)
- if (D) {
- if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
- if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
- XRayInstrKind::Function)) {
- if (XRayAttr->alwaysXRayInstrument() && ShouldXRayInstrumentFunction())
- Fn->addFnAttr("function-instrument", "xray-always");
- if (XRayAttr->neverXRayInstrument())
- Fn->addFnAttr("function-instrument", "xray-never");
- if (const auto *LogArgs = D->getAttr<XRayLogArgsAttr>())
- if (ShouldXRayInstrumentFunction())
- Fn->addFnAttr("xray-log-args",
- llvm::utostr(LogArgs->getArgumentCount()));
- }
- } else {
- if (ShouldXRayInstrumentFunction() && !CGM.imbueXRayAttrs(Fn, Loc))
- Fn->addFnAttr(
- "xray-instruction-threshold",
- llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
- }
- }
-
- // Add no-jump-tables value.
- Fn->addFnAttr("no-jump-tables",
- llvm::toStringRef(CGM.getCodeGenOpts().NoUseJumpTables));
-
- // Add profile-sample-accurate value.
- if (CGM.getCodeGenOpts().ProfileSampleAccurate)
- Fn->addFnAttr("profile-sample-accurate");
-
- if (getLangOpts().OpenCL) {
- // Add metadata for a kernel function.
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- EmitOpenCLKernelMetadata(FD, Fn);
- }
-
- // If we are checking function types, emit a function type signature as
- // prologue data.
- if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function)) {
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- if (llvm::Constant *PrologueSig = getPrologueSignature(CGM, FD)) {
- // Remove any (C++17) exception specifications, to allow calling e.g. a
- // noexcept function through a non-noexcept pointer.
- auto ProtoTy =
- getContext().getFunctionTypeWithExceptionSpec(FD->getType(),
- EST_None);
- llvm::Constant *FTRTTIConst =
- CGM.GetAddrOfRTTIDescriptor(ProtoTy, /*ForEH=*/true);
- llvm::Constant *FTRTTIConstEncoded =
- EncodeAddrForUseInPrologue(Fn, FTRTTIConst);
- llvm::Constant *PrologueStructElems[] = {PrologueSig,
- FTRTTIConstEncoded};
- llvm::Constant *PrologueStructConst =
- llvm::ConstantStruct::getAnon(PrologueStructElems, /*Packed=*/true);
- Fn->setPrologueData(PrologueStructConst);
- }
- }
- }
-
- // If we're checking nullability, we need to know whether we can check the
- // return value. Initialize the flag to 'true' and refine it in EmitParmDecl.
- if (SanOpts.has(SanitizerKind::NullabilityReturn)) {
- auto Nullability = FnRetTy->getNullability(getContext());
- if (Nullability && *Nullability == NullabilityKind::NonNull) {
- if (!(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
- CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>()))
- RetValNullabilityPrecondition =
- llvm::ConstantInt::getTrue(getLLVMContext());
- }
- }
-
- // If we're in C++ mode and the function name is "main", it is guaranteed
- // to be norecurse by the standard (3.6.1.3 "The function main shall not be
- // used within a program").
- if (getLangOpts().CPlusPlus)
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- if (FD->isMain())
- Fn->addFnAttr(llvm::Attribute::NoRecurse);
-
- // If a custom alignment is used, force realigning to this alignment on
- // any main function which certainly will need it.
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- if ((FD->isMain() || FD->isMSVCRTEntryPoint()) &&
- CGM.getCodeGenOpts().StackAlignment)
- Fn->addFnAttr("stackrealign");
-
- llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
-
- // Create a marker to make it easy to insert allocas into the entryblock
- // later. Don't create this with the builder, because we don't want it
- // folded.
- llvm::Value *Undef = llvm::UndefValue::get(Int32Ty);
- AllocaInsertPt = new llvm::BitCastInst(Undef, Int32Ty, "allocapt", EntryBB);
-
- ReturnBlock = getJumpDestInCurrentScope("return");
-
- Builder.SetInsertPoint(EntryBB);
-
- // If we're checking the return value, allocate space for a pointer to a
- // precise source location of the checked return statement.
- if (requiresReturnValueCheck()) {
- ReturnLocation = CreateDefaultAlignTempAlloca(Int8PtrTy, "return.sloc.ptr");
- InitTempAlloca(ReturnLocation, llvm::ConstantPointerNull::get(Int8PtrTy));
- }
-
- // Emit subprogram debug descriptor.
- if (CGDebugInfo *DI = getDebugInfo()) {
- // Reconstruct the type from the argument list so that implicit parameters,
- // such as 'this' and 'vtt', show up in the debug info. Preserve the calling
- // convention.
- CallingConv CC = CallingConv::CC_C;
- if (auto *FD = dyn_cast_or_null<FunctionDecl>(D))
- if (const auto *SrcFnTy = FD->getType()->getAs<FunctionType>())
- CC = SrcFnTy->getCallConv();
- SmallVector<QualType, 16> ArgTypes;
- for (const VarDecl *VD : Args)
- ArgTypes.push_back(VD->getType());
- QualType FnType = getContext().getFunctionType(
- RetTy, ArgTypes, FunctionProtoType::ExtProtoInfo(CC));
- DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, CurFuncIsThunk,
- Builder);
- }
-
- if (ShouldInstrumentFunction()) {
- if (CGM.getCodeGenOpts().InstrumentFunctions)
- CurFn->addFnAttr("instrument-function-entry", "__cyg_profile_func_enter");
- if (CGM.getCodeGenOpts().InstrumentFunctionsAfterInlining)
- CurFn->addFnAttr("instrument-function-entry-inlined",
- "__cyg_profile_func_enter");
- if (CGM.getCodeGenOpts().InstrumentFunctionEntryBare)
- CurFn->addFnAttr("instrument-function-entry-inlined",
- "__cyg_profile_func_enter_bare");
- }
-
- // Since emitting the mcount call here impacts optimizations such as function
- // inlining, we just add an attribute to insert a mcount call in backend.
- // The attribute "counting-function" is set to mcount function name which is
- // architecture dependent.
- if (CGM.getCodeGenOpts().InstrumentForProfiling) {
- // Calls to fentry/mcount should not be generated if function has
- // the no_instrument_function attribute.
- if (!CurFuncDecl || !CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>()) {
- if (CGM.getCodeGenOpts().CallFEntry)
- Fn->addFnAttr("fentry-call", "true");
- else {
- Fn->addFnAttr("instrument-function-entry-inlined",
- getTarget().getMCountName());
- }
- }
- }
-
- if (RetTy->isVoidType()) {
- // Void type; nothing to return.
- ReturnValue = Address::invalid();
-
- // Count the implicit return.
- if (!endsWithReturn(D))
- ++NumReturnExprs;
- } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect) {
- // Indirect return; emit returned value directly into sret slot.
- // This reduces code size, and affects correctness in C++.
- auto AI = CurFn->arg_begin();
- if (CurFnInfo->getReturnInfo().isSRetAfterThis())
- ++AI;
- ReturnValue = Address(&*AI, CurFnInfo->getReturnInfo().getIndirectAlign());
- } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca &&
- !hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
- // Load the sret pointer from the argument struct and return into that.
- unsigned Idx = CurFnInfo->getReturnInfo().getInAllocaFieldIndex();
- llvm::Function::arg_iterator EI = CurFn->arg_end();
- --EI;
- llvm::Value *Addr = Builder.CreateStructGEP(nullptr, &*EI, Idx);
- Addr = Builder.CreateAlignedLoad(Addr, getPointerAlign(), "agg.result");
- ReturnValue = Address(Addr, getNaturalTypeAlignment(RetTy));
- } else {
- ReturnValue = CreateIRTemp(RetTy, "retval");
-
- // Tell the epilog emitter to autorelease the result. We do this
- // now so that various specialized functions can suppress it
- // during their IR-generation.
- if (getLangOpts().ObjCAutoRefCount &&
- !CurFnInfo->isReturnsRetained() &&
- RetTy->isObjCRetainableType())
- AutoreleaseResult = true;
- }
-
- EmitStartEHSpec(CurCodeDecl);
-
- PrologueCleanupDepth = EHStack.stable_begin();
-
- // Emit OpenMP specific initialization of the device functions.
- if (getLangOpts().OpenMP && CurCodeDecl)
- CGM.getOpenMPRuntime().emitFunctionProlog(*this, CurCodeDecl);
-
- EmitFunctionProlog(*CurFnInfo, CurFn, Args);
-
- if (D && isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) {
- CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
- if (MD->getParent()->isLambda() &&
- MD->getOverloadedOperator() == OO_Call) {
- // We're in a lambda; figure out the captures.
- MD->getParent()->getCaptureFields(LambdaCaptureFields,
- LambdaThisCaptureField);
- if (LambdaThisCaptureField) {
- // If the lambda captures the object referred to by '*this' - either by
- // value or by reference, make sure CXXThisValue points to the correct
- // object.
-
- // Get the lvalue for the field (which is a copy of the enclosing object
- // or contains the address of the enclosing object).
- LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField);
- if (!LambdaThisCaptureField->getType()->isPointerType()) {
- // If the enclosing object was captured by value, just use its address.
- CXXThisValue = ThisFieldLValue.getAddress().getPointer();
- } else {
- // Load the lvalue pointed to by the field, since '*this' was captured
- // by reference.
- CXXThisValue =
- EmitLoadOfLValue(ThisFieldLValue, SourceLocation()).getScalarVal();
- }
- }
- for (auto *FD : MD->getParent()->fields()) {
- if (FD->hasCapturedVLAType()) {
- auto *ExprArg = EmitLoadOfLValue(EmitLValueForLambdaField(FD),
- SourceLocation()).getScalarVal();
- auto VAT = FD->getCapturedVLAType();
- VLASizeMap[VAT->getSizeExpr()] = ExprArg;
- }
- }
- } else {
- // Not in a lambda; just use 'this' from the method.
- // FIXME: Should we generate a new load for each use of 'this'? The
- // fast register allocator would be happier...
- CXXThisValue = CXXABIThisValue;
- }
-
- // Check the 'this' pointer once per function, if it's available.
- if (CXXABIThisValue) {
- SanitizerSet SkippedChecks;
- SkippedChecks.set(SanitizerKind::ObjectSize, true);
- QualType ThisTy = MD->getThisType();
-
- // If this is the call operator of a lambda with no capture-default, it
- // may have a static invoker function, which may call this operator with
- // a null 'this' pointer.
- if (isLambdaCallOperator(MD) &&
- MD->getParent()->getLambdaCaptureDefault() == LCD_None)
- SkippedChecks.set(SanitizerKind::Null, true);
-
- EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
- : TCK_MemberCall,
- Loc, CXXABIThisValue, ThisTy,
- getContext().getTypeAlignInChars(ThisTy->getPointeeType()),
- SkippedChecks);
- }
- }
-
- // If any of the arguments have a variably modified type, make sure to
- // emit the type size.
- for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
- i != e; ++i) {
- const VarDecl *VD = *i;
-
- // Dig out the type as written from ParmVarDecls; it's unclear whether
- // the standard (C99 6.9.1p10) requires this, but we're following the
- // precedent set by gcc.
- QualType Ty;
- if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD))
- Ty = PVD->getOriginalType();
- else
- Ty = VD->getType();
-
- if (Ty->isVariablyModifiedType())
- EmitVariablyModifiedType(Ty);
- }
- // Emit a location at the end of the prologue.
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitLocation(Builder, StartLoc);
-
- // TODO: Do we need to handle this in two places like we do with
- // target-features/target-cpu?
- if (CurFuncDecl)
- if (const auto *VecWidth = CurFuncDecl->getAttr<MinVectorWidthAttr>())
- LargestVectorWidth = VecWidth->getVectorWidth();
-}
-
-void CodeGenFunction::EmitFunctionBody(const Stmt *Body) {
- incrementProfileCounter(Body);
- if (const CompoundStmt *S = dyn_cast<CompoundStmt>(Body))
- EmitCompoundStmtWithoutScope(*S);
- else
- EmitStmt(Body);
-}
-
-/// When instrumenting to collect profile data, the counts for some blocks
-/// such as switch cases need to not include the fall-through counts, so
-/// emit a branch around the instrumentation code. When not instrumenting,
-/// this just calls EmitBlock().
-void CodeGenFunction::EmitBlockWithFallThrough(llvm::BasicBlock *BB,
- const Stmt *S) {
- llvm::BasicBlock *SkipCountBB = nullptr;
- if (HaveInsertPoint() && CGM.getCodeGenOpts().hasProfileClangInstr()) {
- // When instrumenting for profiling, the fallthrough to certain
- // statements needs to skip over the instrumentation code so that we
- // get an accurate count.
- SkipCountBB = createBasicBlock("skipcount");
- EmitBranch(SkipCountBB);
- }
- EmitBlock(BB);
- uint64_t CurrentCount = getCurrentProfileCount();
- incrementProfileCounter(S);
- setCurrentProfileCount(getCurrentProfileCount() + CurrentCount);
- if (SkipCountBB)
- EmitBlock(SkipCountBB);
-}
-
-/// Tries to mark the given function nounwind based on the
-/// non-existence of any throwing calls within it. We believe this is
-/// lightweight enough to do at -O0.
-static void TryMarkNoThrow(llvm::Function *F) {
- // LLVM treats 'nounwind' on a function as part of the type, so we
- // can't do this on functions that can be overwritten.
- if (F->isInterposable()) return;
-
- for (llvm::BasicBlock &BB : *F)
- for (llvm::Instruction &I : BB)
- if (I.mayThrow())
- return;
-
- F->setDoesNotThrow();
-}
-
-QualType CodeGenFunction::BuildFunctionArgList(GlobalDecl GD,
- FunctionArgList &Args) {
- const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
- QualType ResTy = FD->getReturnType();
-
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
- if (MD && MD->isInstance()) {
- if (CGM.getCXXABI().HasThisReturn(GD))
- ResTy = MD->getThisType();
- else if (CGM.getCXXABI().hasMostDerivedReturn(GD))
- ResTy = CGM.getContext().VoidPtrTy;
- CGM.getCXXABI().buildThisParam(*this, Args);
- }
-
- // The base version of an inheriting constructor whose constructed base is a
- // virtual base is not passed any arguments (because it doesn't actually call
- // the inherited constructor).
- bool PassedParams = true;
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
- if (auto Inherited = CD->getInheritedConstructor())
- PassedParams =
- getTypes().inheritingCtorHasParams(Inherited, GD.getCtorType());
-
- if (PassedParams) {
- for (auto *Param : FD->parameters()) {
- Args.push_back(Param);
- if (!Param->hasAttr<PassObjectSizeAttr>())
- continue;
-
- auto *Implicit = ImplicitParamDecl::Create(
- getContext(), Param->getDeclContext(), Param->getLocation(),
- /*Id=*/nullptr, getContext().getSizeType(), ImplicitParamDecl::Other);
- SizeArguments[Param] = Implicit;
- Args.push_back(Implicit);
- }
- }
-
- if (MD && (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)))
- CGM.getCXXABI().addImplicitStructorParams(*this, ResTy, Args);
-
- return ResTy;
-}
-
-static bool
-shouldUseUndefinedBehaviorReturnOptimization(const FunctionDecl *FD,
- const ASTContext &Context) {
- QualType T = FD->getReturnType();
- // Avoid the optimization for functions that return a record type with a
- // trivial destructor or another trivially copyable type.
- if (const RecordType *RT = T.getCanonicalType()->getAs<RecordType>()) {
- if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- return !ClassDecl->hasTrivialDestructor();
- }
- return !T.isTriviallyCopyableType(Context);
-}
-
-void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
- const CGFunctionInfo &FnInfo) {
- const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
- CurGD = GD;
-
- FunctionArgList Args;
- QualType ResTy = BuildFunctionArgList(GD, Args);
-
- // Check if we should generate debug info for this function.
- if (FD->hasAttr<NoDebugAttr>())
- DebugInfo = nullptr; // disable debug info indefinitely for this function
-
- // The function might not have a body if we're generating thunks for a
- // function declaration.
- SourceRange BodyRange;
- if (Stmt *Body = FD->getBody())
- BodyRange = Body->getSourceRange();
- else
- BodyRange = FD->getLocation();
- CurEHLocation = BodyRange.getEnd();
-
- // Use the location of the start of the function to determine where
- // the function definition is located. By default use the location
- // of the declaration as the location for the subprogram. A function
- // may lack a declaration in the source code if it is created by code
- // gen. (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
- SourceLocation Loc = FD->getLocation();
-
- // If this is a function specialization then use the pattern body
- // as the location for the function.
- if (const FunctionDecl *SpecDecl = FD->getTemplateInstantiationPattern())
- if (SpecDecl->hasBody(SpecDecl))
- Loc = SpecDecl->getLocation();
-
- Stmt *Body = FD->getBody();
-
- // Initialize helper which will detect jumps which can cause invalid lifetime
- // markers.
- if (Body && ShouldEmitLifetimeMarkers)
- Bypasses.Init(Body);
-
- // Emit the standard function prologue.
- StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
-
- // Generate the body of the function.
- PGO.assignRegionCounters(GD, CurFn);
- if (isa<CXXDestructorDecl>(FD))
- EmitDestructorBody(Args);
- else if (isa<CXXConstructorDecl>(FD))
- EmitConstructorBody(Args);
- else if (getLangOpts().CUDA &&
- !getLangOpts().CUDAIsDevice &&
- FD->hasAttr<CUDAGlobalAttr>())
- CGM.getCUDARuntime().emitDeviceStub(*this, Args);
- else if (isa<CXXMethodDecl>(FD) &&
- cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
- // The lambda static invoker function is special, because it forwards or
- // clones the body of the function call operator (but is actually static).
- EmitLambdaStaticInvokeBody(cast<CXXMethodDecl>(FD));
- } else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
- (cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator() ||
- cast<CXXMethodDecl>(FD)->isMoveAssignmentOperator())) {
- // Implicit copy-assignment gets the same special treatment as implicit
- // copy-constructors.
- emitImplicitAssignmentOperatorBody(Args);
- } else if (Body) {
- EmitFunctionBody(Body);
- } else
- llvm_unreachable("no definition for emitted function");
-
- // C++11 [stmt.return]p2:
- // Flowing off the end of a function [...] results in undefined behavior in
- // a value-returning function.
- // C11 6.9.1p12:
- // If the '}' that terminates a function is reached, and the value of the
- // function call is used by the caller, the behavior is undefined.
- if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && !SawAsmBlock &&
- !FD->getReturnType()->isVoidType() && Builder.GetInsertBlock()) {
- bool ShouldEmitUnreachable =
- CGM.getCodeGenOpts().StrictReturn ||
- shouldUseUndefinedBehaviorReturnOptimization(FD, getContext());
- if (SanOpts.has(SanitizerKind::Return)) {
- SanitizerScope SanScope(this);
- llvm::Value *IsFalse = Builder.getFalse();
- EmitCheck(std::make_pair(IsFalse, SanitizerKind::Return),
- SanitizerHandler::MissingReturn,
- EmitCheckSourceLocation(FD->getLocation()), None);
- } else if (ShouldEmitUnreachable) {
- if (CGM.getCodeGenOpts().OptimizationLevel == 0)
- EmitTrapCall(llvm::Intrinsic::trap);
- }
- if (SanOpts.has(SanitizerKind::Return) || ShouldEmitUnreachable) {
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
- }
- }
-
- // Emit the standard function epilogue.
- FinishFunction(BodyRange.getEnd());
-
- // If we haven't marked the function nothrow through other means, do
- // a quick pass now to see if we can.
- if (!CurFn->doesNotThrow())
- TryMarkNoThrow(CurFn);
-}
-
-/// ContainsLabel - Return true if the statement contains a label in it. If
-/// this statement is not executed normally, it not containing a label means
-/// that we can just remove the code.
-bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
- // Null statement, not a label!
- if (!S) return false;
-
- // If this is a label, we have to emit the code, consider something like:
- // if (0) { ... foo: bar(); } goto foo;
- //
- // TODO: If anyone cared, we could track __label__'s, since we know that you
- // can't jump to one from outside their declared region.
- if (isa<LabelStmt>(S))
- return true;
-
- // If this is a case/default statement, and we haven't seen a switch, we have
- // to emit the code.
- if (isa<SwitchCase>(S) && !IgnoreCaseStmts)
- return true;
-
- // If this is a switch statement, we want to ignore cases below it.
- if (isa<SwitchStmt>(S))
- IgnoreCaseStmts = true;
-
- // Scan subexpressions for verboten labels.
- for (const Stmt *SubStmt : S->children())
- if (ContainsLabel(SubStmt, IgnoreCaseStmts))
- return true;
-
- return false;
-}
-
-/// containsBreak - Return true if the statement contains a break out of it.
-/// If the statement (recursively) contains a switch or loop with a break
-/// inside of it, this is fine.
-bool CodeGenFunction::containsBreak(const Stmt *S) {
- // Null statement, not a label!
- if (!S) return false;
-
- // If this is a switch or loop that defines its own break scope, then we can
- // include it and anything inside of it.
- if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S) ||
- isa<ForStmt>(S))
- return false;
-
- if (isa<BreakStmt>(S))
- return true;
-
- // Scan subexpressions for verboten breaks.
- for (const Stmt *SubStmt : S->children())
- if (containsBreak(SubStmt))
- return true;
-
- return false;
-}
-
-bool CodeGenFunction::mightAddDeclToScope(const Stmt *S) {
- if (!S) return false;
-
- // Some statement kinds add a scope and thus never add a decl to the current
- // scope. Note, this list is longer than the list of statements that might
- // have an unscoped decl nested within them, but this way is conservatively
- // correct even if more statement kinds are added.
- if (isa<IfStmt>(S) || isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
- isa<DoStmt>(S) || isa<ForStmt>(S) || isa<CompoundStmt>(S) ||
- isa<CXXForRangeStmt>(S) || isa<CXXTryStmt>(S) ||
- isa<ObjCForCollectionStmt>(S) || isa<ObjCAtTryStmt>(S))
- return false;
-
- if (isa<DeclStmt>(S))
- return true;
-
- for (const Stmt *SubStmt : S->children())
- if (mightAddDeclToScope(SubStmt))
- return true;
-
- return false;
-}
-
-/// ConstantFoldsToSimpleInteger - If the specified expression does not fold
-/// to a constant, or if it does but contains a label, return false. If it
-/// constant folds return true and set the boolean result in Result.
-bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
- bool &ResultBool,
- bool AllowLabels) {
- llvm::APSInt ResultInt;
- if (!ConstantFoldsToSimpleInteger(Cond, ResultInt, AllowLabels))
- return false;
-
- ResultBool = ResultInt.getBoolValue();
- return true;
-}
-
-/// ConstantFoldsToSimpleInteger - If the specified expression does not fold
-/// to a constant, or if it does but contains a label, return false. If it
-/// constant folds return true and set the folded value.
-bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
- llvm::APSInt &ResultInt,
- bool AllowLabels) {
- // FIXME: Rename and handle conversion of other evaluatable things
- // to bool.
- Expr::EvalResult Result;
- if (!Cond->EvaluateAsInt(Result, getContext()))
- return false; // Not foldable, not integer or not fully evaluatable.
-
- llvm::APSInt Int = Result.Val.getInt();
- if (!AllowLabels && CodeGenFunction::ContainsLabel(Cond))
- return false; // Contains a label.
-
- ResultInt = Int;
- return true;
-}
-
-
-
-/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if
-/// statement) to the specified blocks. Based on the condition, this might try
-/// to simplify the codegen of the conditional based on the branch.
-///
-void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
- llvm::BasicBlock *TrueBlock,
- llvm::BasicBlock *FalseBlock,
- uint64_t TrueCount) {
- Cond = Cond->IgnoreParens();
-
- if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
-
- // Handle X && Y in a condition.
- if (CondBOp->getOpcode() == BO_LAnd) {
- // If we have "1 && X", simplify the code. "0 && X" would have constant
- // folded if the case was simple enough.
- bool ConstantBool = false;
- if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
- ConstantBool) {
- // br(1 && X) -> br(X).
- incrementProfileCounter(CondBOp);
- return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
- TrueCount);
- }
-
- // If we have "X && 1", simplify the code to use an uncond branch.
- // "X && 0" would have been constant folded to 0.
- if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
- ConstantBool) {
- // br(X && 1) -> br(X).
- return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
- TrueCount);
- }
-
- // Emit the LHS as a conditional. If the LHS conditional is false, we
- // want to jump to the FalseBlock.
- llvm::BasicBlock *LHSTrue = createBasicBlock("land.lhs.true");
- // The counter tells us how often we evaluate RHS, and all of TrueCount
- // can be propagated to that branch.
- uint64_t RHSCount = getProfileCount(CondBOp->getRHS());
-
- ConditionalEvaluation eval(*this);
- {
- ApplyDebugLocation DL(*this, Cond);
- EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock, RHSCount);
- EmitBlock(LHSTrue);
- }
-
- incrementProfileCounter(CondBOp);
- setCurrentProfileCount(getProfileCount(CondBOp->getRHS()));
-
- // Any temporaries created here are conditional.
- eval.begin(*this);
- EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, TrueCount);
- eval.end(*this);
-
- return;
- }
-
- if (CondBOp->getOpcode() == BO_LOr) {
- // If we have "0 || X", simplify the code. "1 || X" would have constant
- // folded if the case was simple enough.
- bool ConstantBool = false;
- if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
- !ConstantBool) {
- // br(0 || X) -> br(X).
- incrementProfileCounter(CondBOp);
- return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
- TrueCount);
- }
-
- // If we have "X || 0", simplify the code to use an uncond branch.
- // "X || 1" would have been constant folded to 1.
- if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
- !ConstantBool) {
- // br(X || 0) -> br(X).
- return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
- TrueCount);
- }
-
- // Emit the LHS as a conditional. If the LHS conditional is true, we
- // want to jump to the TrueBlock.
- llvm::BasicBlock *LHSFalse = createBasicBlock("lor.lhs.false");
- // We have the count for entry to the RHS and for the whole expression
- // being true, so we can divy up True count between the short circuit and
- // the RHS.
- uint64_t LHSCount =
- getCurrentProfileCount() - getProfileCount(CondBOp->getRHS());
- uint64_t RHSCount = TrueCount - LHSCount;
-
- ConditionalEvaluation eval(*this);
- {
- ApplyDebugLocation DL(*this, Cond);
- EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse, LHSCount);
- EmitBlock(LHSFalse);
- }
-
- incrementProfileCounter(CondBOp);
- setCurrentProfileCount(getProfileCount(CondBOp->getRHS()));
-
- // Any temporaries created here are conditional.
- eval.begin(*this);
- EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, RHSCount);
-
- eval.end(*this);
-
- return;
- }
- }
-
- if (const UnaryOperator *CondUOp = dyn_cast<UnaryOperator>(Cond)) {
- // br(!x, t, f) -> br(x, f, t)
- if (CondUOp->getOpcode() == UO_LNot) {
- // Negate the count.
- uint64_t FalseCount = getCurrentProfileCount() - TrueCount;
- // Negate the condition and swap the destination blocks.
- return EmitBranchOnBoolExpr(CondUOp->getSubExpr(), FalseBlock, TrueBlock,
- FalseCount);
- }
- }
-
- if (const ConditionalOperator *CondOp = dyn_cast<ConditionalOperator>(Cond)) {
- // br(c ? x : y, t, f) -> br(c, br(x, t, f), br(y, t, f))
- llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
- llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
-
- ConditionalEvaluation cond(*this);
- EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock,
- getProfileCount(CondOp));
-
- // When computing PGO branch weights, we only know the overall count for
- // the true block. This code is essentially doing tail duplication of the
- // naive code-gen, introducing new edges for which counts are not
- // available. Divide the counts proportionally between the LHS and RHS of
- // the conditional operator.
- uint64_t LHSScaledTrueCount = 0;
- if (TrueCount) {
- double LHSRatio =
- getProfileCount(CondOp) / (double)getCurrentProfileCount();
- LHSScaledTrueCount = TrueCount * LHSRatio;
- }
-
- cond.begin(*this);
- EmitBlock(LHSBlock);
- incrementProfileCounter(CondOp);
- {
- ApplyDebugLocation DL(*this, Cond);
- EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock,
- LHSScaledTrueCount);
- }
- cond.end(*this);
-
- cond.begin(*this);
- EmitBlock(RHSBlock);
- EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock,
- TrueCount - LHSScaledTrueCount);
- cond.end(*this);
-
- return;
- }
-
- if (const CXXThrowExpr *Throw = dyn_cast<CXXThrowExpr>(Cond)) {
- // Conditional operator handling can give us a throw expression as a
- // condition for a case like:
- // br(c ? throw x : y, t, f) -> br(c, br(throw x, t, f), br(y, t, f)
- // Fold this to:
- // br(c, throw x, br(y, t, f))
- EmitCXXThrowExpr(Throw, /*KeepInsertionPoint*/false);
- return;
- }
-
- // If the branch has a condition wrapped by __builtin_unpredictable,
- // create metadata that specifies that the branch is unpredictable.
- // Don't bother if not optimizing because that metadata would not be used.
- llvm::MDNode *Unpredictable = nullptr;
- auto *Call = dyn_cast<CallExpr>(Cond->IgnoreImpCasts());
- if (Call && CGM.getCodeGenOpts().OptimizationLevel != 0) {
- auto *FD = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
- if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable) {
- llvm::MDBuilder MDHelper(getLLVMContext());
- Unpredictable = MDHelper.createUnpredictable();
- }
- }
-
- // Create branch weights based on the number of times we get here and the
- // number of times the condition should be true.
- uint64_t CurrentCount = std::max(getCurrentProfileCount(), TrueCount);
- llvm::MDNode *Weights =
- createProfileWeights(TrueCount, CurrentCount - TrueCount);
-
- // Emit the code with the fully general case.
- llvm::Value *CondV;
- {
- ApplyDebugLocation DL(*this, Cond);
- CondV = EvaluateExprAsBool(Cond);
- }
- Builder.CreateCondBr(CondV, TrueBlock, FalseBlock, Weights, Unpredictable);
-}
-
-/// ErrorUnsupported - Print out an error that codegen doesn't support the
-/// specified stmt yet.
-void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type) {
- CGM.ErrorUnsupported(S, Type);
-}
-
-/// emitNonZeroVLAInit - Emit the "zero" initialization of a
-/// variable-length array whose elements have a non-zero bit-pattern.
-///
-/// \param baseType the inner-most element type of the array
-/// \param src - a char* pointing to the bit-pattern for a single
-/// base element of the array
-/// \param sizeInChars - the total size of the VLA, in chars
-static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
- Address dest, Address src,
- llvm::Value *sizeInChars) {
- CGBuilderTy &Builder = CGF.Builder;
-
- CharUnits baseSize = CGF.getContext().getTypeSizeInChars(baseType);
- llvm::Value *baseSizeInChars
- = llvm::ConstantInt::get(CGF.IntPtrTy, baseSize.getQuantity());
-
- Address begin =
- Builder.CreateElementBitCast(dest, CGF.Int8Ty, "vla.begin");
- llvm::Value *end =
- Builder.CreateInBoundsGEP(begin.getPointer(), sizeInChars, "vla.end");
-
- llvm::BasicBlock *originBB = CGF.Builder.GetInsertBlock();
- llvm::BasicBlock *loopBB = CGF.createBasicBlock("vla-init.loop");
- llvm::BasicBlock *contBB = CGF.createBasicBlock("vla-init.cont");
-
- // Make a loop over the VLA. C99 guarantees that the VLA element
- // count must be nonzero.
- CGF.EmitBlock(loopBB);
-
- llvm::PHINode *cur = Builder.CreatePHI(begin.getType(), 2, "vla.cur");
- cur->addIncoming(begin.getPointer(), originBB);
-
- CharUnits curAlign =
- dest.getAlignment().alignmentOfArrayElement(baseSize);
-
- // memcpy the individual element bit-pattern.
- Builder.CreateMemCpy(Address(cur, curAlign), src, baseSizeInChars,
- /*volatile*/ false);
-
- // Go to the next element.
- llvm::Value *next =
- Builder.CreateInBoundsGEP(CGF.Int8Ty, cur, baseSizeInChars, "vla.next");
-
- // Leave if that's the end of the VLA.
- llvm::Value *done = Builder.CreateICmpEQ(next, end, "vla-init.isdone");
- Builder.CreateCondBr(done, contBB, loopBB);
- cur->addIncoming(next, loopBB);
-
- CGF.EmitBlock(contBB);
-}
-
-void
-CodeGenFunction::EmitNullInitialization(Address DestPtr, QualType Ty) {
- // Ignore empty classes in C++.
- if (getLangOpts().CPlusPlus) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
- return;
- }
- }
-
- // Cast the dest ptr to the appropriate i8 pointer type.
- if (DestPtr.getElementType() != Int8Ty)
- DestPtr = Builder.CreateElementBitCast(DestPtr, Int8Ty);
-
- // Get size and alignment info for this aggregate.
- CharUnits size = getContext().getTypeSizeInChars(Ty);
-
- llvm::Value *SizeVal;
- const VariableArrayType *vla;
-
- // Don't bother emitting a zero-byte memset.
- if (size.isZero()) {
- // But note that getTypeInfo returns 0 for a VLA.
- if (const VariableArrayType *vlaType =
- dyn_cast_or_null<VariableArrayType>(
- getContext().getAsArrayType(Ty))) {
- auto VlaSize = getVLASize(vlaType);
- SizeVal = VlaSize.NumElts;
- CharUnits eltSize = getContext().getTypeSizeInChars(VlaSize.Type);
- if (!eltSize.isOne())
- SizeVal = Builder.CreateNUWMul(SizeVal, CGM.getSize(eltSize));
- vla = vlaType;
- } else {
- return;
- }
- } else {
- SizeVal = CGM.getSize(size);
- vla = nullptr;
- }
-
- // If the type contains a pointer to data member we can't memset it to zero.
- // Instead, create a null constant and copy it to the destination.
- // TODO: there are other patterns besides zero that we can usefully memset,
- // like -1, which happens to be the pattern used by member-pointers.
- if (!CGM.getTypes().isZeroInitializable(Ty)) {
- // For a VLA, emit a single element, then splat that over the VLA.
- if (vla) Ty = getContext().getBaseElementType(vla);
-
- llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty);
-
- llvm::GlobalVariable *NullVariable =
- new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(),
- /*isConstant=*/true,
- llvm::GlobalVariable::PrivateLinkage,
- NullConstant, Twine());
- CharUnits NullAlign = DestPtr.getAlignment();
- NullVariable->setAlignment(NullAlign.getQuantity());
- Address SrcPtr(Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy()),
- NullAlign);
-
- if (vla) return emitNonZeroVLAInit(*this, Ty, DestPtr, SrcPtr, SizeVal);
-
- // Get and call the appropriate llvm.memcpy overload.
- Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, false);
- return;
- }
-
- // Otherwise, just memset the whole thing to zero. This is legal
- // because in LLVM, all default initializers (other than the ones we just
- // handled above) are guaranteed to have a bit pattern of all zeros.
- Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, false);
-}
-
-llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
- // Make sure that there is a block for the indirect goto.
- if (!IndirectBranch)
- GetIndirectGotoBlock();
-
- llvm::BasicBlock *BB = getJumpDestForLabel(L).getBlock();
-
- // Make sure the indirect branch includes all of the address-taken blocks.
- IndirectBranch->addDestination(BB);
- return llvm::BlockAddress::get(CurFn, BB);
-}
-
-llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
- // If we already made the indirect branch for indirect goto, return its block.
- if (IndirectBranch) return IndirectBranch->getParent();
-
- CGBuilderTy TmpBuilder(*this, createBasicBlock("indirectgoto"));
-
- // Create the PHI node that indirect gotos will add entries to.
- llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, 0,
- "indirect.goto.dest");
-
- // Create the indirect branch instruction.
- IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal);
- return IndirectBranch->getParent();
-}
-
-/// Computes the length of an array in elements, as well as the base
-/// element type and a properly-typed first element pointer.
-llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
- QualType &baseType,
- Address &addr) {
- const ArrayType *arrayType = origArrayType;
-
- // If it's a VLA, we have to load the stored size. Note that
- // this is the size of the VLA in bytes, not its size in elements.
- llvm::Value *numVLAElements = nullptr;
- if (isa<VariableArrayType>(arrayType)) {
- numVLAElements = getVLASize(cast<VariableArrayType>(arrayType)).NumElts;
-
- // Walk into all VLAs. This doesn't require changes to addr,
- // which has type T* where T is the first non-VLA element type.
- do {
- QualType elementType = arrayType->getElementType();
- arrayType = getContext().getAsArrayType(elementType);
-
- // If we only have VLA components, 'addr' requires no adjustment.
- if (!arrayType) {
- baseType = elementType;
- return numVLAElements;
- }
- } while (isa<VariableArrayType>(arrayType));
-
- // We get out here only if we find a constant array type
- // inside the VLA.
- }
-
- // We have some number of constant-length arrays, so addr should
- // have LLVM type [M x [N x [...]]]*. Build a GEP that walks
- // down to the first element of addr.
- SmallVector<llvm::Value*, 8> gepIndices;
-
- // GEP down to the array type.
- llvm::ConstantInt *zero = Builder.getInt32(0);
- gepIndices.push_back(zero);
-
- uint64_t countFromCLAs = 1;
- QualType eltType;
-
- llvm::ArrayType *llvmArrayType =
- dyn_cast<llvm::ArrayType>(addr.getElementType());
- while (llvmArrayType) {
- assert(isa<ConstantArrayType>(arrayType));
- assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue()
- == llvmArrayType->getNumElements());
-
- gepIndices.push_back(zero);
- countFromCLAs *= llvmArrayType->getNumElements();
- eltType = arrayType->getElementType();
-
- llvmArrayType =
- dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType());
- arrayType = getContext().getAsArrayType(arrayType->getElementType());
- assert((!llvmArrayType || arrayType) &&
- "LLVM and Clang types are out-of-synch");
- }
-
- if (arrayType) {
- // From this point onwards, the Clang array type has been emitted
- // as some other type (probably a packed struct). Compute the array
- // size, and just emit the 'begin' expression as a bitcast.
- while (arrayType) {
- countFromCLAs *=
- cast<ConstantArrayType>(arrayType)->getSize().getZExtValue();
- eltType = arrayType->getElementType();
- arrayType = getContext().getAsArrayType(eltType);
- }
-
- llvm::Type *baseType = ConvertType(eltType);
- addr = Builder.CreateElementBitCast(addr, baseType, "array.begin");
- } else {
- // Create the actual GEP.
- addr = Address(Builder.CreateInBoundsGEP(addr.getPointer(),
- gepIndices, "array.begin"),
- addr.getAlignment());
- }
-
- baseType = eltType;
-
- llvm::Value *numElements
- = llvm::ConstantInt::get(SizeTy, countFromCLAs);
-
- // If we had any VLA dimensions, factor them in.
- if (numVLAElements)
- numElements = Builder.CreateNUWMul(numVLAElements, numElements);
-
- return numElements;
-}
-
-CodeGenFunction::VlaSizePair CodeGenFunction::getVLASize(QualType type) {
- const VariableArrayType *vla = getContext().getAsVariableArrayType(type);
- assert(vla && "type was not a variable array type!");
- return getVLASize(vla);
-}
-
-CodeGenFunction::VlaSizePair
-CodeGenFunction::getVLASize(const VariableArrayType *type) {
- // The number of elements so far; always size_t.
- llvm::Value *numElements = nullptr;
-
- QualType elementType;
- do {
- elementType = type->getElementType();
- llvm::Value *vlaSize = VLASizeMap[type->getSizeExpr()];
- assert(vlaSize && "no size for VLA!");
- assert(vlaSize->getType() == SizeTy);
-
- if (!numElements) {
- numElements = vlaSize;
- } else {
- // It's undefined behavior if this wraps around, so mark it that way.
- // FIXME: Teach -fsanitize=undefined to trap this.
- numElements = Builder.CreateNUWMul(numElements, vlaSize);
- }
- } while ((type = getContext().getAsVariableArrayType(elementType)));
-
- return { numElements, elementType };
-}
-
-CodeGenFunction::VlaSizePair
-CodeGenFunction::getVLAElements1D(QualType type) {
- const VariableArrayType *vla = getContext().getAsVariableArrayType(type);
- assert(vla && "type was not a variable array type!");
- return getVLAElements1D(vla);
-}
-
-CodeGenFunction::VlaSizePair
-CodeGenFunction::getVLAElements1D(const VariableArrayType *Vla) {
- llvm::Value *VlaSize = VLASizeMap[Vla->getSizeExpr()];
- assert(VlaSize && "no size for VLA!");
- assert(VlaSize->getType() == SizeTy);
- return { VlaSize, Vla->getElementType() };
-}
-
-void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
- assert(type->isVariablyModifiedType() &&
- "Must pass variably modified type to EmitVLASizes!");
-
- EnsureInsertPoint();
-
- // We're going to walk down into the type and look for VLA
- // expressions.
- do {
- assert(type->isVariablyModifiedType());
-
- const Type *ty = type.getTypePtr();
- switch (ty->getTypeClass()) {
-
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base)
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("unexpected dependent type!");
-
- // These types are never variably-modified.
- case Type::Builtin:
- case Type::Complex:
- case Type::Vector:
- case Type::ExtVector:
- case Type::Record:
- case Type::Enum:
- case Type::Elaborated:
- case Type::TemplateSpecialization:
- case Type::ObjCTypeParam:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- case Type::ObjCObjectPointer:
- llvm_unreachable("type class is never variably-modified!");
-
- case Type::Adjusted:
- type = cast<AdjustedType>(ty)->getAdjustedType();
- break;
-
- case Type::Decayed:
- type = cast<DecayedType>(ty)->getPointeeType();
- break;
-
- case Type::Pointer:
- type = cast<PointerType>(ty)->getPointeeType();
- break;
-
- case Type::BlockPointer:
- type = cast<BlockPointerType>(ty)->getPointeeType();
- break;
-
- case Type::LValueReference:
- case Type::RValueReference:
- type = cast<ReferenceType>(ty)->getPointeeType();
- break;
-
- case Type::MemberPointer:
- type = cast<MemberPointerType>(ty)->getPointeeType();
- break;
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- // Losing element qualification here is fine.
- type = cast<ArrayType>(ty)->getElementType();
- break;
-
- case Type::VariableArray: {
- // Losing element qualification here is fine.
- const VariableArrayType *vat = cast<VariableArrayType>(ty);
-
- // Unknown size indication requires no size computation.
- // Otherwise, evaluate and record it.
- if (const Expr *size = vat->getSizeExpr()) {
- // It's possible that we might have emitted this already,
- // e.g. with a typedef and a pointer to it.
- llvm::Value *&entry = VLASizeMap[size];
- if (!entry) {
- llvm::Value *Size = EmitScalarExpr(size);
-
- // C11 6.7.6.2p5:
- // If the size is an expression that is not an integer constant
- // expression [...] each time it is evaluated it shall have a value
- // greater than zero.
- if (SanOpts.has(SanitizerKind::VLABound) &&
- size->getType()->isSignedIntegerType()) {
- SanitizerScope SanScope(this);
- llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
- llvm::Constant *StaticArgs[] = {
- EmitCheckSourceLocation(size->getBeginLoc()),
- EmitCheckTypeDescriptor(size->getType())};
- EmitCheck(std::make_pair(Builder.CreateICmpSGT(Size, Zero),
- SanitizerKind::VLABound),
- SanitizerHandler::VLABoundNotPositive, StaticArgs, Size);
- }
-
- // Always zexting here would be wrong if it weren't
- // undefined behavior to have a negative bound.
- entry = Builder.CreateIntCast(Size, SizeTy, /*signed*/ false);
- }
- }
- type = vat->getElementType();
- break;
- }
-
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- type = cast<FunctionType>(ty)->getReturnType();
- break;
-
- case Type::Paren:
- case Type::TypeOf:
- case Type::UnaryTransform:
- case Type::Attributed:
- case Type::SubstTemplateTypeParm:
- case Type::PackExpansion:
- // Keep walking after single level desugaring.
- type = type.getSingleStepDesugaredType(getContext());
- break;
-
- case Type::Typedef:
- case Type::Decltype:
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- // Stop walking: nothing to do.
- return;
-
- case Type::TypeOfExpr:
- // Stop walking: emit typeof expression.
- EmitIgnoredExpr(cast<TypeOfExprType>(ty)->getUnderlyingExpr());
- return;
-
- case Type::Atomic:
- type = cast<AtomicType>(ty)->getValueType();
- break;
-
- case Type::Pipe:
- type = cast<PipeType>(ty)->getElementType();
- break;
- }
- } while (type->isVariablyModifiedType());
-}
-
-Address CodeGenFunction::EmitVAListRef(const Expr* E) {
- if (getContext().getBuiltinVaListType()->isArrayType())
- return EmitPointerWithAlignment(E);
- return EmitLValue(E).getAddress();
-}
-
-Address CodeGenFunction::EmitMSVAListRef(const Expr *E) {
- return EmitLValue(E).getAddress();
-}
-
-void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
- const APValue &Init) {
- assert(!Init.isUninit() && "Invalid DeclRefExpr initializer!");
- if (CGDebugInfo *Dbg = getDebugInfo())
- if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo)
- Dbg->EmitGlobalVariable(E->getDecl(), Init);
-}
-
-CodeGenFunction::PeepholeProtection
-CodeGenFunction::protectFromPeepholes(RValue rvalue) {
- // At the moment, the only aggressive peephole we do in IR gen
- // is trunc(zext) folding, but if we add more, we can easily
- // extend this protection.
-
- if (!rvalue.isScalar()) return PeepholeProtection();
- llvm::Value *value = rvalue.getScalarVal();
- if (!isa<llvm::ZExtInst>(value)) return PeepholeProtection();
-
- // Just make an extra bitcast.
- assert(HaveInsertPoint());
- llvm::Instruction *inst = new llvm::BitCastInst(value, value->getType(), "",
- Builder.GetInsertBlock());
-
- PeepholeProtection protection;
- protection.Inst = inst;
- return protection;
-}
-
-void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) {
- if (!protection.Inst) return;
-
- // In theory, we could try to duplicate the peepholes now, but whatever.
- protection.Inst->eraseFromParent();
-}
-
-void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
- QualType Ty, SourceLocation Loc,
- SourceLocation AssumptionLoc,
- llvm::Value *Alignment,
- llvm::Value *OffsetValue) {
- llvm::Value *TheCheck;
- llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption(
- CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck);
- if (SanOpts.has(SanitizerKind::Alignment)) {
- EmitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, Alignment,
- OffsetValue, TheCheck, Assumption);
- }
-}
-
-void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
- QualType Ty, SourceLocation Loc,
- SourceLocation AssumptionLoc,
- unsigned Alignment,
- llvm::Value *OffsetValue) {
- llvm::Value *TheCheck;
- llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption(
- CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck);
- if (SanOpts.has(SanitizerKind::Alignment)) {
- llvm::Value *AlignmentVal = llvm::ConstantInt::get(IntPtrTy, Alignment);
- EmitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, AlignmentVal,
- OffsetValue, TheCheck, Assumption);
- }
-}
-
-void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
- const Expr *E,
- SourceLocation AssumptionLoc,
- unsigned Alignment,
- llvm::Value *OffsetValue) {
- if (auto *CE = dyn_cast<CastExpr>(E))
- E = CE->getSubExprAsWritten();
- QualType Ty = E->getType();
- SourceLocation Loc = E->getExprLoc();
-
- EmitAlignmentAssumption(PtrValue, Ty, Loc, AssumptionLoc, Alignment,
- OffsetValue);
-}
-
-llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Value *AnnotationFn,
- llvm::Value *AnnotatedVal,
- StringRef AnnotationStr,
- SourceLocation Location) {
- llvm::Value *Args[4] = {
- AnnotatedVal,
- Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy),
- Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy),
- CGM.EmitAnnotationLineNo(Location)
- };
- return Builder.CreateCall(AnnotationFn, Args);
-}
-
-void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) {
- assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
- // FIXME We create a new bitcast for every annotation because that's what
- // llvm-gcc was doing.
- for (const auto *I : D->specific_attrs<AnnotateAttr>())
- EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation),
- Builder.CreateBitCast(V, CGM.Int8PtrTy, V->getName()),
- I->getAnnotation(), D->getLocation());
-}
-
-Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
- Address Addr) {
- assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
- llvm::Value *V = Addr.getPointer();
- llvm::Type *VTy = V->getType();
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation,
- CGM.Int8PtrTy);
-
- for (const auto *I : D->specific_attrs<AnnotateAttr>()) {
- // FIXME Always emit the cast inst so we can differentiate between
- // annotation on the first field of a struct and annotation on the struct
- // itself.
- if (VTy != CGM.Int8PtrTy)
- V = Builder.CreateBitCast(V, CGM.Int8PtrTy);
- V = EmitAnnotationCall(F, V, I->getAnnotation(), D->getLocation());
- V = Builder.CreateBitCast(V, VTy);
- }
-
- return Address(V, Addr.getAlignment());
-}
-
-CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() { }
-
-CodeGenFunction::SanitizerScope::SanitizerScope(CodeGenFunction *CGF)
- : CGF(CGF) {
- assert(!CGF->IsSanitizerScope);
- CGF->IsSanitizerScope = true;
-}
-
-CodeGenFunction::SanitizerScope::~SanitizerScope() {
- CGF->IsSanitizerScope = false;
-}
-
-void CodeGenFunction::InsertHelper(llvm::Instruction *I,
- const llvm::Twine &Name,
- llvm::BasicBlock *BB,
- llvm::BasicBlock::iterator InsertPt) const {
- LoopStack.InsertHelper(I);
- if (IsSanitizerScope)
- CGM.getSanitizerMetadata()->disableSanitizerForInstruction(I);
-}
-
-void CGBuilderInserter::InsertHelper(
- llvm::Instruction *I, const llvm::Twine &Name, llvm::BasicBlock *BB,
- llvm::BasicBlock::iterator InsertPt) const {
- llvm::IRBuilderDefaultInserter::InsertHelper(I, Name, BB, InsertPt);
- if (CGF)
- CGF->InsertHelper(I, Name, BB, InsertPt);
-}
-
-static bool hasRequiredFeatures(const SmallVectorImpl<StringRef> &ReqFeatures,
- CodeGenModule &CGM, const FunctionDecl *FD,
- std::string &FirstMissing) {
- // If there aren't any required features listed then go ahead and return.
- if (ReqFeatures.empty())
- return false;
-
- // Now build up the set of caller features and verify that all the required
- // features are there.
- llvm::StringMap<bool> CallerFeatureMap;
- CGM.getFunctionFeatureMap(CallerFeatureMap, GlobalDecl().getWithDecl(FD));
-
- // If we have at least one of the features in the feature list return
- // true, otherwise return false.
- return std::all_of(
- ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef Feature) {
- SmallVector<StringRef, 1> OrFeatures;
- Feature.split(OrFeatures, '|');
- return llvm::any_of(OrFeatures, [&](StringRef Feature) {
- if (!CallerFeatureMap.lookup(Feature)) {
- FirstMissing = Feature.str();
- return false;
- }
- return true;
- });
- });
-}
-
-// Emits an error if we don't have a valid set of target features for the
-// called function.
-void CodeGenFunction::checkTargetFeatures(const CallExpr *E,
- const FunctionDecl *TargetDecl) {
- // Early exit if this is an indirect call.
- if (!TargetDecl)
- return;
-
- // Get the current enclosing function if it exists. If it doesn't
- // we can't check the target features anyhow.
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl);
- if (!FD)
- return;
-
- // Grab the required features for the call. For a builtin this is listed in
- // the td file with the default cpu, for an always_inline function this is any
- // listed cpu and any listed features.
- unsigned BuiltinID = TargetDecl->getBuiltinID();
- std::string MissingFeature;
- if (BuiltinID) {
- SmallVector<StringRef, 1> ReqFeatures;
- const char *FeatureList =
- CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
- // Return if the builtin doesn't have any required features.
- if (!FeatureList || StringRef(FeatureList) == "")
- return;
- StringRef(FeatureList).split(ReqFeatures, ',');
- if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature))
- CGM.getDiags().Report(E->getBeginLoc(), diag::err_builtin_needs_feature)
- << TargetDecl->getDeclName()
- << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
-
- } else if (TargetDecl->hasAttr<TargetAttr>() ||
- TargetDecl->hasAttr<CPUSpecificAttr>()) {
- // Get the required features for the callee.
-
- const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>();
- TargetAttr::ParsedTargetAttr ParsedAttr = CGM.filterFunctionTargetAttrs(TD);
-
- SmallVector<StringRef, 1> ReqFeatures;
- llvm::StringMap<bool> CalleeFeatureMap;
- CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);
-
- for (const auto &F : ParsedAttr.Features) {
- if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1)))
- ReqFeatures.push_back(StringRef(F).substr(1));
- }
-
- for (const auto &F : CalleeFeatureMap) {
- // Only positive features are "required".
- if (F.getValue())
- ReqFeatures.push_back(F.getKey());
- }
- if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature))
- CGM.getDiags().Report(E->getBeginLoc(), diag::err_function_needs_feature)
- << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature;
- }
-}
-
-void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) {
- if (!CGM.getCodeGenOpts().SanitizeStats)
- return;
-
- llvm::IRBuilder<> IRB(Builder.GetInsertBlock(), Builder.GetInsertPoint());
- IRB.SetCurrentDebugLocation(Builder.getCurrentDebugLocation());
- CGM.getSanStats().create(IRB, SSK);
-}
-
-llvm::Value *
-CodeGenFunction::FormResolverCondition(const MultiVersionResolverOption &RO) {
- llvm::Value *Condition = nullptr;
-
- if (!RO.Conditions.Architecture.empty())
- Condition = EmitX86CpuIs(RO.Conditions.Architecture);
-
- if (!RO.Conditions.Features.empty()) {
- llvm::Value *FeatureCond = EmitX86CpuSupports(RO.Conditions.Features);
- Condition =
- Condition ? Builder.CreateAnd(Condition, FeatureCond) : FeatureCond;
- }
- return Condition;
-}
-
-static void CreateMultiVersionResolverReturn(CodeGenModule &CGM,
- llvm::Function *Resolver,
- CGBuilderTy &Builder,
- llvm::Function *FuncToReturn,
- bool SupportsIFunc) {
- if (SupportsIFunc) {
- Builder.CreateRet(FuncToReturn);
- return;
- }
-
- llvm::SmallVector<llvm::Value *, 10> Args;
- llvm::for_each(Resolver->args(),
- [&](llvm::Argument &Arg) { Args.push_back(&Arg); });
-
- llvm::CallInst *Result = Builder.CreateCall(FuncToReturn, Args);
- Result->setTailCallKind(llvm::CallInst::TCK_MustTail);
-
- if (Resolver->getReturnType()->isVoidTy())
- Builder.CreateRetVoid();
- else
- Builder.CreateRet(Result);
-}
-
-void CodeGenFunction::EmitMultiVersionResolver(
- llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
- assert((getContext().getTargetInfo().getTriple().getArch() ==
- llvm::Triple::x86 ||
- getContext().getTargetInfo().getTriple().getArch() ==
- llvm::Triple::x86_64) &&
- "Only implemented for x86 targets");
-
- bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
-
- // Main function's basic block.
- llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);
- Builder.SetInsertPoint(CurBlock);
- EmitX86CpuInit();
-
- for (const MultiVersionResolverOption &RO : Options) {
- Builder.SetInsertPoint(CurBlock);
- llvm::Value *Condition = FormResolverCondition(RO);
-
- // The 'default' or 'generic' case.
- if (!Condition) {
- assert(&RO == Options.end() - 1 &&
- "Default or Generic case must be last");
- CreateMultiVersionResolverReturn(CGM, Resolver, Builder, RO.Function,
- SupportsIFunc);
- return;
- }
-
- llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
- CGBuilderTy RetBuilder(*this, RetBlock);
- CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, RO.Function,
- SupportsIFunc);
- CurBlock = createBasicBlock("resolver_else", Resolver);
- Builder.CreateCondBr(Condition, RetBlock, CurBlock);
- }
-
- // If no generic/default, emit an unreachable.
- Builder.SetInsertPoint(CurBlock);
- llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
- TrapCall->setDoesNotReturn();
- TrapCall->setDoesNotThrow();
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
-}
-
-// Loc - where the diagnostic will point, where in the source code this
-// alignment has failed.
-// SecondaryLoc - if present (will be present if sufficiently different from
-// Loc), the diagnostic will additionally point a "Note:" to this location.
-// It should be the location where the __attribute__((assume_aligned))
-// was written e.g.
-void CodeGenFunction::EmitAlignmentAssumptionCheck(
- llvm::Value *Ptr, QualType Ty, SourceLocation Loc,
- SourceLocation SecondaryLoc, llvm::Value *Alignment,
- llvm::Value *OffsetValue, llvm::Value *TheCheck,
- llvm::Instruction *Assumption) {
- assert(Assumption && isa<llvm::CallInst>(Assumption) &&
- cast<llvm::CallInst>(Assumption)->getCalledValue() ==
- llvm::Intrinsic::getDeclaration(
- Builder.GetInsertBlock()->getParent()->getParent(),
- llvm::Intrinsic::assume) &&
- "Assumption should be a call to llvm.assume().");
- assert(&(Builder.GetInsertBlock()->back()) == Assumption &&
- "Assumption should be the last instruction of the basic block, "
- "since the basic block is still being generated.");
-
- if (!SanOpts.has(SanitizerKind::Alignment))
- return;
-
- // Don't check pointers to volatile data. The behavior here is implementation-
- // defined.
- if (Ty->getPointeeType().isVolatileQualified())
- return;
-
- // We need to temorairly remove the assumption so we can insert the
- // sanitizer check before it, else the check will be dropped by optimizations.
- Assumption->removeFromParent();
-
- {
- SanitizerScope SanScope(this);
-
- if (!OffsetValue)
- OffsetValue = Builder.getInt1(0); // no offset.
-
- llvm::Constant *StaticData[] = {EmitCheckSourceLocation(Loc),
- EmitCheckSourceLocation(SecondaryLoc),
- EmitCheckTypeDescriptor(Ty)};
- llvm::Value *DynamicData[] = {EmitCheckValue(Ptr),
- EmitCheckValue(Alignment),
- EmitCheckValue(OffsetValue)};
- EmitCheck({std::make_pair(TheCheck, SanitizerKind::Alignment)},
- SanitizerHandler::AlignmentAssumption, StaticData, DynamicData);
- }
-
- // We are now in the (new, empty) "cont" basic block.
- // Reintroduce the assumption.
- Builder.Insert(Assumption);
- // FIXME: Assumption still has it's original basic block as it's Parent.
-}
-
-llvm::DebugLoc CodeGenFunction::SourceLocToDebugLoc(SourceLocation Location) {
- if (CGDebugInfo *DI = getDebugInfo())
- return DI->SourceLocToDebugLoc(Location);
-
- return llvm::DebugLoc();
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h
deleted file mode 100644
index 89cb850ab1b..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h
+++ /dev/null
@@ -1,4373 +0,0 @@
-//===-- CodeGenFunction.h - Per-Function state for LLVM CodeGen -*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the internal per-function state used for llvm translation.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENFUNCTION_H
-#define LLVM_CLANG_LIB_CODEGEN_CODEGENFUNCTION_H
-
-#include "CGBuilder.h"
-#include "CGDebugInfo.h"
-#include "CGLoopInfo.h"
-#include "CGValue.h"
-#include "CodeGenModule.h"
-#include "CodeGenPGO.h"
-#include "EHScopeStack.h"
-#include "VarBypassDetector.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/ExprOpenMP.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/ABI.h"
-#include "clang/Basic/CapturedStmt.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/OpenMPKinds.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/IR/ValueHandle.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Transforms/Utils/SanitizerStats.h"
-
-namespace llvm {
-class BasicBlock;
-class LLVMContext;
-class MDNode;
-class Module;
-class SwitchInst;
-class Twine;
-class Value;
-class CallSite;
-}
-
-namespace clang {
-class ASTContext;
-class BlockDecl;
-class CXXDestructorDecl;
-class CXXForRangeStmt;
-class CXXTryStmt;
-class Decl;
-class LabelDecl;
-class EnumConstantDecl;
-class FunctionDecl;
-class FunctionProtoType;
-class LabelStmt;
-class ObjCContainerDecl;
-class ObjCInterfaceDecl;
-class ObjCIvarDecl;
-class ObjCMethodDecl;
-class ObjCImplementationDecl;
-class ObjCPropertyImplDecl;
-class TargetInfo;
-class VarDecl;
-class ObjCForCollectionStmt;
-class ObjCAtTryStmt;
-class ObjCAtThrowStmt;
-class ObjCAtSynchronizedStmt;
-class ObjCAutoreleasePoolStmt;
-
-namespace analyze_os_log {
-class OSLogBufferLayout;
-}
-
-namespace CodeGen {
-class CodeGenTypes;
-class CGCallee;
-class CGFunctionInfo;
-class CGRecordLayout;
-class CGBlockInfo;
-class CGCXXABI;
-class BlockByrefHelpers;
-class BlockByrefInfo;
-class BlockFlags;
-class BlockFieldFlags;
-class RegionCodeGenTy;
-class TargetCodeGenInfo;
-struct OMPTaskDataTy;
-struct CGCoroData;
-
-/// The kind of evaluation to perform on values of a particular
-/// type. Basically, is the code in CGExprScalar, CGExprComplex, or
-/// CGExprAgg?
-///
-/// TODO: should vectors maybe be split out into their own thing?
-enum TypeEvaluationKind {
- TEK_Scalar,
- TEK_Complex,
- TEK_Aggregate
-};
-
-#define LIST_SANITIZER_CHECKS \
- SANITIZER_CHECK(AddOverflow, add_overflow, 0) \
- SANITIZER_CHECK(BuiltinUnreachable, builtin_unreachable, 0) \
- SANITIZER_CHECK(CFICheckFail, cfi_check_fail, 0) \
- SANITIZER_CHECK(DivremOverflow, divrem_overflow, 0) \
- SANITIZER_CHECK(DynamicTypeCacheMiss, dynamic_type_cache_miss, 0) \
- SANITIZER_CHECK(FloatCastOverflow, float_cast_overflow, 0) \
- SANITIZER_CHECK(FunctionTypeMismatch, function_type_mismatch, 0) \
- SANITIZER_CHECK(ImplicitConversion, implicit_conversion, 0) \
- SANITIZER_CHECK(InvalidBuiltin, invalid_builtin, 0) \
- SANITIZER_CHECK(LoadInvalidValue, load_invalid_value, 0) \
- SANITIZER_CHECK(MissingReturn, missing_return, 0) \
- SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \
- SANITIZER_CHECK(NegateOverflow, negate_overflow, 0) \
- SANITIZER_CHECK(NullabilityArg, nullability_arg, 0) \
- SANITIZER_CHECK(NullabilityReturn, nullability_return, 1) \
- SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \
- SANITIZER_CHECK(NonnullReturn, nonnull_return, 1) \
- SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \
- SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0) \
- SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \
- SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \
- SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \
- SANITIZER_CHECK(AlignmentAssumption, alignment_assumption, 0) \
- SANITIZER_CHECK(VLABoundNotPositive, vla_bound_not_positive, 0)
-
-enum SanitizerHandler {
-#define SANITIZER_CHECK(Enum, Name, Version) Enum,
- LIST_SANITIZER_CHECKS
-#undef SANITIZER_CHECK
-};
-
-/// Helper class with most of the code for saving a value for a
-/// conditional expression cleanup.
-struct DominatingLLVMValue {
- typedef llvm::PointerIntPair<llvm::Value*, 1, bool> saved_type;
-
- /// Answer whether the given value needs extra work to be saved.
- static bool needsSaving(llvm::Value *value) {
- // If it's not an instruction, we don't need to save.
- if (!isa<llvm::Instruction>(value)) return false;
-
- // If it's an instruction in the entry block, we don't need to save.
- llvm::BasicBlock *block = cast<llvm::Instruction>(value)->getParent();
- return (block != &block->getParent()->getEntryBlock());
- }
-
- static saved_type save(CodeGenFunction &CGF, llvm::Value *value);
- static llvm::Value *restore(CodeGenFunction &CGF, saved_type value);
-};
-
-/// A partial specialization of DominatingValue for llvm::Values that
-/// might be llvm::Instructions.
-template <class T> struct DominatingPointer<T,true> : DominatingLLVMValue {
- typedef T *type;
- static type restore(CodeGenFunction &CGF, saved_type value) {
- return static_cast<T*>(DominatingLLVMValue::restore(CGF, value));
- }
-};
-
-/// A specialization of DominatingValue for Address.
-template <> struct DominatingValue<Address> {
- typedef Address type;
-
- struct saved_type {
- DominatingLLVMValue::saved_type SavedValue;
- CharUnits Alignment;
- };
-
- static bool needsSaving(type value) {
- return DominatingLLVMValue::needsSaving(value.getPointer());
- }
- static saved_type save(CodeGenFunction &CGF, type value) {
- return { DominatingLLVMValue::save(CGF, value.getPointer()),
- value.getAlignment() };
- }
- static type restore(CodeGenFunction &CGF, saved_type value) {
- return Address(DominatingLLVMValue::restore(CGF, value.SavedValue),
- value.Alignment);
- }
-};
-
-/// A specialization of DominatingValue for RValue.
-template <> struct DominatingValue<RValue> {
- typedef RValue type;
- class saved_type {
- enum Kind { ScalarLiteral, ScalarAddress, AggregateLiteral,
- AggregateAddress, ComplexAddress };
-
- llvm::Value *Value;
- unsigned K : 3;
- unsigned Align : 29;
- saved_type(llvm::Value *v, Kind k, unsigned a = 0)
- : Value(v), K(k), Align(a) {}
-
- public:
- static bool needsSaving(RValue value);
- static saved_type save(CodeGenFunction &CGF, RValue value);
- RValue restore(CodeGenFunction &CGF);
-
- // implementations in CGCleanup.cpp
- };
-
- static bool needsSaving(type value) {
- return saved_type::needsSaving(value);
- }
- static saved_type save(CodeGenFunction &CGF, type value) {
- return saved_type::save(CGF, value);
- }
- static type restore(CodeGenFunction &CGF, saved_type value) {
- return value.restore(CGF);
- }
-};
-
-/// CodeGenFunction - This class organizes the per-function state that is used
-/// while generating LLVM code.
-class CodeGenFunction : public CodeGenTypeCache {
- CodeGenFunction(const CodeGenFunction &) = delete;
- void operator=(const CodeGenFunction &) = delete;
-
- friend class CGCXXABI;
-public:
- /// A jump destination is an abstract label, branching to which may
- /// require a jump out through normal cleanups.
- struct JumpDest {
- JumpDest() : Block(nullptr), ScopeDepth(), Index(0) {}
- JumpDest(llvm::BasicBlock *Block,
- EHScopeStack::stable_iterator Depth,
- unsigned Index)
- : Block(Block), ScopeDepth(Depth), Index(Index) {}
-
- bool isValid() const { return Block != nullptr; }
- llvm::BasicBlock *getBlock() const { return Block; }
- EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; }
- unsigned getDestIndex() const { return Index; }
-
- // This should be used cautiously.
- void setScopeDepth(EHScopeStack::stable_iterator depth) {
- ScopeDepth = depth;
- }
-
- private:
- llvm::BasicBlock *Block;
- EHScopeStack::stable_iterator ScopeDepth;
- unsigned Index;
- };
-
- CodeGenModule &CGM; // Per-module state.
- const TargetInfo &Target;
-
- typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
- LoopInfoStack LoopStack;
- CGBuilderTy Builder;
-
- // Stores variables for which we can't generate correct lifetime markers
- // because of jumps.
- VarBypassDetector Bypasses;
-
- // CodeGen lambda for loops and support for ordered clause
- typedef llvm::function_ref<void(CodeGenFunction &, const OMPLoopDirective &,
- JumpDest)>
- CodeGenLoopTy;
- typedef llvm::function_ref<void(CodeGenFunction &, SourceLocation,
- const unsigned, const bool)>
- CodeGenOrderedTy;
-
- // Codegen lambda for loop bounds in worksharing loop constructs
- typedef llvm::function_ref<std::pair<LValue, LValue>(
- CodeGenFunction &, const OMPExecutableDirective &S)>
- CodeGenLoopBoundsTy;
-
- // Codegen lambda for loop bounds in dispatch-based loop implementation
- typedef llvm::function_ref<std::pair<llvm::Value *, llvm::Value *>(
- CodeGenFunction &, const OMPExecutableDirective &S, Address LB,
- Address UB)>
- CodeGenDispatchBoundsTy;
-
- /// CGBuilder insert helper. This function is called after an
- /// instruction is created using Builder.
- void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
- llvm::BasicBlock *BB,
- llvm::BasicBlock::iterator InsertPt) const;
-
- /// CurFuncDecl - Holds the Decl for the current outermost
- /// non-closure context.
- const Decl *CurFuncDecl;
- /// CurCodeDecl - This is the inner-most code context, which includes blocks.
- const Decl *CurCodeDecl;
- const CGFunctionInfo *CurFnInfo;
- QualType FnRetTy;
- llvm::Function *CurFn = nullptr;
-
- // Holds coroutine data if the current function is a coroutine. We use a
- // wrapper to manage its lifetime, so that we don't have to define CGCoroData
- // in this header.
- struct CGCoroInfo {
- std::unique_ptr<CGCoroData> Data;
- CGCoroInfo();
- ~CGCoroInfo();
- };
- CGCoroInfo CurCoro;
-
- bool isCoroutine() const {
- return CurCoro.Data != nullptr;
- }
-
- /// CurGD - The GlobalDecl for the current function being compiled.
- GlobalDecl CurGD;
-
- /// PrologueCleanupDepth - The cleanup depth enclosing all the
- /// cleanups associated with the parameters.
- EHScopeStack::stable_iterator PrologueCleanupDepth;
-
- /// ReturnBlock - Unified return block.
- JumpDest ReturnBlock;
-
- /// ReturnValue - The temporary alloca to hold the return
- /// value. This is invalid iff the function has no return value.
- Address ReturnValue = Address::invalid();
-
- /// Return true if a label was seen in the current scope.
- bool hasLabelBeenSeenInCurrentScope() const {
- if (CurLexicalScope)
- return CurLexicalScope->hasLabels();
- return !LabelMap.empty();
- }
-
- /// AllocaInsertPoint - This is an instruction in the entry block before which
- /// we prefer to insert allocas.
- llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
-
- /// API for captured statement code generation.
- class CGCapturedStmtInfo {
- public:
- explicit CGCapturedStmtInfo(CapturedRegionKind K = CR_Default)
- : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) {}
- explicit CGCapturedStmtInfo(const CapturedStmt &S,
- CapturedRegionKind K = CR_Default)
- : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) {
-
- RecordDecl::field_iterator Field =
- S.getCapturedRecordDecl()->field_begin();
- for (CapturedStmt::const_capture_iterator I = S.capture_begin(),
- E = S.capture_end();
- I != E; ++I, ++Field) {
- if (I->capturesThis())
- CXXThisFieldDecl = *Field;
- else if (I->capturesVariable())
- CaptureFields[I->getCapturedVar()->getCanonicalDecl()] = *Field;
- else if (I->capturesVariableByCopy())
- CaptureFields[I->getCapturedVar()->getCanonicalDecl()] = *Field;
- }
- }
-
- virtual ~CGCapturedStmtInfo();
-
- CapturedRegionKind getKind() const { return Kind; }
-
- virtual void setContextValue(llvm::Value *V) { ThisValue = V; }
- // Retrieve the value of the context parameter.
- virtual llvm::Value *getContextValue() const { return ThisValue; }
-
- /// Lookup the captured field decl for a variable.
- virtual const FieldDecl *lookup(const VarDecl *VD) const {
- return CaptureFields.lookup(VD->getCanonicalDecl());
- }
-
- bool isCXXThisExprCaptured() const { return getThisFieldDecl() != nullptr; }
- virtual FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; }
-
- static bool classof(const CGCapturedStmtInfo *) {
- return true;
- }
-
- /// Emit the captured statement body.
- virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S) {
- CGF.incrementProfileCounter(S);
- CGF.EmitStmt(S);
- }
-
- /// Get the name of the capture helper.
- virtual StringRef getHelperName() const { return "__captured_stmt"; }
-
- private:
- /// The kind of captured statement being generated.
- CapturedRegionKind Kind;
-
- /// Keep the map between VarDecl and FieldDecl.
- llvm::SmallDenseMap<const VarDecl *, FieldDecl *> CaptureFields;
-
- /// The base address of the captured record, passed in as the first
- /// argument of the parallel region function.
- llvm::Value *ThisValue;
-
- /// Captured 'this' type.
- FieldDecl *CXXThisFieldDecl;
- };
- CGCapturedStmtInfo *CapturedStmtInfo = nullptr;
-
- /// RAII for correct setting/restoring of CapturedStmtInfo.
- class CGCapturedStmtRAII {
- private:
- CodeGenFunction &CGF;
- CGCapturedStmtInfo *PrevCapturedStmtInfo;
- public:
- CGCapturedStmtRAII(CodeGenFunction &CGF,
- CGCapturedStmtInfo *NewCapturedStmtInfo)
- : CGF(CGF), PrevCapturedStmtInfo(CGF.CapturedStmtInfo) {
- CGF.CapturedStmtInfo = NewCapturedStmtInfo;
- }
- ~CGCapturedStmtRAII() { CGF.CapturedStmtInfo = PrevCapturedStmtInfo; }
- };
-
- /// An abstract representation of regular/ObjC call/message targets.
- class AbstractCallee {
- /// The function declaration of the callee.
- const Decl *CalleeDecl;
-
- public:
- AbstractCallee() : CalleeDecl(nullptr) {}
- AbstractCallee(const FunctionDecl *FD) : CalleeDecl(FD) {}
- AbstractCallee(const ObjCMethodDecl *OMD) : CalleeDecl(OMD) {}
- bool hasFunctionDecl() const {
- return dyn_cast_or_null<FunctionDecl>(CalleeDecl);
- }
- const Decl *getDecl() const { return CalleeDecl; }
- unsigned getNumParams() const {
- if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecl))
- return FD->getNumParams();
- return cast<ObjCMethodDecl>(CalleeDecl)->param_size();
- }
- const ParmVarDecl *getParamDecl(unsigned I) const {
- if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecl))
- return FD->getParamDecl(I);
- return *(cast<ObjCMethodDecl>(CalleeDecl)->param_begin() + I);
- }
- };
-
- /// Sanitizers enabled for this function.
- SanitizerSet SanOpts;
-
- /// True if CodeGen currently emits code implementing sanitizer checks.
- bool IsSanitizerScope = false;
-
- /// RAII object to set/unset CodeGenFunction::IsSanitizerScope.
- class SanitizerScope {
- CodeGenFunction *CGF;
- public:
- SanitizerScope(CodeGenFunction *CGF);
- ~SanitizerScope();
- };
-
- /// In C++, whether we are code generating a thunk. This controls whether we
- /// should emit cleanups.
- bool CurFuncIsThunk = false;
-
- /// In ARC, whether we should autorelease the return value.
- bool AutoreleaseResult = false;
-
- /// Whether we processed a Microsoft-style asm block during CodeGen. These can
- /// potentially set the return value.
- bool SawAsmBlock = false;
-
- const NamedDecl *CurSEHParent = nullptr;
-
- /// True if the current function is an outlined SEH helper. This can be a
- /// finally block or filter expression.
- bool IsOutlinedSEHHelper = false;
-
- const CodeGen::CGBlockInfo *BlockInfo = nullptr;
- llvm::Value *BlockPointer = nullptr;
-
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
- FieldDecl *LambdaThisCaptureField = nullptr;
-
- /// A mapping from NRVO variables to the flags used to indicate
- /// when the NRVO has been applied to this variable.
- llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
-
- EHScopeStack EHStack;
- llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
- llvm::SmallVector<const JumpDest *, 2> SEHTryEpilogueStack;
-
- llvm::Instruction *CurrentFuncletPad = nullptr;
-
- class CallLifetimeEnd final : public EHScopeStack::Cleanup {
- llvm::Value *Addr;
- llvm::Value *Size;
-
- public:
- CallLifetimeEnd(Address addr, llvm::Value *size)
- : Addr(addr.getPointer()), Size(size) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitLifetimeEnd(Size, Addr);
- }
- };
-
- /// Header for data within LifetimeExtendedCleanupStack.
- struct LifetimeExtendedCleanupHeader {
- /// The size of the following cleanup object.
- unsigned Size;
- /// The kind of cleanup to push: a value from the CleanupKind enumeration.
- unsigned Kind : 31;
- /// Whether this is a conditional cleanup.
- unsigned IsConditional : 1;
-
- size_t getSize() const { return Size; }
- CleanupKind getKind() const { return (CleanupKind)Kind; }
- bool isConditional() const { return IsConditional; }
- };
-
- /// i32s containing the indexes of the cleanup destinations.
- Address NormalCleanupDest = Address::invalid();
-
- unsigned NextCleanupDestIndex = 1;
-
- /// FirstBlockInfo - The head of a singly-linked-list of block layouts.
- CGBlockInfo *FirstBlockInfo = nullptr;
-
- /// EHResumeBlock - Unified block containing a call to llvm.eh.resume.
- llvm::BasicBlock *EHResumeBlock = nullptr;
-
- /// The exception slot. All landing pads write the current exception pointer
- /// into this alloca.
- llvm::Value *ExceptionSlot = nullptr;
-
- /// The selector slot. Under the MandatoryCleanup model, all landing pads
- /// write the current selector value into this alloca.
- llvm::AllocaInst *EHSelectorSlot = nullptr;
-
- /// A stack of exception code slots. Entering an __except block pushes a slot
- /// on the stack and leaving pops one. The __exception_code() intrinsic loads
- /// a value from the top of the stack.
- SmallVector<Address, 1> SEHCodeSlotStack;
-
- /// Value returned by __exception_info intrinsic.
- llvm::Value *SEHInfo = nullptr;
-
- /// Emits a landing pad for the current EH stack.
- llvm::BasicBlock *EmitLandingPad();
-
- llvm::BasicBlock *getInvokeDestImpl();
-
- template <class T>
- typename DominatingValue<T>::saved_type saveValueInCond(T value) {
- return DominatingValue<T>::save(*this, value);
- }
-
-public:
- /// ObjCEHValueStack - Stack of Objective-C exception values, used for
- /// rethrows.
- SmallVector<llvm::Value*, 8> ObjCEHValueStack;
-
- /// A class controlling the emission of a finally block.
- class FinallyInfo {
- /// Where the catchall's edge through the cleanup should go.
- JumpDest RethrowDest;
-
- /// A function to call to enter the catch.
- llvm::Constant *BeginCatchFn;
-
- /// An i1 variable indicating whether or not the @finally is
- /// running for an exception.
- llvm::AllocaInst *ForEHVar;
-
- /// An i8* variable into which the exception pointer to rethrow
- /// has been saved.
- llvm::AllocaInst *SavedExnVar;
-
- public:
- void enter(CodeGenFunction &CGF, const Stmt *Finally,
- llvm::Constant *beginCatchFn, llvm::Constant *endCatchFn,
- llvm::Constant *rethrowFn);
- void exit(CodeGenFunction &CGF);
- };
-
- /// Returns true inside SEH __try blocks.
- bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); }
-
- /// Returns true while emitting a cleanuppad.
- bool isCleanupPadScope() const {
- return CurrentFuncletPad && isa<llvm::CleanupPadInst>(CurrentFuncletPad);
- }
-
- /// pushFullExprCleanup - Push a cleanup to be run at the end of the
- /// current full-expression. Safe against the possibility that
- /// we're currently inside a conditionally-evaluated expression.
- template <class T, class... As>
- void pushFullExprCleanup(CleanupKind kind, As... A) {
- // If we're not in a conditional branch, or if none of the
- // arguments requires saving, then use the unconditional cleanup.
- if (!isInConditionalBranch())
- return EHStack.pushCleanup<T>(kind, A...);
-
- // Stash values in a tuple so we can guarantee the order of saves.
- typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
- SavedTuple Saved{saveValueInCond(A)...};
-
- typedef EHScopeStack::ConditionalCleanup<T, As...> CleanupType;
- EHStack.pushCleanupTuple<CleanupType>(kind, Saved);
- initFullExprCleanup();
- }
-
- /// Queue a cleanup to be pushed after finishing the current
- /// full-expression.
- template <class T, class... As>
- void pushCleanupAfterFullExpr(CleanupKind Kind, As... A) {
- if (!isInConditionalBranch())
- return pushCleanupAfterFullExprImpl<T>(Kind, Address::invalid(), A...);
-
- Address ActiveFlag = createCleanupActiveFlag();
- assert(!DominatingValue<Address>::needsSaving(ActiveFlag) &&
- "cleanup active flag should never need saving");
-
- typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
- SavedTuple Saved{saveValueInCond(A)...};
-
- typedef EHScopeStack::ConditionalCleanup<T, As...> CleanupType;
- pushCleanupAfterFullExprImpl<CleanupType>(Kind, ActiveFlag, Saved);
- }
-
- template <class T, class... As>
- void pushCleanupAfterFullExprImpl(CleanupKind Kind, Address ActiveFlag,
- As... A) {
- LifetimeExtendedCleanupHeader Header = {sizeof(T), Kind,
- ActiveFlag.isValid()};
-
- size_t OldSize = LifetimeExtendedCleanupStack.size();
- LifetimeExtendedCleanupStack.resize(
- LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size +
- (Header.IsConditional ? sizeof(ActiveFlag) : 0));
-
- static_assert(sizeof(Header) % alignof(T) == 0,
- "Cleanup will be allocated on misaligned address");
- char *Buffer = &LifetimeExtendedCleanupStack[OldSize];
- new (Buffer) LifetimeExtendedCleanupHeader(Header);
- new (Buffer + sizeof(Header)) T(A...);
- if (Header.IsConditional)
- new (Buffer + sizeof(Header) + sizeof(T)) Address(ActiveFlag);
- }
-
- /// Set up the last cleanup that was pushed as a conditional
- /// full-expression cleanup.
- void initFullExprCleanup() {
- initFullExprCleanupWithFlag(createCleanupActiveFlag());
- }
-
- void initFullExprCleanupWithFlag(Address ActiveFlag);
- Address createCleanupActiveFlag();
-
- /// PushDestructorCleanup - Push a cleanup to call the
- /// complete-object destructor of an object of the given type at the
- /// given address. Does nothing if T is not a C++ class type with a
- /// non-trivial destructor.
- void PushDestructorCleanup(QualType T, Address Addr);
-
- /// PushDestructorCleanup - Push a cleanup to call the
- /// complete-object variant of the given destructor on the object at
- /// the given address.
- void PushDestructorCleanup(const CXXDestructorDecl *Dtor, Address Addr);
-
- /// PopCleanupBlock - Will pop the cleanup entry on the stack and
- /// process all branch fixups.
- void PopCleanupBlock(bool FallThroughIsBranchThrough = false);
-
- /// DeactivateCleanupBlock - Deactivates the given cleanup block.
- /// The block cannot be reactivated. Pops it if it's the top of the
- /// stack.
- ///
- /// \param DominatingIP - An instruction which is known to
- /// dominate the current IP (if set) and which lies along
- /// all paths of execution between the current IP and the
- /// the point at which the cleanup comes into scope.
- void DeactivateCleanupBlock(EHScopeStack::stable_iterator Cleanup,
- llvm::Instruction *DominatingIP);
-
- /// ActivateCleanupBlock - Activates an initially-inactive cleanup.
- /// Cannot be used to resurrect a deactivated cleanup.
- ///
- /// \param DominatingIP - An instruction which is known to
- /// dominate the current IP (if set) and which lies along
- /// all paths of execution between the current IP and the
- /// the point at which the cleanup comes into scope.
- void ActivateCleanupBlock(EHScopeStack::stable_iterator Cleanup,
- llvm::Instruction *DominatingIP);
-
- /// Enters a new scope for capturing cleanups, all of which
- /// will be executed once the scope is exited.
- class RunCleanupsScope {
- EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth;
- size_t LifetimeExtendedCleanupStackSize;
- bool OldDidCallStackSave;
- protected:
- bool PerformCleanup;
- private:
-
- RunCleanupsScope(const RunCleanupsScope &) = delete;
- void operator=(const RunCleanupsScope &) = delete;
-
- protected:
- CodeGenFunction& CGF;
-
- public:
- /// Enter a new cleanup scope.
- explicit RunCleanupsScope(CodeGenFunction &CGF)
- : PerformCleanup(true), CGF(CGF)
- {
- CleanupStackDepth = CGF.EHStack.stable_begin();
- LifetimeExtendedCleanupStackSize =
- CGF.LifetimeExtendedCleanupStack.size();
- OldDidCallStackSave = CGF.DidCallStackSave;
- CGF.DidCallStackSave = false;
- OldCleanupScopeDepth = CGF.CurrentCleanupScopeDepth;
- CGF.CurrentCleanupScopeDepth = CleanupStackDepth;
- }
-
- /// Exit this cleanup scope, emitting any accumulated cleanups.
- ~RunCleanupsScope() {
- if (PerformCleanup)
- ForceCleanup();
- }
-
- /// Determine whether this scope requires any cleanups.
- bool requiresCleanups() const {
- return CGF.EHStack.stable_begin() != CleanupStackDepth;
- }
-
- /// Force the emission of cleanups now, instead of waiting
- /// until this object is destroyed.
- /// \param ValuesToReload - A list of values that need to be available at
- /// the insertion point after cleanup emission. If cleanup emission created
- /// a shared cleanup block, these value pointers will be rewritten.
- /// Otherwise, they not will be modified.
- void ForceCleanup(std::initializer_list<llvm::Value**> ValuesToReload = {}) {
- assert(PerformCleanup && "Already forced cleanup");
- CGF.DidCallStackSave = OldDidCallStackSave;
- CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize,
- ValuesToReload);
- PerformCleanup = false;
- CGF.CurrentCleanupScopeDepth = OldCleanupScopeDepth;
- }
- };
-
- // Cleanup stack depth of the RunCleanupsScope that was pushed most recently.
- EHScopeStack::stable_iterator CurrentCleanupScopeDepth =
- EHScopeStack::stable_end();
-
- class LexicalScope : public RunCleanupsScope {
- SourceRange Range;
- SmallVector<const LabelDecl*, 4> Labels;
- LexicalScope *ParentScope;
-
- LexicalScope(const LexicalScope &) = delete;
- void operator=(const LexicalScope &) = delete;
-
- public:
- /// Enter a new cleanup scope.
- explicit LexicalScope(CodeGenFunction &CGF, SourceRange Range)
- : RunCleanupsScope(CGF), Range(Range), ParentScope(CGF.CurLexicalScope) {
- CGF.CurLexicalScope = this;
- if (CGDebugInfo *DI = CGF.getDebugInfo())
- DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin());
- }
-
- void addLabel(const LabelDecl *label) {
- assert(PerformCleanup && "adding label to dead scope?");
- Labels.push_back(label);
- }
-
- /// Exit this cleanup scope, emitting any accumulated
- /// cleanups.
- ~LexicalScope() {
- if (CGDebugInfo *DI = CGF.getDebugInfo())
- DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
-
- // If we should perform a cleanup, force them now. Note that
- // this ends the cleanup scope before rescoping any labels.
- if (PerformCleanup) {
- ApplyDebugLocation DL(CGF, Range.getEnd());
- ForceCleanup();
- }
- }
-
- /// Force the emission of cleanups now, instead of waiting
- /// until this object is destroyed.
- void ForceCleanup() {
- CGF.CurLexicalScope = ParentScope;
- RunCleanupsScope::ForceCleanup();
-
- if (!Labels.empty())
- rescopeLabels();
- }
-
- bool hasLabels() const {
- return !Labels.empty();
- }
-
- void rescopeLabels();
- };
-
- typedef llvm::DenseMap<const Decl *, Address> DeclMapTy;
-
- /// The class used to assign some variables some temporarily addresses.
- class OMPMapVars {
- DeclMapTy SavedLocals;
- DeclMapTy SavedTempAddresses;
- OMPMapVars(const OMPMapVars &) = delete;
- void operator=(const OMPMapVars &) = delete;
-
- public:
- explicit OMPMapVars() = default;
- ~OMPMapVars() {
- assert(SavedLocals.empty() && "Did not restored original addresses.");
- };
-
- /// Sets the address of the variable \p LocalVD to be \p TempAddr in
- /// function \p CGF.
- /// \return true if at least one variable was set already, false otherwise.
- bool setVarAddr(CodeGenFunction &CGF, const VarDecl *LocalVD,
- Address TempAddr) {
- LocalVD = LocalVD->getCanonicalDecl();
- // Only save it once.
- if (SavedLocals.count(LocalVD)) return false;
-
- // Copy the existing local entry to SavedLocals.
- auto it = CGF.LocalDeclMap.find(LocalVD);
- if (it != CGF.LocalDeclMap.end())
- SavedLocals.try_emplace(LocalVD, it->second);
- else
- SavedLocals.try_emplace(LocalVD, Address::invalid());
-
- // Generate the private entry.
- QualType VarTy = LocalVD->getType();
- if (VarTy->isReferenceType()) {
- Address Temp = CGF.CreateMemTemp(VarTy);
- CGF.Builder.CreateStore(TempAddr.getPointer(), Temp);
- TempAddr = Temp;
- }
- SavedTempAddresses.try_emplace(LocalVD, TempAddr);
-
- return true;
- }
-
- /// Applies new addresses to the list of the variables.
- /// \return true if at least one variable is using new address, false
- /// otherwise.
- bool apply(CodeGenFunction &CGF) {
- copyInto(SavedTempAddresses, CGF.LocalDeclMap);
- SavedTempAddresses.clear();
- return !SavedLocals.empty();
- }
-
- /// Restores original addresses of the variables.
- void restore(CodeGenFunction &CGF) {
- if (!SavedLocals.empty()) {
- copyInto(SavedLocals, CGF.LocalDeclMap);
- SavedLocals.clear();
- }
- }
-
- private:
- /// Copy all the entries in the source map over the corresponding
- /// entries in the destination, which must exist.
- static void copyInto(const DeclMapTy &Src, DeclMapTy &Dest) {
- for (auto &Pair : Src) {
- if (!Pair.second.isValid()) {
- Dest.erase(Pair.first);
- continue;
- }
-
- auto I = Dest.find(Pair.first);
- if (I != Dest.end())
- I->second = Pair.second;
- else
- Dest.insert(Pair);
- }
- }
- };
-
- /// The scope used to remap some variables as private in the OpenMP loop body
- /// (or other captured region emitted without outlining), and to restore old
- /// vars back on exit.
- class OMPPrivateScope : public RunCleanupsScope {
- OMPMapVars MappedVars;
- OMPPrivateScope(const OMPPrivateScope &) = delete;
- void operator=(const OMPPrivateScope &) = delete;
-
- public:
- /// Enter a new OpenMP private scope.
- explicit OMPPrivateScope(CodeGenFunction &CGF) : RunCleanupsScope(CGF) {}
-
- /// Registers \p LocalVD variable as a private and apply \p PrivateGen
- /// function for it to generate corresponding private variable. \p
- /// PrivateGen returns an address of the generated private variable.
- /// \return true if the variable is registered as private, false if it has
- /// been privatized already.
- bool addPrivate(const VarDecl *LocalVD,
- const llvm::function_ref<Address()> PrivateGen) {
- assert(PerformCleanup && "adding private to dead scope");
- return MappedVars.setVarAddr(CGF, LocalVD, PrivateGen());
- }
-
- /// Privatizes local variables previously registered as private.
- /// Registration is separate from the actual privatization to allow
- /// initializers use values of the original variables, not the private one.
- /// This is important, for example, if the private variable is a class
- /// variable initialized by a constructor that references other private
- /// variables. But at initialization original variables must be used, not
- /// private copies.
- /// \return true if at least one variable was privatized, false otherwise.
- bool Privatize() { return MappedVars.apply(CGF); }
-
- void ForceCleanup() {
- RunCleanupsScope::ForceCleanup();
- MappedVars.restore(CGF);
- }
-
- /// Exit scope - all the mapped variables are restored.
- ~OMPPrivateScope() {
- if (PerformCleanup)
- ForceCleanup();
- }
-
- /// Checks if the global variable is captured in current function.
- bool isGlobalVarCaptured(const VarDecl *VD) const {
- VD = VD->getCanonicalDecl();
- return !VD->isLocalVarDeclOrParm() && CGF.LocalDeclMap.count(VD) > 0;
- }
- };
-
- /// Takes the old cleanup stack size and emits the cleanup blocks
- /// that have been added.
- void
- PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
- std::initializer_list<llvm::Value **> ValuesToReload = {});
-
- /// Takes the old cleanup stack size and emits the cleanup blocks
- /// that have been added, then adds all lifetime-extended cleanups from
- /// the given position to the stack.
- void
- PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
- size_t OldLifetimeExtendedStackSize,
- std::initializer_list<llvm::Value **> ValuesToReload = {});
-
- void ResolveBranchFixups(llvm::BasicBlock *Target);
-
- /// The given basic block lies in the current EH scope, but may be a
- /// target of a potentially scope-crossing jump; get a stable handle
- /// to which we can perform this jump later.
- JumpDest getJumpDestInCurrentScope(llvm::BasicBlock *Target) {
- return JumpDest(Target,
- EHStack.getInnermostNormalCleanup(),
- NextCleanupDestIndex++);
- }
-
- /// The given basic block lies in the current EH scope, but may be a
- /// target of a potentially scope-crossing jump; get a stable handle
- /// to which we can perform this jump later.
- JumpDest getJumpDestInCurrentScope(StringRef Name = StringRef()) {
- return getJumpDestInCurrentScope(createBasicBlock(Name));
- }
-
- /// EmitBranchThroughCleanup - Emit a branch from the current insert
- /// block through the normal cleanup handling code (if any) and then
- /// on to \arg Dest.
- void EmitBranchThroughCleanup(JumpDest Dest);
-
- /// isObviouslyBranchWithoutCleanups - Return true if a branch to the
- /// specified destination obviously has no cleanups to run. 'false' is always
- /// a conservatively correct answer for this method.
- bool isObviouslyBranchWithoutCleanups(JumpDest Dest) const;
-
- /// popCatchScope - Pops the catch scope at the top of the EHScope
- /// stack, emitting any required code (other than the catch handlers
- /// themselves).
- void popCatchScope();
-
- llvm::BasicBlock *getEHResumeBlock(bool isCleanup);
- llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope);
- llvm::BasicBlock *
- getFuncletEHDispatchBlock(EHScopeStack::stable_iterator scope);
-
- /// An object to manage conditionally-evaluated expressions.
- class ConditionalEvaluation {
- llvm::BasicBlock *StartBB;
-
- public:
- ConditionalEvaluation(CodeGenFunction &CGF)
- : StartBB(CGF.Builder.GetInsertBlock()) {}
-
- void begin(CodeGenFunction &CGF) {
- assert(CGF.OutermostConditional != this);
- if (!CGF.OutermostConditional)
- CGF.OutermostConditional = this;
- }
-
- void end(CodeGenFunction &CGF) {
- assert(CGF.OutermostConditional != nullptr);
- if (CGF.OutermostConditional == this)
- CGF.OutermostConditional = nullptr;
- }
-
- /// Returns a block which will be executed prior to each
- /// evaluation of the conditional code.
- llvm::BasicBlock *getStartingBlock() const {
- return StartBB;
- }
- };
-
- /// isInConditionalBranch - Return true if we're currently emitting
- /// one branch or the other of a conditional expression.
- bool isInConditionalBranch() const { return OutermostConditional != nullptr; }
-
- void setBeforeOutermostConditional(llvm::Value *value, Address addr) {
- assert(isInConditionalBranch());
- llvm::BasicBlock *block = OutermostConditional->getStartingBlock();
- auto store = new llvm::StoreInst(value, addr.getPointer(), &block->back());
- store->setAlignment(addr.getAlignment().getQuantity());
- }
-
- /// An RAII object to record that we're evaluating a statement
- /// expression.
- class StmtExprEvaluation {
- CodeGenFunction &CGF;
-
- /// We have to save the outermost conditional: cleanups in a
- /// statement expression aren't conditional just because the
- /// StmtExpr is.
- ConditionalEvaluation *SavedOutermostConditional;
-
- public:
- StmtExprEvaluation(CodeGenFunction &CGF)
- : CGF(CGF), SavedOutermostConditional(CGF.OutermostConditional) {
- CGF.OutermostConditional = nullptr;
- }
-
- ~StmtExprEvaluation() {
- CGF.OutermostConditional = SavedOutermostConditional;
- CGF.EnsureInsertPoint();
- }
- };
-
- /// An object which temporarily prevents a value from being
- /// destroyed by aggressive peephole optimizations that assume that
- /// all uses of a value have been realized in the IR.
- class PeepholeProtection {
- llvm::Instruction *Inst;
- friend class CodeGenFunction;
-
- public:
- PeepholeProtection() : Inst(nullptr) {}
- };
-
- /// A non-RAII class containing all the information about a bound
- /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for
- /// this which makes individual mappings very simple; using this
- /// class directly is useful when you have a variable number of
- /// opaque values or don't want the RAII functionality for some
- /// reason.
- class OpaqueValueMappingData {
- const OpaqueValueExpr *OpaqueValue;
- bool BoundLValue;
- CodeGenFunction::PeepholeProtection Protection;
-
- OpaqueValueMappingData(const OpaqueValueExpr *ov,
- bool boundLValue)
- : OpaqueValue(ov), BoundLValue(boundLValue) {}
- public:
- OpaqueValueMappingData() : OpaqueValue(nullptr) {}
-
- static bool shouldBindAsLValue(const Expr *expr) {
- // gl-values should be bound as l-values for obvious reasons.
- // Records should be bound as l-values because IR generation
- // always keeps them in memory. Expressions of function type
- // act exactly like l-values but are formally required to be
- // r-values in C.
- return expr->isGLValue() ||
- expr->getType()->isFunctionType() ||
- hasAggregateEvaluationKind(expr->getType());
- }
-
- static OpaqueValueMappingData bind(CodeGenFunction &CGF,
- const OpaqueValueExpr *ov,
- const Expr *e) {
- if (shouldBindAsLValue(ov))
- return bind(CGF, ov, CGF.EmitLValue(e));
- return bind(CGF, ov, CGF.EmitAnyExpr(e));
- }
-
- static OpaqueValueMappingData bind(CodeGenFunction &CGF,
- const OpaqueValueExpr *ov,
- const LValue &lv) {
- assert(shouldBindAsLValue(ov));
- CGF.OpaqueLValues.insert(std::make_pair(ov, lv));
- return OpaqueValueMappingData(ov, true);
- }
-
- static OpaqueValueMappingData bind(CodeGenFunction &CGF,
- const OpaqueValueExpr *ov,
- const RValue &rv) {
- assert(!shouldBindAsLValue(ov));
- CGF.OpaqueRValues.insert(std::make_pair(ov, rv));
-
- OpaqueValueMappingData data(ov, false);
-
- // Work around an extremely aggressive peephole optimization in
- // EmitScalarConversion which assumes that all other uses of a
- // value are extant.
- data.Protection = CGF.protectFromPeepholes(rv);
-
- return data;
- }
-
- bool isValid() const { return OpaqueValue != nullptr; }
- void clear() { OpaqueValue = nullptr; }
-
- void unbind(CodeGenFunction &CGF) {
- assert(OpaqueValue && "no data to unbind!");
-
- if (BoundLValue) {
- CGF.OpaqueLValues.erase(OpaqueValue);
- } else {
- CGF.OpaqueRValues.erase(OpaqueValue);
- CGF.unprotectFromPeepholes(Protection);
- }
- }
- };
-
- /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
- class OpaqueValueMapping {
- CodeGenFunction &CGF;
- OpaqueValueMappingData Data;
-
- public:
- static bool shouldBindAsLValue(const Expr *expr) {
- return OpaqueValueMappingData::shouldBindAsLValue(expr);
- }
-
- /// Build the opaque value mapping for the given conditional
- /// operator if it's the GNU ?: extension. This is a common
- /// enough pattern that the convenience operator is really
- /// helpful.
- ///
- OpaqueValueMapping(CodeGenFunction &CGF,
- const AbstractConditionalOperator *op) : CGF(CGF) {
- if (isa<ConditionalOperator>(op))
- // Leave Data empty.
- return;
-
- const BinaryConditionalOperator *e = cast<BinaryConditionalOperator>(op);
- Data = OpaqueValueMappingData::bind(CGF, e->getOpaqueValue(),
- e->getCommon());
- }
-
- /// Build the opaque value mapping for an OpaqueValueExpr whose source
- /// expression is set to the expression the OVE represents.
- OpaqueValueMapping(CodeGenFunction &CGF, const OpaqueValueExpr *OV)
- : CGF(CGF) {
- if (OV) {
- assert(OV->getSourceExpr() && "wrong form of OpaqueValueMapping used "
- "for OVE with no source expression");
- Data = OpaqueValueMappingData::bind(CGF, OV, OV->getSourceExpr());
- }
- }
-
- OpaqueValueMapping(CodeGenFunction &CGF,
- const OpaqueValueExpr *opaqueValue,
- LValue lvalue)
- : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, lvalue)) {
- }
-
- OpaqueValueMapping(CodeGenFunction &CGF,
- const OpaqueValueExpr *opaqueValue,
- RValue rvalue)
- : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, rvalue)) {
- }
-
- void pop() {
- Data.unbind(CGF);
- Data.clear();
- }
-
- ~OpaqueValueMapping() {
- if (Data.isValid()) Data.unbind(CGF);
- }
- };
-
-private:
- CGDebugInfo *DebugInfo;
- /// Used to create unique names for artificial VLA size debug info variables.
- unsigned VLAExprCounter = 0;
- bool DisableDebugInfo = false;
-
- /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
- /// calling llvm.stacksave for multiple VLAs in the same scope.
- bool DidCallStackSave = false;
-
- /// IndirectBranch - The first time an indirect goto is seen we create a block
- /// with an indirect branch. Every time we see the address of a label taken,
- /// we add the label to the indirect goto. Every subsequent indirect goto is
- /// codegen'd as a jump to the IndirectBranch's basic block.
- llvm::IndirectBrInst *IndirectBranch = nullptr;
-
- /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
- /// decls.
- DeclMapTy LocalDeclMap;
-
- // Keep track of the cleanups for callee-destructed parameters pushed to the
- // cleanup stack so that they can be deactivated later.
- llvm::DenseMap<const ParmVarDecl *, EHScopeStack::stable_iterator>
- CalleeDestructedParamCleanups;
-
- /// SizeArguments - If a ParmVarDecl had the pass_object_size attribute, this
- /// will contain a mapping from said ParmVarDecl to its implicit "object_size"
- /// parameter.
- llvm::SmallDenseMap<const ParmVarDecl *, const ImplicitParamDecl *, 2>
- SizeArguments;
-
- /// Track escaped local variables with auto storage. Used during SEH
- /// outlining to produce a call to llvm.localescape.
- llvm::DenseMap<llvm::AllocaInst *, int> EscapedLocals;
-
- /// LabelMap - This keeps track of the LLVM basic block for each C label.
- llvm::DenseMap<const LabelDecl*, JumpDest> LabelMap;
-
- // BreakContinueStack - This keeps track of where break and continue
- // statements should jump to.
- struct BreakContinue {
- BreakContinue(JumpDest Break, JumpDest Continue)
- : BreakBlock(Break), ContinueBlock(Continue) {}
-
- JumpDest BreakBlock;
- JumpDest ContinueBlock;
- };
- SmallVector<BreakContinue, 8> BreakContinueStack;
-
- /// Handles cancellation exit points in OpenMP-related constructs.
- class OpenMPCancelExitStack {
- /// Tracks cancellation exit point and join point for cancel-related exit
- /// and normal exit.
- struct CancelExit {
- CancelExit() = default;
- CancelExit(OpenMPDirectiveKind Kind, JumpDest ExitBlock,
- JumpDest ContBlock)
- : Kind(Kind), ExitBlock(ExitBlock), ContBlock(ContBlock) {}
- OpenMPDirectiveKind Kind = OMPD_unknown;
- /// true if the exit block has been emitted already by the special
- /// emitExit() call, false if the default codegen is used.
- bool HasBeenEmitted = false;
- JumpDest ExitBlock;
- JumpDest ContBlock;
- };
-
- SmallVector<CancelExit, 8> Stack;
-
- public:
- OpenMPCancelExitStack() : Stack(1) {}
- ~OpenMPCancelExitStack() = default;
- /// Fetches the exit block for the current OpenMP construct.
- JumpDest getExitBlock() const { return Stack.back().ExitBlock; }
- /// Emits exit block with special codegen procedure specific for the related
- /// OpenMP construct + emits code for normal construct cleanup.
- void emitExit(CodeGenFunction &CGF, OpenMPDirectiveKind Kind,
- const llvm::function_ref<void(CodeGenFunction &)> CodeGen) {
- if (Stack.back().Kind == Kind && getExitBlock().isValid()) {
- assert(CGF.getOMPCancelDestination(Kind).isValid());
- assert(CGF.HaveInsertPoint());
- assert(!Stack.back().HasBeenEmitted);
- auto IP = CGF.Builder.saveAndClearIP();
- CGF.EmitBlock(Stack.back().ExitBlock.getBlock());
- CodeGen(CGF);
- CGF.EmitBranch(Stack.back().ContBlock.getBlock());
- CGF.Builder.restoreIP(IP);
- Stack.back().HasBeenEmitted = true;
- }
- CodeGen(CGF);
- }
- /// Enter the cancel supporting \a Kind construct.
- /// \param Kind OpenMP directive that supports cancel constructs.
- /// \param HasCancel true, if the construct has inner cancel directive,
- /// false otherwise.
- void enter(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, bool HasCancel) {
- Stack.push_back({Kind,
- HasCancel ? CGF.getJumpDestInCurrentScope("cancel.exit")
- : JumpDest(),
- HasCancel ? CGF.getJumpDestInCurrentScope("cancel.cont")
- : JumpDest()});
- }
- /// Emits default exit point for the cancel construct (if the special one
- /// has not be used) + join point for cancel/normal exits.
- void exit(CodeGenFunction &CGF) {
- if (getExitBlock().isValid()) {
- assert(CGF.getOMPCancelDestination(Stack.back().Kind).isValid());
- bool HaveIP = CGF.HaveInsertPoint();
- if (!Stack.back().HasBeenEmitted) {
- if (HaveIP)
- CGF.EmitBranchThroughCleanup(Stack.back().ContBlock);
- CGF.EmitBlock(Stack.back().ExitBlock.getBlock());
- CGF.EmitBranchThroughCleanup(Stack.back().ContBlock);
- }
- CGF.EmitBlock(Stack.back().ContBlock.getBlock());
- if (!HaveIP) {
- CGF.Builder.CreateUnreachable();
- CGF.Builder.ClearInsertionPoint();
- }
- }
- Stack.pop_back();
- }
- };
- OpenMPCancelExitStack OMPCancelStack;
-
- CodeGenPGO PGO;
-
- /// Calculate branch weights appropriate for PGO data
- llvm::MDNode *createProfileWeights(uint64_t TrueCount, uint64_t FalseCount);
- llvm::MDNode *createProfileWeights(ArrayRef<uint64_t> Weights);
- llvm::MDNode *createProfileWeightsForLoop(const Stmt *Cond,
- uint64_t LoopCount);
-
-public:
- /// Increment the profiler's counter for the given statement by \p StepV.
- /// If \p StepV is null, the default increment is 1.
- void incrementProfileCounter(const Stmt *S, llvm::Value *StepV = nullptr) {
- if (CGM.getCodeGenOpts().hasProfileClangInstr())
- PGO.emitCounterIncrement(Builder, S, StepV);
- PGO.setCurrentStmt(S);
- }
-
- /// Get the profiler's count for the given statement.
- uint64_t getProfileCount(const Stmt *S) {
- Optional<uint64_t> Count = PGO.getStmtCount(S);
- if (!Count.hasValue())
- return 0;
- return *Count;
- }
-
- /// Set the profiler's current count.
- void setCurrentProfileCount(uint64_t Count) {
- PGO.setCurrentRegionCount(Count);
- }
-
- /// Get the profiler's current count. This is generally the count for the most
- /// recently incremented counter.
- uint64_t getCurrentProfileCount() {
- return PGO.getCurrentRegionCount();
- }
-
-private:
-
- /// SwitchInsn - This is nearest current switch instruction. It is null if
- /// current context is not in a switch.
- llvm::SwitchInst *SwitchInsn = nullptr;
- /// The branch weights of SwitchInsn when doing instrumentation based PGO.
- SmallVector<uint64_t, 16> *SwitchWeights = nullptr;
-
- /// CaseRangeBlock - This block holds if condition check for last case
- /// statement range in current switch instruction.
- llvm::BasicBlock *CaseRangeBlock = nullptr;
-
- /// OpaqueLValues - Keeps track of the current set of opaque value
- /// expressions.
- llvm::DenseMap<const OpaqueValueExpr *, LValue> OpaqueLValues;
- llvm::DenseMap<const OpaqueValueExpr *, RValue> OpaqueRValues;
-
- // VLASizeMap - This keeps track of the associated size for each VLA type.
- // We track this by the size expression rather than the type itself because
- // in certain situations, like a const qualifier applied to an VLA typedef,
- // multiple VLA types can share the same size expression.
- // FIXME: Maybe this could be a stack of maps that is pushed/popped as we
- // enter/leave scopes.
- llvm::DenseMap<const Expr*, llvm::Value*> VLASizeMap;
-
- /// A block containing a single 'unreachable' instruction. Created
- /// lazily by getUnreachableBlock().
- llvm::BasicBlock *UnreachableBlock = nullptr;
-
- /// Counts of the number return expressions in the function.
- unsigned NumReturnExprs = 0;
-
- /// Count the number of simple (constant) return expressions in the function.
- unsigned NumSimpleReturnExprs = 0;
-
- /// The last regular (non-return) debug location (breakpoint) in the function.
- SourceLocation LastStopPoint;
-
-public:
- /// A scope within which we are constructing the fields of an object which
- /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use
- /// if we need to evaluate a CXXDefaultInitExpr within the evaluation.
- class FieldConstructionScope {
- public:
- FieldConstructionScope(CodeGenFunction &CGF, Address This)
- : CGF(CGF), OldCXXDefaultInitExprThis(CGF.CXXDefaultInitExprThis) {
- CGF.CXXDefaultInitExprThis = This;
- }
- ~FieldConstructionScope() {
- CGF.CXXDefaultInitExprThis = OldCXXDefaultInitExprThis;
- }
-
- private:
- CodeGenFunction &CGF;
- Address OldCXXDefaultInitExprThis;
- };
-
- /// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this'
- /// is overridden to be the object under construction.
- class CXXDefaultInitExprScope {
- public:
- CXXDefaultInitExprScope(CodeGenFunction &CGF)
- : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue),
- OldCXXThisAlignment(CGF.CXXThisAlignment) {
- CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getPointer();
- CGF.CXXThisAlignment = CGF.CXXDefaultInitExprThis.getAlignment();
- }
- ~CXXDefaultInitExprScope() {
- CGF.CXXThisValue = OldCXXThisValue;
- CGF.CXXThisAlignment = OldCXXThisAlignment;
- }
-
- public:
- CodeGenFunction &CGF;
- llvm::Value *OldCXXThisValue;
- CharUnits OldCXXThisAlignment;
- };
-
- /// The scope of an ArrayInitLoopExpr. Within this scope, the value of the
- /// current loop index is overridden.
- class ArrayInitLoopExprScope {
- public:
- ArrayInitLoopExprScope(CodeGenFunction &CGF, llvm::Value *Index)
- : CGF(CGF), OldArrayInitIndex(CGF.ArrayInitIndex) {
- CGF.ArrayInitIndex = Index;
- }
- ~ArrayInitLoopExprScope() {
- CGF.ArrayInitIndex = OldArrayInitIndex;
- }
-
- private:
- CodeGenFunction &CGF;
- llvm::Value *OldArrayInitIndex;
- };
-
- class InlinedInheritingConstructorScope {
- public:
- InlinedInheritingConstructorScope(CodeGenFunction &CGF, GlobalDecl GD)
- : CGF(CGF), OldCurGD(CGF.CurGD), OldCurFuncDecl(CGF.CurFuncDecl),
- OldCurCodeDecl(CGF.CurCodeDecl),
- OldCXXABIThisDecl(CGF.CXXABIThisDecl),
- OldCXXABIThisValue(CGF.CXXABIThisValue),
- OldCXXThisValue(CGF.CXXThisValue),
- OldCXXABIThisAlignment(CGF.CXXABIThisAlignment),
- OldCXXThisAlignment(CGF.CXXThisAlignment),
- OldReturnValue(CGF.ReturnValue), OldFnRetTy(CGF.FnRetTy),
- OldCXXInheritedCtorInitExprArgs(
- std::move(CGF.CXXInheritedCtorInitExprArgs)) {
- CGF.CurGD = GD;
- CGF.CurFuncDecl = CGF.CurCodeDecl =
- cast<CXXConstructorDecl>(GD.getDecl());
- CGF.CXXABIThisDecl = nullptr;
- CGF.CXXABIThisValue = nullptr;
- CGF.CXXThisValue = nullptr;
- CGF.CXXABIThisAlignment = CharUnits();
- CGF.CXXThisAlignment = CharUnits();
- CGF.ReturnValue = Address::invalid();
- CGF.FnRetTy = QualType();
- CGF.CXXInheritedCtorInitExprArgs.clear();
- }
- ~InlinedInheritingConstructorScope() {
- CGF.CurGD = OldCurGD;
- CGF.CurFuncDecl = OldCurFuncDecl;
- CGF.CurCodeDecl = OldCurCodeDecl;
- CGF.CXXABIThisDecl = OldCXXABIThisDecl;
- CGF.CXXABIThisValue = OldCXXABIThisValue;
- CGF.CXXThisValue = OldCXXThisValue;
- CGF.CXXABIThisAlignment = OldCXXABIThisAlignment;
- CGF.CXXThisAlignment = OldCXXThisAlignment;
- CGF.ReturnValue = OldReturnValue;
- CGF.FnRetTy = OldFnRetTy;
- CGF.CXXInheritedCtorInitExprArgs =
- std::move(OldCXXInheritedCtorInitExprArgs);
- }
-
- private:
- CodeGenFunction &CGF;
- GlobalDecl OldCurGD;
- const Decl *OldCurFuncDecl;
- const Decl *OldCurCodeDecl;
- ImplicitParamDecl *OldCXXABIThisDecl;
- llvm::Value *OldCXXABIThisValue;
- llvm::Value *OldCXXThisValue;
- CharUnits OldCXXABIThisAlignment;
- CharUnits OldCXXThisAlignment;
- Address OldReturnValue;
- QualType OldFnRetTy;
- CallArgList OldCXXInheritedCtorInitExprArgs;
- };
-
-private:
- /// CXXThisDecl - When generating code for a C++ member function,
- /// this will hold the implicit 'this' declaration.
- ImplicitParamDecl *CXXABIThisDecl = nullptr;
- llvm::Value *CXXABIThisValue = nullptr;
- llvm::Value *CXXThisValue = nullptr;
- CharUnits CXXABIThisAlignment;
- CharUnits CXXThisAlignment;
-
- /// The value of 'this' to use when evaluating CXXDefaultInitExprs within
- /// this expression.
- Address CXXDefaultInitExprThis = Address::invalid();
-
- /// The current array initialization index when evaluating an
- /// ArrayInitIndexExpr within an ArrayInitLoopExpr.
- llvm::Value *ArrayInitIndex = nullptr;
-
- /// The values of function arguments to use when evaluating
- /// CXXInheritedCtorInitExprs within this context.
- CallArgList CXXInheritedCtorInitExprArgs;
-
- /// CXXStructorImplicitParamDecl - When generating code for a constructor or
- /// destructor, this will hold the implicit argument (e.g. VTT).
- ImplicitParamDecl *CXXStructorImplicitParamDecl = nullptr;
- llvm::Value *CXXStructorImplicitParamValue = nullptr;
-
- /// OutermostConditional - Points to the outermost active
- /// conditional control. This is used so that we know if a
- /// temporary should be destroyed conditionally.
- ConditionalEvaluation *OutermostConditional = nullptr;
-
- /// The current lexical scope.
- LexicalScope *CurLexicalScope = nullptr;
-
- /// The current source location that should be used for exception
- /// handling code.
- SourceLocation CurEHLocation;
-
- /// BlockByrefInfos - For each __block variable, contains
- /// information about the layout of the variable.
- llvm::DenseMap<const ValueDecl *, BlockByrefInfo> BlockByrefInfos;
-
- /// Used by -fsanitize=nullability-return to determine whether the return
- /// value can be checked.
- llvm::Value *RetValNullabilityPrecondition = nullptr;
-
- /// Check if -fsanitize=nullability-return instrumentation is required for
- /// this function.
- bool requiresReturnValueNullabilityCheck() const {
- return RetValNullabilityPrecondition;
- }
-
- /// Used to store precise source locations for return statements by the
- /// runtime return value checks.
- Address ReturnLocation = Address::invalid();
-
- /// Check if the return value of this function requires sanitization.
- bool requiresReturnValueCheck() const {
- return requiresReturnValueNullabilityCheck() ||
- (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
- CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>());
- }
-
- llvm::BasicBlock *TerminateLandingPad = nullptr;
- llvm::BasicBlock *TerminateHandler = nullptr;
- llvm::BasicBlock *TrapBB = nullptr;
-
- /// Terminate funclets keyed by parent funclet pad.
- llvm::MapVector<llvm::Value *, llvm::BasicBlock *> TerminateFunclets;
-
- /// Largest vector width used in ths function. Will be used to create a
- /// function attribute.
- unsigned LargestVectorWidth = 0;
-
- /// True if we need emit the life-time markers.
- const bool ShouldEmitLifetimeMarkers;
-
- /// Add OpenCL kernel arg metadata and the kernel attribute metadata to
- /// the function metadata.
- void EmitOpenCLKernelMetadata(const FunctionDecl *FD,
- llvm::Function *Fn);
-
-public:
- CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext=false);
- ~CodeGenFunction();
-
- CodeGenTypes &getTypes() const { return CGM.getTypes(); }
- ASTContext &getContext() const { return CGM.getContext(); }
- CGDebugInfo *getDebugInfo() {
- if (DisableDebugInfo)
- return nullptr;
- return DebugInfo;
- }
- void disableDebugInfo() { DisableDebugInfo = true; }
- void enableDebugInfo() { DisableDebugInfo = false; }
-
- bool shouldUseFusedARCCalls() {
- return CGM.getCodeGenOpts().OptimizationLevel == 0;
- }
-
- const LangOptions &getLangOpts() const { return CGM.getLangOpts(); }
-
- /// Returns a pointer to the function's exception object and selector slot,
- /// which is assigned in every landing pad.
- Address getExceptionSlot();
- Address getEHSelectorSlot();
-
- /// Returns the contents of the function's exception object and selector
- /// slots.
- llvm::Value *getExceptionFromSlot();
- llvm::Value *getSelectorFromSlot();
-
- Address getNormalCleanupDestSlot();
-
- llvm::BasicBlock *getUnreachableBlock() {
- if (!UnreachableBlock) {
- UnreachableBlock = createBasicBlock("unreachable");
- new llvm::UnreachableInst(getLLVMContext(), UnreachableBlock);
- }
- return UnreachableBlock;
- }
-
- llvm::BasicBlock *getInvokeDest() {
- if (!EHStack.requiresLandingPad()) return nullptr;
- return getInvokeDestImpl();
- }
-
- bool currentFunctionUsesSEHTry() const { return CurSEHParent != nullptr; }
-
- const TargetInfo &getTarget() const { return Target; }
- llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
- const TargetCodeGenInfo &getTargetHooks() const {
- return CGM.getTargetCodeGenInfo();
- }
-
- //===--------------------------------------------------------------------===//
- // Cleanups
- //===--------------------------------------------------------------------===//
-
- typedef void Destroyer(CodeGenFunction &CGF, Address addr, QualType ty);
-
- void pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
- Address arrayEndPointer,
- QualType elementType,
- CharUnits elementAlignment,
- Destroyer *destroyer);
- void pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
- llvm::Value *arrayEnd,
- QualType elementType,
- CharUnits elementAlignment,
- Destroyer *destroyer);
-
- void pushDestroy(QualType::DestructionKind dtorKind,
- Address addr, QualType type);
- void pushEHDestroy(QualType::DestructionKind dtorKind,
- Address addr, QualType type);
- void pushDestroy(CleanupKind kind, Address addr, QualType type,
- Destroyer *destroyer, bool useEHCleanupForArray);
- void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr,
- QualType type, Destroyer *destroyer,
- bool useEHCleanupForArray);
- void pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
- llvm::Value *CompletePtr,
- QualType ElementType);
- void pushStackRestore(CleanupKind kind, Address SPMem);
- void emitDestroy(Address addr, QualType type, Destroyer *destroyer,
- bool useEHCleanupForArray);
- llvm::Function *generateDestroyHelper(Address addr, QualType type,
- Destroyer *destroyer,
- bool useEHCleanupForArray,
- const VarDecl *VD);
- void emitArrayDestroy(llvm::Value *begin, llvm::Value *end,
- QualType elementType, CharUnits elementAlign,
- Destroyer *destroyer,
- bool checkZeroLength, bool useEHCleanup);
-
- Destroyer *getDestroyer(QualType::DestructionKind destructionKind);
-
- /// Determines whether an EH cleanup is required to destroy a type
- /// with the given destruction kind.
- bool needsEHCleanup(QualType::DestructionKind kind) {
- switch (kind) {
- case QualType::DK_none:
- return false;
- case QualType::DK_cxx_destructor:
- case QualType::DK_objc_weak_lifetime:
- case QualType::DK_nontrivial_c_struct:
- return getLangOpts().Exceptions;
- case QualType::DK_objc_strong_lifetime:
- return getLangOpts().Exceptions &&
- CGM.getCodeGenOpts().ObjCAutoRefCountExceptions;
- }
- llvm_unreachable("bad destruction kind");
- }
-
- CleanupKind getCleanupKind(QualType::DestructionKind kind) {
- return (needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup);
- }
-
- //===--------------------------------------------------------------------===//
- // Objective-C
- //===--------------------------------------------------------------------===//
-
- void GenerateObjCMethod(const ObjCMethodDecl *OMD);
-
- void StartObjCMethod(const ObjCMethodDecl *MD, const ObjCContainerDecl *CD);
-
- /// GenerateObjCGetter - Synthesize an Objective-C property getter function.
- void GenerateObjCGetter(ObjCImplementationDecl *IMP,
- const ObjCPropertyImplDecl *PID);
- void generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl,
- const ObjCMethodDecl *GetterMothodDecl,
- llvm::Constant *AtomicHelperFn);
-
- void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
- ObjCMethodDecl *MD, bool ctor);
-
- /// GenerateObjCSetter - Synthesize an Objective-C property setter function
- /// for the given property.
- void GenerateObjCSetter(ObjCImplementationDecl *IMP,
- const ObjCPropertyImplDecl *PID);
- void generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl,
- llvm::Constant *AtomicHelperFn);
-
- //===--------------------------------------------------------------------===//
- // Block Bits
- //===--------------------------------------------------------------------===//
-
- /// Emit block literal.
- /// \return an LLVM value which is a pointer to a struct which contains
- /// information about the block, including the block invoke function, the
- /// captured variables, etc.
- llvm::Value *EmitBlockLiteral(const BlockExpr *);
- static void destroyBlockInfos(CGBlockInfo *info);
-
- llvm::Function *GenerateBlockFunction(GlobalDecl GD,
- const CGBlockInfo &Info,
- const DeclMapTy &ldm,
- bool IsLambdaConversionToBlock,
- bool BuildGlobalBlock);
-
- /// Check if \p T is a C++ class that has a destructor that can throw.
- static bool cxxDestructorCanThrow(QualType T);
-
- llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo);
- llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo);
- llvm::Constant *GenerateObjCAtomicSetterCopyHelperFunction(
- const ObjCPropertyImplDecl *PID);
- llvm::Constant *GenerateObjCAtomicGetterCopyHelperFunction(
- const ObjCPropertyImplDecl *PID);
- llvm::Value *EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty);
-
- void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags,
- bool CanThrow);
-
- class AutoVarEmission;
-
- void emitByrefStructureInit(const AutoVarEmission &emission);
-
- /// Enter a cleanup to destroy a __block variable. Note that this
- /// cleanup should be a no-op if the variable hasn't left the stack
- /// yet; if a cleanup is required for the variable itself, that needs
- /// to be done externally.
- ///
- /// \param Kind Cleanup kind.
- ///
- /// \param Addr When \p LoadBlockVarAddr is false, the address of the __block
- /// structure that will be passed to _Block_object_dispose. When
- /// \p LoadBlockVarAddr is true, the address of the field of the block
- /// structure that holds the address of the __block structure.
- ///
- /// \param Flags The flag that will be passed to _Block_object_dispose.
- ///
- /// \param LoadBlockVarAddr Indicates whether we need to emit a load from
- /// \p Addr to get the address of the __block structure.
- void enterByrefCleanup(CleanupKind Kind, Address Addr, BlockFieldFlags Flags,
- bool LoadBlockVarAddr, bool CanThrow);
-
- void setBlockContextParameter(const ImplicitParamDecl *D, unsigned argNum,
- llvm::Value *ptr);
-
- Address LoadBlockStruct();
- Address GetAddrOfBlockDecl(const VarDecl *var);
-
- /// BuildBlockByrefAddress - Computes the location of the
- /// data in a variable which is declared as __block.
- Address emitBlockByrefAddress(Address baseAddr, const VarDecl *V,
- bool followForward = true);
- Address emitBlockByrefAddress(Address baseAddr,
- const BlockByrefInfo &info,
- bool followForward,
- const llvm::Twine &name);
-
- const BlockByrefInfo &getBlockByrefInfo(const VarDecl *var);
-
- QualType BuildFunctionArgList(GlobalDecl GD, FunctionArgList &Args);
-
- void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
- const CGFunctionInfo &FnInfo);
-
- /// Annotate the function with an attribute that disables TSan checking at
- /// runtime.
- void markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn);
-
- /// Emit code for the start of a function.
- /// \param Loc The location to be associated with the function.
- /// \param StartLoc The location of the function body.
- void StartFunction(GlobalDecl GD,
- QualType RetTy,
- llvm::Function *Fn,
- const CGFunctionInfo &FnInfo,
- const FunctionArgList &Args,
- SourceLocation Loc = SourceLocation(),
- SourceLocation StartLoc = SourceLocation());
-
- static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor);
-
- void EmitConstructorBody(FunctionArgList &Args);
- void EmitDestructorBody(FunctionArgList &Args);
- void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
- void EmitFunctionBody(const Stmt *Body);
- void EmitBlockWithFallThrough(llvm::BasicBlock *BB, const Stmt *S);
-
- void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
- CallArgList &CallArgs);
- void EmitLambdaBlockInvokeBody();
- void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD);
- void EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD);
- void EmitAsanPrologueOrEpilogue(bool Prologue);
-
- /// Emit the unified return block, trying to avoid its emission when
- /// possible.
- /// \return The debug location of the user written return statement if the
- /// return block is is avoided.
- llvm::DebugLoc EmitReturnBlock();
-
- /// FinishFunction - Complete IR generation of the current function. It is
- /// legal to call this function even if there is no current insertion point.
- void FinishFunction(SourceLocation EndLoc=SourceLocation());
-
- void StartThunk(llvm::Function *Fn, GlobalDecl GD,
- const CGFunctionInfo &FnInfo, bool IsUnprototyped);
-
- void EmitCallAndReturnForThunk(llvm::Constant *Callee, const ThunkInfo *Thunk,
- bool IsUnprototyped);
-
- void FinishThunk();
-
- /// Emit a musttail call for a thunk with a potentially adjusted this pointer.
- void EmitMustTailThunk(GlobalDecl GD, llvm::Value *AdjustedThisPtr,
- llvm::Value *Callee);
-
- /// Generate a thunk for the given method.
- void generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
- GlobalDecl GD, const ThunkInfo &Thunk,
- bool IsUnprototyped);
-
- llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn,
- const CGFunctionInfo &FnInfo,
- GlobalDecl GD, const ThunkInfo &Thunk);
-
- void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
- FunctionArgList &Args);
-
- void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init);
-
- /// Struct with all information about dynamic [sub]class needed to set vptr.
- struct VPtr {
- BaseSubobject Base;
- const CXXRecordDecl *NearestVBase;
- CharUnits OffsetFromNearestVBase;
- const CXXRecordDecl *VTableClass;
- };
-
- /// Initialize the vtable pointer of the given subobject.
- void InitializeVTablePointer(const VPtr &vptr);
-
- typedef llvm::SmallVector<VPtr, 4> VPtrsVector;
-
- typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
- VPtrsVector getVTablePointers(const CXXRecordDecl *VTableClass);
-
- void getVTablePointers(BaseSubobject Base, const CXXRecordDecl *NearestVBase,
- CharUnits OffsetFromNearestVBase,
- bool BaseIsNonVirtualPrimaryBase,
- const CXXRecordDecl *VTableClass,
- VisitedVirtualBasesSetTy &VBases, VPtrsVector &vptrs);
-
- void InitializeVTablePointers(const CXXRecordDecl *ClassDecl);
-
- /// GetVTablePtr - Return the Value of the vtable pointer member pointed
- /// to by This.
- llvm::Value *GetVTablePtr(Address This, llvm::Type *VTableTy,
- const CXXRecordDecl *VTableClass);
-
- enum CFITypeCheckKind {
- CFITCK_VCall,
- CFITCK_NVCall,
- CFITCK_DerivedCast,
- CFITCK_UnrelatedCast,
- CFITCK_ICall,
- CFITCK_NVMFCall,
- CFITCK_VMFCall,
- };
-
- /// Derived is the presumed address of an object of type T after a
- /// cast. If T is a polymorphic class type, emit a check that the virtual
- /// table for Derived belongs to a class derived from T.
- void EmitVTablePtrCheckForCast(QualType T, llvm::Value *Derived,
- bool MayBeNull, CFITypeCheckKind TCK,
- SourceLocation Loc);
-
- /// EmitVTablePtrCheckForCall - Virtual method MD is being called via VTable.
- /// If vptr CFI is enabled, emit a check that VTable is valid.
- void EmitVTablePtrCheckForCall(const CXXRecordDecl *RD, llvm::Value *VTable,
- CFITypeCheckKind TCK, SourceLocation Loc);
-
- /// EmitVTablePtrCheck - Emit a check that VTable is a valid virtual table for
- /// RD using llvm.type.test.
- void EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable,
- CFITypeCheckKind TCK, SourceLocation Loc);
-
- /// If whole-program virtual table optimization is enabled, emit an assumption
- /// that VTable is a member of RD's type identifier. Or, if vptr CFI is
- /// enabled, emit a check that VTable is a member of RD's type identifier.
- void EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
- llvm::Value *VTable, SourceLocation Loc);
-
- /// Returns whether we should perform a type checked load when loading a
- /// virtual function for virtual calls to members of RD. This is generally
- /// true when both vcall CFI and whole-program-vtables are enabled.
- bool ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD);
-
- /// Emit a type checked load from the given vtable.
- llvm::Value *EmitVTableTypeCheckedLoad(const CXXRecordDecl *RD, llvm::Value *VTable,
- uint64_t VTableByteOffset);
-
- /// EnterDtorCleanups - Enter the cleanups necessary to complete the
- /// given phase of destruction for a destructor. The end result
- /// should call destructors on members and base classes in reverse
- /// order of their construction.
- void EnterDtorCleanups(const CXXDestructorDecl *Dtor, CXXDtorType Type);
-
- /// ShouldInstrumentFunction - Return true if the current function should be
- /// instrumented with __cyg_profile_func_* calls
- bool ShouldInstrumentFunction();
-
- /// ShouldXRayInstrument - Return true if the current function should be
- /// instrumented with XRay nop sleds.
- bool ShouldXRayInstrumentFunction() const;
-
- /// AlwaysEmitXRayCustomEvents - Return true if we must unconditionally emit
- /// XRay custom event handling calls.
- bool AlwaysEmitXRayCustomEvents() const;
-
- /// AlwaysEmitXRayTypedEvents - Return true if clang must unconditionally emit
- /// XRay typed event handling calls.
- bool AlwaysEmitXRayTypedEvents() const;
-
- /// Encode an address into a form suitable for use in a function prologue.
- llvm::Constant *EncodeAddrForUseInPrologue(llvm::Function *F,
- llvm::Constant *Addr);
-
- /// Decode an address used in a function prologue, encoded by \c
- /// EncodeAddrForUseInPrologue.
- llvm::Value *DecodeAddrUsedInPrologue(llvm::Value *F,
- llvm::Value *EncodedAddr);
-
- /// EmitFunctionProlog - Emit the target specific LLVM code to load the
- /// arguments for the given function. This is also responsible for naming the
- /// LLVM function arguments.
- void EmitFunctionProlog(const CGFunctionInfo &FI,
- llvm::Function *Fn,
- const FunctionArgList &Args);
-
- /// EmitFunctionEpilog - Emit the target specific LLVM code to return the
- /// given temporary.
- void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc,
- SourceLocation EndLoc);
-
- /// Emit a test that checks if the return value \p RV is nonnull.
- void EmitReturnValueCheck(llvm::Value *RV);
-
- /// EmitStartEHSpec - Emit the start of the exception spec.
- void EmitStartEHSpec(const Decl *D);
-
- /// EmitEndEHSpec - Emit the end of the exception spec.
- void EmitEndEHSpec(const Decl *D);
-
- /// getTerminateLandingPad - Return a landing pad that just calls terminate.
- llvm::BasicBlock *getTerminateLandingPad();
-
- /// getTerminateLandingPad - Return a cleanup funclet that just calls
- /// terminate.
- llvm::BasicBlock *getTerminateFunclet();
-
- /// getTerminateHandler - Return a handler (not a landing pad, just
- /// a catch handler) that just calls terminate. This is used when
- /// a terminate scope encloses a try.
- llvm::BasicBlock *getTerminateHandler();
-
- llvm::Type *ConvertTypeForMem(QualType T);
- llvm::Type *ConvertType(QualType T);
- llvm::Type *ConvertType(const TypeDecl *T) {
- return ConvertType(getContext().getTypeDeclType(T));
- }
-
- /// LoadObjCSelf - Load the value of self. This function is only valid while
- /// generating code for an Objective-C method.
- llvm::Value *LoadObjCSelf();
-
- /// TypeOfSelfObject - Return type of object that this self represents.
- QualType TypeOfSelfObject();
-
- /// getEvaluationKind - Return the TypeEvaluationKind of QualType \c T.
- static TypeEvaluationKind getEvaluationKind(QualType T);
-
- static bool hasScalarEvaluationKind(QualType T) {
- return getEvaluationKind(T) == TEK_Scalar;
- }
-
- static bool hasAggregateEvaluationKind(QualType T) {
- return getEvaluationKind(T) == TEK_Aggregate;
- }
-
- /// createBasicBlock - Create an LLVM basic block.
- llvm::BasicBlock *createBasicBlock(const Twine &name = "",
- llvm::Function *parent = nullptr,
- llvm::BasicBlock *before = nullptr) {
- return llvm::BasicBlock::Create(getLLVMContext(), name, parent, before);
- }
-
- /// getBasicBlockForLabel - Return the LLVM basicblock that the specified
- /// label maps to.
- JumpDest getJumpDestForLabel(const LabelDecl *S);
-
- /// SimplifyForwardingBlocks - If the given basic block is only a branch to
- /// another basic block, simplify it. This assumes that no other code could
- /// potentially reference the basic block.
- void SimplifyForwardingBlocks(llvm::BasicBlock *BB);
-
- /// EmitBlock - Emit the given block \arg BB and set it as the insert point,
- /// adding a fall-through branch from the current insert block if
- /// necessary. It is legal to call this function even if there is no current
- /// insertion point.
- ///
- /// IsFinished - If true, indicates that the caller has finished emitting
- /// branches to the given block and does not expect to emit code into it. This
- /// means the block can be ignored if it is unreachable.
- void EmitBlock(llvm::BasicBlock *BB, bool IsFinished=false);
-
- /// EmitBlockAfterUses - Emit the given block somewhere hopefully
- /// near its uses, and leave the insertion point in it.
- void EmitBlockAfterUses(llvm::BasicBlock *BB);
-
- /// EmitBranch - Emit a branch to the specified basic block from the current
- /// insert block, taking care to avoid creation of branches from dummy
- /// blocks. It is legal to call this function even if there is no current
- /// insertion point.
- ///
- /// This function clears the current insertion point. The caller should follow
- /// calls to this function with calls to Emit*Block prior to generation new
- /// code.
- void EmitBranch(llvm::BasicBlock *Block);
-
- /// HaveInsertPoint - True if an insertion point is defined. If not, this
- /// indicates that the current code being emitted is unreachable.
- bool HaveInsertPoint() const {
- return Builder.GetInsertBlock() != nullptr;
- }
-
- /// EnsureInsertPoint - Ensure that an insertion point is defined so that
- /// emitted IR has a place to go. Note that by definition, if this function
- /// creates a block then that block is unreachable; callers may do better to
- /// detect when no insertion point is defined and simply skip IR generation.
- void EnsureInsertPoint() {
- if (!HaveInsertPoint())
- EmitBlock(createBasicBlock());
- }
-
- /// ErrorUnsupported - Print out an error that codegen doesn't support the
- /// specified stmt yet.
- void ErrorUnsupported(const Stmt *S, const char *Type);
-
- //===--------------------------------------------------------------------===//
- // Helpers
- //===--------------------------------------------------------------------===//
-
- LValue MakeAddrLValue(Address Addr, QualType T,
- AlignmentSource Source = AlignmentSource::Type) {
- return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source),
- CGM.getTBAAAccessInfo(T));
- }
-
- LValue MakeAddrLValue(Address Addr, QualType T, LValueBaseInfo BaseInfo,
- TBAAAccessInfo TBAAInfo) {
- return LValue::MakeAddr(Addr, T, getContext(), BaseInfo, TBAAInfo);
- }
-
- LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment,
- AlignmentSource Source = AlignmentSource::Type) {
- return LValue::MakeAddr(Address(V, Alignment), T, getContext(),
- LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T));
- }
-
- LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment,
- LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) {
- return LValue::MakeAddr(Address(V, Alignment), T, getContext(),
- BaseInfo, TBAAInfo);
- }
-
- LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T);
- LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T);
- CharUnits getNaturalTypeAlignment(QualType T,
- LValueBaseInfo *BaseInfo = nullptr,
- TBAAAccessInfo *TBAAInfo = nullptr,
- bool forPointeeType = false);
- CharUnits getNaturalPointeeTypeAlignment(QualType T,
- LValueBaseInfo *BaseInfo = nullptr,
- TBAAAccessInfo *TBAAInfo = nullptr);
-
- Address EmitLoadOfReference(LValue RefLVal,
- LValueBaseInfo *PointeeBaseInfo = nullptr,
- TBAAAccessInfo *PointeeTBAAInfo = nullptr);
- LValue EmitLoadOfReferenceLValue(LValue RefLVal);
- LValue EmitLoadOfReferenceLValue(Address RefAddr, QualType RefTy,
- AlignmentSource Source =
- AlignmentSource::Type) {
- LValue RefLVal = MakeAddrLValue(RefAddr, RefTy, LValueBaseInfo(Source),
- CGM.getTBAAAccessInfo(RefTy));
- return EmitLoadOfReferenceLValue(RefLVal);
- }
-
- Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy,
- LValueBaseInfo *BaseInfo = nullptr,
- TBAAAccessInfo *TBAAInfo = nullptr);
- LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy);
-
- /// CreateTempAlloca - This creates an alloca and inserts it into the entry
- /// block if \p ArraySize is nullptr, otherwise inserts it at the current
- /// insertion point of the builder. The caller is responsible for setting an
- /// appropriate alignment on
- /// the alloca.
- ///
- /// \p ArraySize is the number of array elements to be allocated if it
- /// is not nullptr.
- ///
- /// LangAS::Default is the address space of pointers to local variables and
- /// temporaries, as exposed in the source language. In certain
- /// configurations, this is not the same as the alloca address space, and a
- /// cast is needed to lift the pointer from the alloca AS into
- /// LangAS::Default. This can happen when the target uses a restricted
- /// address space for the stack but the source language requires
- /// LangAS::Default to be a generic address space. The latter condition is
- /// common for most programming languages; OpenCL is an exception in that
- /// LangAS::Default is the private address space, which naturally maps
- /// to the stack.
- ///
- /// Because the address of a temporary is often exposed to the program in
- /// various ways, this function will perform the cast. The original alloca
- /// instruction is returned through \p Alloca if it is not nullptr.
- ///
- /// The cast is not performaed in CreateTempAllocaWithoutCast. This is
- /// more efficient if the caller knows that the address will not be exposed.
- llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp",
- llvm::Value *ArraySize = nullptr);
- Address CreateTempAlloca(llvm::Type *Ty, CharUnits align,
- const Twine &Name = "tmp",
- llvm::Value *ArraySize = nullptr,
- Address *Alloca = nullptr);
- Address CreateTempAllocaWithoutCast(llvm::Type *Ty, CharUnits align,
- const Twine &Name = "tmp",
- llvm::Value *ArraySize = nullptr);
-
- /// CreateDefaultAlignedTempAlloca - This creates an alloca with the
- /// default ABI alignment of the given LLVM type.
- ///
- /// IMPORTANT NOTE: This is *not* generally the right alignment for
- /// any given AST type that happens to have been lowered to the
- /// given IR type. This should only ever be used for function-local,
- /// IR-driven manipulations like saving and restoring a value. Do
- /// not hand this address off to arbitrary IRGen routines, and especially
- /// do not pass it as an argument to a function that might expect a
- /// properly ABI-aligned value.
- Address CreateDefaultAlignTempAlloca(llvm::Type *Ty,
- const Twine &Name = "tmp");
-
- /// InitTempAlloca - Provide an initial value for the given alloca which
- /// will be observable at all locations in the function.
- ///
- /// The address should be something that was returned from one of
- /// the CreateTempAlloca or CreateMemTemp routines, and the
- /// initializer must be valid in the entry block (i.e. it must
- /// either be a constant or an argument value).
- void InitTempAlloca(Address Alloca, llvm::Value *Value);
-
- /// CreateIRTemp - Create a temporary IR object of the given type, with
- /// appropriate alignment. This routine should only be used when an temporary
- /// value needs to be stored into an alloca (for example, to avoid explicit
- /// PHI construction), but the type is the IR type, not the type appropriate
- /// for storing in memory.
- ///
- /// That is, this is exactly equivalent to CreateMemTemp, but calling
- /// ConvertType instead of ConvertTypeForMem.
- Address CreateIRTemp(QualType T, const Twine &Name = "tmp");
-
- /// CreateMemTemp - Create a temporary memory object of the given type, with
- /// appropriate alignmen and cast it to the default address space. Returns
- /// the original alloca instruction by \p Alloca if it is not nullptr.
- Address CreateMemTemp(QualType T, const Twine &Name = "tmp",
- Address *Alloca = nullptr);
- Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp",
- Address *Alloca = nullptr);
-
- /// CreateMemTemp - Create a temporary memory object of the given type, with
- /// appropriate alignmen without casting it to the default address space.
- Address CreateMemTempWithoutCast(QualType T, const Twine &Name = "tmp");
- Address CreateMemTempWithoutCast(QualType T, CharUnits Align,
- const Twine &Name = "tmp");
-
- /// CreateAggTemp - Create a temporary memory object for the given
- /// aggregate type.
- AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp") {
- return AggValueSlot::forAddr(CreateMemTemp(T, Name),
- T.getQualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap);
- }
-
- /// Emit a cast to void* in the appropriate address space.
- llvm::Value *EmitCastToVoidPtr(llvm::Value *value);
-
- /// EvaluateExprAsBool - Perform the usual unary conversions on the specified
- /// expression and compare the result against zero, returning an Int1Ty value.
- llvm::Value *EvaluateExprAsBool(const Expr *E);
-
- /// EmitIgnoredExpr - Emit an expression in a context which ignores the result.
- void EmitIgnoredExpr(const Expr *E);
-
- /// EmitAnyExpr - Emit code to compute the specified expression which can have
- /// any type. The result is returned as an RValue struct. If this is an
- /// aggregate expression, the aggloc/agglocvolatile arguments indicate where
- /// the result should be returned.
- ///
- /// \param ignoreResult True if the resulting value isn't used.
- RValue EmitAnyExpr(const Expr *E,
- AggValueSlot aggSlot = AggValueSlot::ignored(),
- bool ignoreResult = false);
-
- // EmitVAListRef - Emit a "reference" to a va_list; this is either the address
- // or the value of the expression, depending on how va_list is defined.
- Address EmitVAListRef(const Expr *E);
-
- /// Emit a "reference" to a __builtin_ms_va_list; this is
- /// always the value of the expression, because a __builtin_ms_va_list is a
- /// pointer to a char.
- Address EmitMSVAListRef(const Expr *E);
-
- /// EmitAnyExprToTemp - Similarly to EmitAnyExpr(), however, the result will
- /// always be accessible even if no aggregate location is provided.
- RValue EmitAnyExprToTemp(const Expr *E);
-
- /// EmitAnyExprToMem - Emits the code necessary to evaluate an
- /// arbitrary expression into the given memory location.
- void EmitAnyExprToMem(const Expr *E, Address Location,
- Qualifiers Quals, bool IsInitializer);
-
- void EmitAnyExprToExn(const Expr *E, Address Addr);
-
- /// EmitExprAsInit - Emits the code necessary to initialize a
- /// location in memory with the given initializer.
- void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue,
- bool capturedByInit);
-
- /// hasVolatileMember - returns true if aggregate type has a volatile
- /// member.
- bool hasVolatileMember(QualType T) {
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
- return RD->hasVolatileMember();
- }
- return false;
- }
-
- /// Determine whether a return value slot may overlap some other object.
- AggValueSlot::Overlap_t overlapForReturnValue() {
- // FIXME: Assuming no overlap here breaks guaranteed copy elision for base
- // class subobjects. These cases may need to be revisited depending on the
- // resolution of the relevant core issue.
- return AggValueSlot::DoesNotOverlap;
- }
-
- /// Determine whether a field initialization may overlap some other object.
- AggValueSlot::Overlap_t overlapForFieldInit(const FieldDecl *FD) {
- // FIXME: These cases can result in overlap as a result of P0840R0's
- // [[no_unique_address]] attribute. We can still infer NoOverlap in the
- // presence of that attribute if the field is within the nvsize of its
- // containing class, because non-virtual subobjects are initialized in
- // address order.
- return AggValueSlot::DoesNotOverlap;
- }
-
- /// Determine whether a base class initialization may overlap some other
- /// object.
- AggValueSlot::Overlap_t overlapForBaseInit(const CXXRecordDecl *RD,
- const CXXRecordDecl *BaseRD,
- bool IsVirtual);
-
- /// Emit an aggregate assignment.
- void EmitAggregateAssign(LValue Dest, LValue Src, QualType EltTy) {
- bool IsVolatile = hasVolatileMember(EltTy);
- EmitAggregateCopy(Dest, Src, EltTy, AggValueSlot::MayOverlap, IsVolatile);
- }
-
- void EmitAggregateCopyCtor(LValue Dest, LValue Src,
- AggValueSlot::Overlap_t MayOverlap) {
- EmitAggregateCopy(Dest, Src, Src.getType(), MayOverlap);
- }
-
- /// EmitAggregateCopy - Emit an aggregate copy.
- ///
- /// \param isVolatile \c true iff either the source or the destination is
- /// volatile.
- /// \param MayOverlap Whether the tail padding of the destination might be
- /// occupied by some other object. More efficient code can often be
- /// generated if not.
- void EmitAggregateCopy(LValue Dest, LValue Src, QualType EltTy,
- AggValueSlot::Overlap_t MayOverlap,
- bool isVolatile = false);
-
- /// GetAddrOfLocalVar - Return the address of a local variable.
- Address GetAddrOfLocalVar(const VarDecl *VD) {
- auto it = LocalDeclMap.find(VD);
- assert(it != LocalDeclMap.end() &&
- "Invalid argument to GetAddrOfLocalVar(), no decl!");
- return it->second;
- }
-
- /// Given an opaque value expression, return its LValue mapping if it exists,
- /// otherwise create one.
- LValue getOrCreateOpaqueLValueMapping(const OpaqueValueExpr *e);
-
- /// Given an opaque value expression, return its RValue mapping if it exists,
- /// otherwise create one.
- RValue getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e);
-
- /// Get the index of the current ArrayInitLoopExpr, if any.
- llvm::Value *getArrayInitIndex() { return ArrayInitIndex; }
-
- /// getAccessedFieldNo - Given an encoded value and a result number, return
- /// the input field number being accessed.
- static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
-
- llvm::BlockAddress *GetAddrOfLabel(const LabelDecl *L);
- llvm::BasicBlock *GetIndirectGotoBlock();
-
- /// Check if \p E is a C++ "this" pointer wrapped in value-preserving casts.
- static bool IsWrappedCXXThis(const Expr *E);
-
- /// EmitNullInitialization - Generate code to set a value of the given type to
- /// null, If the type contains data member pointers, they will be initialized
- /// to -1 in accordance with the Itanium C++ ABI.
- void EmitNullInitialization(Address DestPtr, QualType Ty);
-
- /// Emits a call to an LLVM variable-argument intrinsic, either
- /// \c llvm.va_start or \c llvm.va_end.
- /// \param ArgValue A reference to the \c va_list as emitted by either
- /// \c EmitVAListRef or \c EmitMSVAListRef.
- /// \param IsStart If \c true, emits a call to \c llvm.va_start; otherwise,
- /// calls \c llvm.va_end.
- llvm::Value *EmitVAStartEnd(llvm::Value *ArgValue, bool IsStart);
-
- /// Generate code to get an argument from the passed in pointer
- /// and update it accordingly.
- /// \param VE The \c VAArgExpr for which to generate code.
- /// \param VAListAddr Receives a reference to the \c va_list as emitted by
- /// either \c EmitVAListRef or \c EmitMSVAListRef.
- /// \returns A pointer to the argument.
- // FIXME: We should be able to get rid of this method and use the va_arg
- // instruction in LLVM instead once it works well enough.
- Address EmitVAArg(VAArgExpr *VE, Address &VAListAddr);
-
- /// emitArrayLength - Compute the length of an array, even if it's a
- /// VLA, and drill down to the base element type.
- llvm::Value *emitArrayLength(const ArrayType *arrayType,
- QualType &baseType,
- Address &addr);
-
- /// EmitVLASize - Capture all the sizes for the VLA expressions in
- /// the given variably-modified type and store them in the VLASizeMap.
- ///
- /// This function can be called with a null (unreachable) insert point.
- void EmitVariablyModifiedType(QualType Ty);
-
- struct VlaSizePair {
- llvm::Value *NumElts;
- QualType Type;
-
- VlaSizePair(llvm::Value *NE, QualType T) : NumElts(NE), Type(T) {}
- };
-
- /// Return the number of elements for a single dimension
- /// for the given array type.
- VlaSizePair getVLAElements1D(const VariableArrayType *vla);
- VlaSizePair getVLAElements1D(QualType vla);
-
- /// Returns an LLVM value that corresponds to the size,
- /// in non-variably-sized elements, of a variable length array type,
- /// plus that largest non-variably-sized element type. Assumes that
- /// the type has already been emitted with EmitVariablyModifiedType.
- VlaSizePair getVLASize(const VariableArrayType *vla);
- VlaSizePair getVLASize(QualType vla);
-
- /// LoadCXXThis - Load the value of 'this'. This function is only valid while
- /// generating code for an C++ member function.
- llvm::Value *LoadCXXThis() {
- assert(CXXThisValue && "no 'this' value for this function");
- return CXXThisValue;
- }
- Address LoadCXXThisAddress();
-
- /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
- /// virtual bases.
- // FIXME: Every place that calls LoadCXXVTT is something
- // that needs to be abstracted properly.
- llvm::Value *LoadCXXVTT() {
- assert(CXXStructorImplicitParamValue && "no VTT value for this function");
- return CXXStructorImplicitParamValue;
- }
-
- /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
- /// complete class to the given direct base.
- Address
- GetAddressOfDirectBaseInCompleteClass(Address Value,
- const CXXRecordDecl *Derived,
- const CXXRecordDecl *Base,
- bool BaseIsVirtual);
-
- static bool ShouldNullCheckClassCastValue(const CastExpr *Cast);
-
- /// GetAddressOfBaseClass - This function will add the necessary delta to the
- /// load of 'this' and returns address of the base class.
- Address GetAddressOfBaseClass(Address Value,
- const CXXRecordDecl *Derived,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd,
- bool NullCheckValue, SourceLocation Loc);
-
- Address GetAddressOfDerivedClass(Address Value,
- const CXXRecordDecl *Derived,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd,
- bool NullCheckValue);
-
- /// GetVTTParameter - Return the VTT parameter that should be passed to a
- /// base constructor/destructor with virtual bases.
- /// FIXME: VTTs are Itanium ABI-specific, so the definition should move
- /// to ItaniumCXXABI.cpp together with all the references to VTT.
- llvm::Value *GetVTTParameter(GlobalDecl GD, bool ForVirtualBase,
- bool Delegating);
-
- void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
- CXXCtorType CtorType,
- const FunctionArgList &Args,
- SourceLocation Loc);
- // It's important not to confuse this and the previous function. Delegating
- // constructors are the C++0x feature. The constructor delegate optimization
- // is used to reduce duplication in the base and complete consturctors where
- // they are substantially the same.
- void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
- const FunctionArgList &Args);
-
- /// Emit a call to an inheriting constructor (that is, one that invokes a
- /// constructor inherited from a base class) by inlining its definition. This
- /// is necessary if the ABI does not support forwarding the arguments to the
- /// base class constructor (because they're variadic or similar).
- void EmitInlinedInheritingCXXConstructorCall(const CXXConstructorDecl *Ctor,
- CXXCtorType CtorType,
- bool ForVirtualBase,
- bool Delegating,
- CallArgList &Args);
-
- /// Emit a call to a constructor inherited from a base class, passing the
- /// current constructor's arguments along unmodified (without even making
- /// a copy).
- void EmitInheritedCXXConstructorCall(const CXXConstructorDecl *D,
- bool ForVirtualBase, Address This,
- bool InheritedFromVBase,
- const CXXInheritedCtorInitExpr *E);
-
- void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, bool Delegating,
- Address This, const CXXConstructExpr *E,
- AggValueSlot::Overlap_t Overlap,
- bool NewPointerIsChecked);
-
- void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, bool Delegating,
- Address This, CallArgList &Args,
- AggValueSlot::Overlap_t Overlap,
- SourceLocation Loc,
- bool NewPointerIsChecked);
-
- /// Emit assumption load for all bases. Requires to be be called only on
- /// most-derived class and not under construction of the object.
- void EmitVTableAssumptionLoads(const CXXRecordDecl *ClassDecl, Address This);
-
- /// Emit assumption that vptr load == global vtable.
- void EmitVTableAssumptionLoad(const VPtr &vptr, Address This);
-
- void EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
- Address This, Address Src,
- const CXXConstructExpr *E);
-
- void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- const ArrayType *ArrayTy,
- Address ArrayPtr,
- const CXXConstructExpr *E,
- bool NewPointerIsChecked,
- bool ZeroInitialization = false);
-
- void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- llvm::Value *NumElements,
- Address ArrayPtr,
- const CXXConstructExpr *E,
- bool NewPointerIsChecked,
- bool ZeroInitialization = false);
-
- static Destroyer destroyCXXObject;
-
- void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
- bool ForVirtualBase, bool Delegating,
- Address This);
-
- void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
- llvm::Type *ElementTy, Address NewPtr,
- llvm::Value *NumElements,
- llvm::Value *AllocSizeWithoutCookie);
-
- void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
- Address Ptr);
-
- llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr);
- void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr);
-
- llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
- void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
-
- void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr,
- QualType DeleteTy, llvm::Value *NumElements = nullptr,
- CharUnits CookieSize = CharUnits());
-
- RValue EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
- const CallExpr *TheCallExpr, bool IsDelete);
-
- llvm::Value *EmitCXXTypeidExpr(const CXXTypeidExpr *E);
- llvm::Value *EmitDynamicCast(Address V, const CXXDynamicCastExpr *DCE);
- Address EmitCXXUuidofExpr(const CXXUuidofExpr *E);
-
- /// Situations in which we might emit a check for the suitability of a
- /// pointer or glvalue.
- enum TypeCheckKind {
- /// Checking the operand of a load. Must be suitably sized and aligned.
- TCK_Load,
- /// Checking the destination of a store. Must be suitably sized and aligned.
- TCK_Store,
- /// Checking the bound value in a reference binding. Must be suitably sized
- /// and aligned, but is not required to refer to an object (until the
- /// reference is used), per core issue 453.
- TCK_ReferenceBinding,
- /// Checking the object expression in a non-static data member access. Must
- /// be an object within its lifetime.
- TCK_MemberAccess,
- /// Checking the 'this' pointer for a call to a non-static member function.
- /// Must be an object within its lifetime.
- TCK_MemberCall,
- /// Checking the 'this' pointer for a constructor call.
- TCK_ConstructorCall,
- /// Checking the operand of a static_cast to a derived pointer type. Must be
- /// null or an object within its lifetime.
- TCK_DowncastPointer,
- /// Checking the operand of a static_cast to a derived reference type. Must
- /// be an object within its lifetime.
- TCK_DowncastReference,
- /// Checking the operand of a cast to a base object. Must be suitably sized
- /// and aligned.
- TCK_Upcast,
- /// Checking the operand of a cast to a virtual base object. Must be an
- /// object within its lifetime.
- TCK_UpcastToVirtualBase,
- /// Checking the value assigned to a _Nonnull pointer. Must not be null.
- TCK_NonnullAssign,
- /// Checking the operand of a dynamic_cast or a typeid expression. Must be
- /// null or an object within its lifetime.
- TCK_DynamicOperation
- };
-
- /// Determine whether the pointer type check \p TCK permits null pointers.
- static bool isNullPointerAllowed(TypeCheckKind TCK);
-
- /// Determine whether the pointer type check \p TCK requires a vptr check.
- static bool isVptrCheckRequired(TypeCheckKind TCK, QualType Ty);
-
- /// Whether any type-checking sanitizers are enabled. If \c false,
- /// calls to EmitTypeCheck can be skipped.
- bool sanitizePerformTypeCheck() const;
-
- /// Emit a check that \p V is the address of storage of the
- /// appropriate size and alignment for an object of type \p Type.
- void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
- QualType Type, CharUnits Alignment = CharUnits::Zero(),
- SanitizerSet SkippedChecks = SanitizerSet());
-
- /// Emit a check that \p Base points into an array object, which
- /// we can access at index \p Index. \p Accessed should be \c false if we
- /// this expression is used as an lvalue, for instance in "&Arr[Idx]".
- void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index,
- QualType IndexType, bool Accessed);
-
- llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
- bool isInc, bool isPre);
- ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
- bool isInc, bool isPre);
-
- /// Converts Location to a DebugLoc, if debug information is enabled.
- llvm::DebugLoc SourceLocToDebugLoc(SourceLocation Location);
-
-
- //===--------------------------------------------------------------------===//
- // Declaration Emission
- //===--------------------------------------------------------------------===//
-
- /// EmitDecl - Emit a declaration.
- ///
- /// This function can be called with a null (unreachable) insert point.
- void EmitDecl(const Decl &D);
-
- /// EmitVarDecl - Emit a local variable declaration.
- ///
- /// This function can be called with a null (unreachable) insert point.
- void EmitVarDecl(const VarDecl &D);
-
- void EmitScalarInit(const Expr *init, const ValueDecl *D, LValue lvalue,
- bool capturedByInit);
-
- typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
- llvm::Value *Address);
-
- /// Determine whether the given initializer is trivial in the sense
- /// that it requires no code to be generated.
- bool isTrivialInitializer(const Expr *Init);
-
- /// EmitAutoVarDecl - Emit an auto variable declaration.
- ///
- /// This function can be called with a null (unreachable) insert point.
- void EmitAutoVarDecl(const VarDecl &D);
-
- class AutoVarEmission {
- friend class CodeGenFunction;
-
- const VarDecl *Variable;
-
- /// The address of the alloca for languages with explicit address space
- /// (e.g. OpenCL) or alloca casted to generic pointer for address space
- /// agnostic languages (e.g. C++). Invalid if the variable was emitted
- /// as a global constant.
- Address Addr;
-
- llvm::Value *NRVOFlag;
-
- /// True if the variable is a __block variable that is captured by an
- /// escaping block.
- bool IsEscapingByRef;
-
- /// True if the variable is of aggregate type and has a constant
- /// initializer.
- bool IsConstantAggregate;
-
- /// Non-null if we should use lifetime annotations.
- llvm::Value *SizeForLifetimeMarkers;
-
- /// Address with original alloca instruction. Invalid if the variable was
- /// emitted as a global constant.
- Address AllocaAddr;
-
- struct Invalid {};
- AutoVarEmission(Invalid)
- : Variable(nullptr), Addr(Address::invalid()),
- AllocaAddr(Address::invalid()) {}
-
- AutoVarEmission(const VarDecl &variable)
- : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr),
- IsEscapingByRef(false), IsConstantAggregate(false),
- SizeForLifetimeMarkers(nullptr), AllocaAddr(Address::invalid()) {}
-
- bool wasEmittedAsGlobal() const { return !Addr.isValid(); }
-
- public:
- static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
-
- bool useLifetimeMarkers() const {
- return SizeForLifetimeMarkers != nullptr;
- }
- llvm::Value *getSizeForLifetimeMarkers() const {
- assert(useLifetimeMarkers());
- return SizeForLifetimeMarkers;
- }
-
- /// Returns the raw, allocated address, which is not necessarily
- /// the address of the object itself. It is casted to default
- /// address space for address space agnostic languages.
- Address getAllocatedAddress() const {
- return Addr;
- }
-
- /// Returns the address for the original alloca instruction.
- Address getOriginalAllocatedAddress() const { return AllocaAddr; }
-
- /// Returns the address of the object within this declaration.
- /// Note that this does not chase the forwarding pointer for
- /// __block decls.
- Address getObjectAddress(CodeGenFunction &CGF) const {
- if (!IsEscapingByRef) return Addr;
-
- return CGF.emitBlockByrefAddress(Addr, Variable, /*forward*/ false);
- }
- };
- AutoVarEmission EmitAutoVarAlloca(const VarDecl &var);
- void EmitAutoVarInit(const AutoVarEmission &emission);
- void EmitAutoVarCleanups(const AutoVarEmission &emission);
- void emitAutoVarTypeCleanup(const AutoVarEmission &emission,
- QualType::DestructionKind dtorKind);
-
- /// Emits the alloca and debug information for the size expressions for each
- /// dimension of an array. It registers the association of its (1-dimensional)
- /// QualTypes and size expression's debug node, so that CGDebugInfo can
- /// reference this node when creating the DISubrange object to describe the
- /// array types.
- void EmitAndRegisterVariableArrayDimensions(CGDebugInfo *DI,
- const VarDecl &D,
- bool EmitDebugInfo);
-
- void EmitStaticVarDecl(const VarDecl &D,
- llvm::GlobalValue::LinkageTypes Linkage);
-
- class ParamValue {
- llvm::Value *Value;
- unsigned Alignment;
- ParamValue(llvm::Value *V, unsigned A) : Value(V), Alignment(A) {}
- public:
- static ParamValue forDirect(llvm::Value *value) {
- return ParamValue(value, 0);
- }
- static ParamValue forIndirect(Address addr) {
- assert(!addr.getAlignment().isZero());
- return ParamValue(addr.getPointer(), addr.getAlignment().getQuantity());
- }
-
- bool isIndirect() const { return Alignment != 0; }
- llvm::Value *getAnyValue() const { return Value; }
-
- llvm::Value *getDirectValue() const {
- assert(!isIndirect());
- return Value;
- }
-
- Address getIndirectAddress() const {
- assert(isIndirect());
- return Address(Value, CharUnits::fromQuantity(Alignment));
- }
- };
-
- /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
- void EmitParmDecl(const VarDecl &D, ParamValue Arg, unsigned ArgNo);
-
- /// protectFromPeepholes - Protect a value that we're intending to
- /// store to the side, but which will probably be used later, from
- /// aggressive peepholing optimizations that might delete it.
- ///
- /// Pass the result to unprotectFromPeepholes to declare that
- /// protection is no longer required.
- ///
- /// There's no particular reason why this shouldn't apply to
- /// l-values, it's just that no existing peepholes work on pointers.
- PeepholeProtection protectFromPeepholes(RValue rvalue);
- void unprotectFromPeepholes(PeepholeProtection protection);
-
- void EmitAlignmentAssumptionCheck(llvm::Value *Ptr, QualType Ty,
- SourceLocation Loc,
- SourceLocation AssumptionLoc,
- llvm::Value *Alignment,
- llvm::Value *OffsetValue,
- llvm::Value *TheCheck,
- llvm::Instruction *Assumption);
-
- void EmitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty,
- SourceLocation Loc, SourceLocation AssumptionLoc,
- llvm::Value *Alignment,
- llvm::Value *OffsetValue = nullptr);
-
- void EmitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty,
- SourceLocation Loc, SourceLocation AssumptionLoc,
- unsigned Alignment,
- llvm::Value *OffsetValue = nullptr);
-
- void EmitAlignmentAssumption(llvm::Value *PtrValue, const Expr *E,
- SourceLocation AssumptionLoc, unsigned Alignment,
- llvm::Value *OffsetValue = nullptr);
-
- //===--------------------------------------------------------------------===//
- // Statement Emission
- //===--------------------------------------------------------------------===//
-
- /// EmitStopPoint - Emit a debug stoppoint if we are emitting debug info.
- void EmitStopPoint(const Stmt *S);
-
- /// EmitStmt - Emit the code for the statement \arg S. It is legal to call
- /// this function even if there is no current insertion point.
- ///
- /// This function may clear the current insertion point; callers should use
- /// EnsureInsertPoint if they wish to subsequently generate code without first
- /// calling EmitBlock, EmitBranch, or EmitStmt.
- void EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs = None);
-
- /// EmitSimpleStmt - Try to emit a "simple" statement which does not
- /// necessarily require an insertion point or debug information; typically
- /// because the statement amounts to a jump or a container of other
- /// statements.
- ///
- /// \return True if the statement was handled.
- bool EmitSimpleStmt(const Stmt *S);
-
- Address EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
- AggValueSlot AVS = AggValueSlot::ignored());
- Address EmitCompoundStmtWithoutScope(const CompoundStmt &S,
- bool GetLast = false,
- AggValueSlot AVS =
- AggValueSlot::ignored());
-
- /// EmitLabel - Emit the block for the given label. It is legal to call this
- /// function even if there is no current insertion point.
- void EmitLabel(const LabelDecl *D); // helper for EmitLabelStmt.
-
- void EmitLabelStmt(const LabelStmt &S);
- void EmitAttributedStmt(const AttributedStmt &S);
- void EmitGotoStmt(const GotoStmt &S);
- void EmitIndirectGotoStmt(const IndirectGotoStmt &S);
- void EmitIfStmt(const IfStmt &S);
-
- void EmitWhileStmt(const WhileStmt &S,
- ArrayRef<const Attr *> Attrs = None);
- void EmitDoStmt(const DoStmt &S, ArrayRef<const Attr *> Attrs = None);
- void EmitForStmt(const ForStmt &S,
- ArrayRef<const Attr *> Attrs = None);
- void EmitReturnStmt(const ReturnStmt &S);
- void EmitDeclStmt(const DeclStmt &S);
- void EmitBreakStmt(const BreakStmt &S);
- void EmitContinueStmt(const ContinueStmt &S);
- void EmitSwitchStmt(const SwitchStmt &S);
- void EmitDefaultStmt(const DefaultStmt &S);
- void EmitCaseStmt(const CaseStmt &S);
- void EmitCaseStmtRange(const CaseStmt &S);
- void EmitAsmStmt(const AsmStmt &S);
-
- void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
- void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
- void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
- void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
- void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S);
-
- void EmitCoroutineBody(const CoroutineBodyStmt &S);
- void EmitCoreturnStmt(const CoreturnStmt &S);
- RValue EmitCoawaitExpr(const CoawaitExpr &E,
- AggValueSlot aggSlot = AggValueSlot::ignored(),
- bool ignoreResult = false);
- LValue EmitCoawaitLValue(const CoawaitExpr *E);
- RValue EmitCoyieldExpr(const CoyieldExpr &E,
- AggValueSlot aggSlot = AggValueSlot::ignored(),
- bool ignoreResult = false);
- LValue EmitCoyieldLValue(const CoyieldExpr *E);
- RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID);
-
- void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
- void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
-
- void EmitCXXTryStmt(const CXXTryStmt &S);
- void EmitSEHTryStmt(const SEHTryStmt &S);
- void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
- void EnterSEHTryStmt(const SEHTryStmt &S);
- void ExitSEHTryStmt(const SEHTryStmt &S);
-
- void pushSEHCleanup(CleanupKind kind,
- llvm::Function *FinallyFunc);
- void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, bool IsFilter,
- const Stmt *OutlinedStmt);
-
- llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
- const SEHExceptStmt &Except);
-
- llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
- const SEHFinallyStmt &Finally);
-
- void EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,
- llvm::Value *ParentFP,
- llvm::Value *EntryEBP);
- llvm::Value *EmitSEHExceptionCode();
- llvm::Value *EmitSEHExceptionInfo();
- llvm::Value *EmitSEHAbnormalTermination();
-
- /// Emit simple code for OpenMP directives in Simd-only mode.
- void EmitSimpleOMPExecutableDirective(const OMPExecutableDirective &D);
-
- /// Scan the outlined statement for captures from the parent function. For
- /// each capture, mark the capture as escaped and emit a call to
- /// llvm.localrecover. Insert the localrecover result into the LocalDeclMap.
- void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt,
- bool IsFilter);
-
- /// Recovers the address of a local in a parent function. ParentVar is the
- /// address of the variable used in the immediate parent function. It can
- /// either be an alloca or a call to llvm.localrecover if there are nested
- /// outlined functions. ParentFP is the frame pointer of the outermost parent
- /// frame.
- Address recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
- Address ParentVar,
- llvm::Value *ParentFP);
-
- void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
- ArrayRef<const Attr *> Attrs = None);
-
- /// Controls insertion of cancellation exit blocks in worksharing constructs.
- class OMPCancelStackRAII {
- CodeGenFunction &CGF;
-
- public:
- OMPCancelStackRAII(CodeGenFunction &CGF, OpenMPDirectiveKind Kind,
- bool HasCancel)
- : CGF(CGF) {
- CGF.OMPCancelStack.enter(CGF, Kind, HasCancel);
- }
- ~OMPCancelStackRAII() { CGF.OMPCancelStack.exit(CGF); }
- };
-
- /// Returns calculated size of the specified type.
- llvm::Value *getTypeSize(QualType Ty);
- LValue InitCapturedStruct(const CapturedStmt &S);
- llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
- llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
- Address GenerateCapturedStmtArgument(const CapturedStmt &S);
- llvm::Function *GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S);
- void GenerateOpenMPCapturedVars(const CapturedStmt &S,
- SmallVectorImpl<llvm::Value *> &CapturedVars);
- void emitOMPSimpleStore(LValue LVal, RValue RVal, QualType RValTy,
- SourceLocation Loc);
- /// Perform element by element copying of arrays with type \a
- /// OriginalType from \a SrcAddr to \a DestAddr using copying procedure
- /// generated by \a CopyGen.
- ///
- /// \param DestAddr Address of the destination array.
- /// \param SrcAddr Address of the source array.
- /// \param OriginalType Type of destination and source arrays.
- /// \param CopyGen Copying procedure that copies value of single array element
- /// to another single array element.
- void EmitOMPAggregateAssign(
- Address DestAddr, Address SrcAddr, QualType OriginalType,
- const llvm::function_ref<void(Address, Address)> CopyGen);
- /// Emit proper copying of data from one variable to another.
- ///
- /// \param OriginalType Original type of the copied variables.
- /// \param DestAddr Destination address.
- /// \param SrcAddr Source address.
- /// \param DestVD Destination variable used in \a CopyExpr (for arrays, has
- /// type of the base array element).
- /// \param SrcVD Source variable used in \a CopyExpr (for arrays, has type of
- /// the base array element).
- /// \param Copy Actual copygin expression for copying data from \a SrcVD to \a
- /// DestVD.
- void EmitOMPCopy(QualType OriginalType,
- Address DestAddr, Address SrcAddr,
- const VarDecl *DestVD, const VarDecl *SrcVD,
- const Expr *Copy);
- /// Emit atomic update code for constructs: \a X = \a X \a BO \a E or
- /// \a X = \a E \a BO \a E.
- ///
- /// \param X Value to be updated.
- /// \param E Update value.
- /// \param BO Binary operation for update operation.
- /// \param IsXLHSInRHSPart true if \a X is LHS in RHS part of the update
- /// expression, false otherwise.
- /// \param AO Atomic ordering of the generated atomic instructions.
- /// \param CommonGen Code generator for complex expressions that cannot be
- /// expressed through atomicrmw instruction.
- /// \returns <true, OldAtomicValue> if simple 'atomicrmw' instruction was
- /// generated, <false, RValue::get(nullptr)> otherwise.
- std::pair<bool, RValue> EmitOMPAtomicSimpleUpdateExpr(
- LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart,
- llvm::AtomicOrdering AO, SourceLocation Loc,
- const llvm::function_ref<RValue(RValue)> CommonGen);
- bool EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
- OMPPrivateScope &PrivateScope);
- void EmitOMPPrivateClause(const OMPExecutableDirective &D,
- OMPPrivateScope &PrivateScope);
- void EmitOMPUseDevicePtrClause(
- const OMPClause &C, OMPPrivateScope &PrivateScope,
- const llvm::DenseMap<const ValueDecl *, Address> &CaptureDeviceAddrMap);
- /// Emit code for copyin clause in \a D directive. The next code is
- /// generated at the start of outlined functions for directives:
- /// \code
- /// threadprivate_var1 = master_threadprivate_var1;
- /// operator=(threadprivate_var2, master_threadprivate_var2);
- /// ...
- /// __kmpc_barrier(&loc, global_tid);
- /// \endcode
- ///
- /// \param D OpenMP directive possibly with 'copyin' clause(s).
- /// \returns true if at least one copyin variable is found, false otherwise.
- bool EmitOMPCopyinClause(const OMPExecutableDirective &D);
- /// Emit initial code for lastprivate variables. If some variable is
- /// not also firstprivate, then the default initialization is used. Otherwise
- /// initialization of this variable is performed by EmitOMPFirstprivateClause
- /// method.
- ///
- /// \param D Directive that may have 'lastprivate' directives.
- /// \param PrivateScope Private scope for capturing lastprivate variables for
- /// proper codegen in internal captured statement.
- ///
- /// \returns true if there is at least one lastprivate variable, false
- /// otherwise.
- bool EmitOMPLastprivateClauseInit(const OMPExecutableDirective &D,
- OMPPrivateScope &PrivateScope);
- /// Emit final copying of lastprivate values to original variables at
- /// the end of the worksharing or simd directive.
- ///
- /// \param D Directive that has at least one 'lastprivate' directives.
- /// \param IsLastIterCond Boolean condition that must be set to 'i1 true' if
- /// it is the last iteration of the loop code in associated directive, or to
- /// 'i1 false' otherwise. If this item is nullptr, no final check is required.
- void EmitOMPLastprivateClauseFinal(const OMPExecutableDirective &D,
- bool NoFinals,
- llvm::Value *IsLastIterCond = nullptr);
- /// Emit initial code for linear clauses.
- void EmitOMPLinearClause(const OMPLoopDirective &D,
- CodeGenFunction::OMPPrivateScope &PrivateScope);
- /// Emit final code for linear clauses.
- /// \param CondGen Optional conditional code for final part of codegen for
- /// linear clause.
- void EmitOMPLinearClauseFinal(
- const OMPLoopDirective &D,
- const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen);
- /// Emit initial code for reduction variables. Creates reduction copies
- /// and initializes them with the values according to OpenMP standard.
- ///
- /// \param D Directive (possibly) with the 'reduction' clause.
- /// \param PrivateScope Private scope for capturing reduction variables for
- /// proper codegen in internal captured statement.
- ///
- void EmitOMPReductionClauseInit(const OMPExecutableDirective &D,
- OMPPrivateScope &PrivateScope);
- /// Emit final update of reduction values to original variables at
- /// the end of the directive.
- ///
- /// \param D Directive that has at least one 'reduction' directives.
- /// \param ReductionKind The kind of reduction to perform.
- void EmitOMPReductionClauseFinal(const OMPExecutableDirective &D,
- const OpenMPDirectiveKind ReductionKind);
- /// Emit initial code for linear variables. Creates private copies
- /// and initializes them with the values according to OpenMP standard.
- ///
- /// \param D Directive (possibly) with the 'linear' clause.
- /// \return true if at least one linear variable is found that should be
- /// initialized with the value of the original variable, false otherwise.
- bool EmitOMPLinearClauseInit(const OMPLoopDirective &D);
-
- typedef const llvm::function_ref<void(CodeGenFunction & /*CGF*/,
- llvm::Value * /*OutlinedFn*/,
- const OMPTaskDataTy & /*Data*/)>
- TaskGenTy;
- void EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
- const OpenMPDirectiveKind CapturedRegion,
- const RegionCodeGenTy &BodyGen,
- const TaskGenTy &TaskGen, OMPTaskDataTy &Data);
- struct OMPTargetDataInfo {
- Address BasePointersArray = Address::invalid();
- Address PointersArray = Address::invalid();
- Address SizesArray = Address::invalid();
- unsigned NumberOfTargetItems = 0;
- explicit OMPTargetDataInfo() = default;
- OMPTargetDataInfo(Address BasePointersArray, Address PointersArray,
- Address SizesArray, unsigned NumberOfTargetItems)
- : BasePointersArray(BasePointersArray), PointersArray(PointersArray),
- SizesArray(SizesArray), NumberOfTargetItems(NumberOfTargetItems) {}
- };
- void EmitOMPTargetTaskBasedDirective(const OMPExecutableDirective &S,
- const RegionCodeGenTy &BodyGen,
- OMPTargetDataInfo &InputInfo);
-
- void EmitOMPParallelDirective(const OMPParallelDirective &S);
- void EmitOMPSimdDirective(const OMPSimdDirective &S);
- void EmitOMPForDirective(const OMPForDirective &S);
- void EmitOMPForSimdDirective(const OMPForSimdDirective &S);
- void EmitOMPSectionsDirective(const OMPSectionsDirective &S);
- void EmitOMPSectionDirective(const OMPSectionDirective &S);
- void EmitOMPSingleDirective(const OMPSingleDirective &S);
- void EmitOMPMasterDirective(const OMPMasterDirective &S);
- void EmitOMPCriticalDirective(const OMPCriticalDirective &S);
- void EmitOMPParallelForDirective(const OMPParallelForDirective &S);
- void EmitOMPParallelForSimdDirective(const OMPParallelForSimdDirective &S);
- void EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &S);
- void EmitOMPTaskDirective(const OMPTaskDirective &S);
- void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S);
- void EmitOMPBarrierDirective(const OMPBarrierDirective &S);
- void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S);
- void EmitOMPTaskgroupDirective(const OMPTaskgroupDirective &S);
- void EmitOMPFlushDirective(const OMPFlushDirective &S);
- void EmitOMPOrderedDirective(const OMPOrderedDirective &S);
- void EmitOMPAtomicDirective(const OMPAtomicDirective &S);
- void EmitOMPTargetDirective(const OMPTargetDirective &S);
- void EmitOMPTargetDataDirective(const OMPTargetDataDirective &S);
- void EmitOMPTargetEnterDataDirective(const OMPTargetEnterDataDirective &S);
- void EmitOMPTargetExitDataDirective(const OMPTargetExitDataDirective &S);
- void EmitOMPTargetUpdateDirective(const OMPTargetUpdateDirective &S);
- void EmitOMPTargetParallelDirective(const OMPTargetParallelDirective &S);
- void
- EmitOMPTargetParallelForDirective(const OMPTargetParallelForDirective &S);
- void EmitOMPTeamsDirective(const OMPTeamsDirective &S);
- void
- EmitOMPCancellationPointDirective(const OMPCancellationPointDirective &S);
- void EmitOMPCancelDirective(const OMPCancelDirective &S);
- void EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S);
- void EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S);
- void EmitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective &S);
- void EmitOMPDistributeDirective(const OMPDistributeDirective &S);
- void EmitOMPDistributeParallelForDirective(
- const OMPDistributeParallelForDirective &S);
- void EmitOMPDistributeParallelForSimdDirective(
- const OMPDistributeParallelForSimdDirective &S);
- void EmitOMPDistributeSimdDirective(const OMPDistributeSimdDirective &S);
- void EmitOMPTargetParallelForSimdDirective(
- const OMPTargetParallelForSimdDirective &S);
- void EmitOMPTargetSimdDirective(const OMPTargetSimdDirective &S);
- void EmitOMPTeamsDistributeDirective(const OMPTeamsDistributeDirective &S);
- void
- EmitOMPTeamsDistributeSimdDirective(const OMPTeamsDistributeSimdDirective &S);
- void EmitOMPTeamsDistributeParallelForSimdDirective(
- const OMPTeamsDistributeParallelForSimdDirective &S);
- void EmitOMPTeamsDistributeParallelForDirective(
- const OMPTeamsDistributeParallelForDirective &S);
- void EmitOMPTargetTeamsDirective(const OMPTargetTeamsDirective &S);
- void EmitOMPTargetTeamsDistributeDirective(
- const OMPTargetTeamsDistributeDirective &S);
- void EmitOMPTargetTeamsDistributeParallelForDirective(
- const OMPTargetTeamsDistributeParallelForDirective &S);
- void EmitOMPTargetTeamsDistributeParallelForSimdDirective(
- const OMPTargetTeamsDistributeParallelForSimdDirective &S);
- void EmitOMPTargetTeamsDistributeSimdDirective(
- const OMPTargetTeamsDistributeSimdDirective &S);
-
- /// Emit device code for the target directive.
- static void EmitOMPTargetDeviceFunction(CodeGenModule &CGM,
- StringRef ParentName,
- const OMPTargetDirective &S);
- static void
- EmitOMPTargetParallelDeviceFunction(CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetParallelDirective &S);
- /// Emit device code for the target parallel for directive.
- static void EmitOMPTargetParallelForDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetParallelForDirective &S);
- /// Emit device code for the target parallel for simd directive.
- static void EmitOMPTargetParallelForSimdDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetParallelForSimdDirective &S);
- /// Emit device code for the target teams directive.
- static void
- EmitOMPTargetTeamsDeviceFunction(CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDirective &S);
- /// Emit device code for the target teams distribute directive.
- static void EmitOMPTargetTeamsDistributeDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeDirective &S);
- /// Emit device code for the target teams distribute simd directive.
- static void EmitOMPTargetTeamsDistributeSimdDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeSimdDirective &S);
- /// Emit device code for the target simd directive.
- static void EmitOMPTargetSimdDeviceFunction(CodeGenModule &CGM,
- StringRef ParentName,
- const OMPTargetSimdDirective &S);
- /// Emit device code for the target teams distribute parallel for simd
- /// directive.
- static void EmitOMPTargetTeamsDistributeParallelForSimdDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeParallelForSimdDirective &S);
-
- static void EmitOMPTargetTeamsDistributeParallelForDeviceFunction(
- CodeGenModule &CGM, StringRef ParentName,
- const OMPTargetTeamsDistributeParallelForDirective &S);
- /// Emit inner loop of the worksharing/simd construct.
- ///
- /// \param S Directive, for which the inner loop must be emitted.
- /// \param RequiresCleanup true, if directive has some associated private
- /// variables.
- /// \param LoopCond Bollean condition for loop continuation.
- /// \param IncExpr Increment expression for loop control variable.
- /// \param BodyGen Generator for the inner body of the inner loop.
- /// \param PostIncGen Genrator for post-increment code (required for ordered
- /// loop directvies).
- void EmitOMPInnerLoop(
- const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
- const Expr *IncExpr,
- const llvm::function_ref<void(CodeGenFunction &)> BodyGen,
- const llvm::function_ref<void(CodeGenFunction &)> PostIncGen);
-
- JumpDest getOMPCancelDestination(OpenMPDirectiveKind Kind);
- /// Emit initial code for loop counters of loop-based directives.
- void EmitOMPPrivateLoopCounters(const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope);
-
- /// Helper for the OpenMP loop directives.
- void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit);
-
- /// Emit code for the worksharing loop-based directive.
- /// \return true, if this construct has any lastprivate clause, false -
- /// otherwise.
- bool EmitOMPWorksharingLoop(const OMPLoopDirective &S, Expr *EUB,
- const CodeGenLoopBoundsTy &CodeGenLoopBounds,
- const CodeGenDispatchBoundsTy &CGDispatchBounds);
-
- /// Emit code for the distribute loop-based directive.
- void EmitOMPDistributeLoop(const OMPLoopDirective &S,
- const CodeGenLoopTy &CodeGenLoop, Expr *IncExpr);
-
- /// Helpers for the OpenMP loop directives.
- void EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic = false);
- void EmitOMPSimdFinal(
- const OMPLoopDirective &D,
- const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen);
-
- /// Emits the lvalue for the expression with possibly captured variable.
- LValue EmitOMPSharedLValue(const Expr *E);
-
-private:
- /// Helpers for blocks.
- llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info);
-
- /// struct with the values to be passed to the OpenMP loop-related functions
- struct OMPLoopArguments {
- /// loop lower bound
- Address LB = Address::invalid();
- /// loop upper bound
- Address UB = Address::invalid();
- /// loop stride
- Address ST = Address::invalid();
- /// isLastIteration argument for runtime functions
- Address IL = Address::invalid();
- /// Chunk value generated by sema
- llvm::Value *Chunk = nullptr;
- /// EnsureUpperBound
- Expr *EUB = nullptr;
- /// IncrementExpression
- Expr *IncExpr = nullptr;
- /// Loop initialization
- Expr *Init = nullptr;
- /// Loop exit condition
- Expr *Cond = nullptr;
- /// Update of LB after a whole chunk has been executed
- Expr *NextLB = nullptr;
- /// Update of UB after a whole chunk has been executed
- Expr *NextUB = nullptr;
- OMPLoopArguments() = default;
- OMPLoopArguments(Address LB, Address UB, Address ST, Address IL,
- llvm::Value *Chunk = nullptr, Expr *EUB = nullptr,
- Expr *IncExpr = nullptr, Expr *Init = nullptr,
- Expr *Cond = nullptr, Expr *NextLB = nullptr,
- Expr *NextUB = nullptr)
- : LB(LB), UB(UB), ST(ST), IL(IL), Chunk(Chunk), EUB(EUB),
- IncExpr(IncExpr), Init(Init), Cond(Cond), NextLB(NextLB),
- NextUB(NextUB) {}
- };
- void EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
- const OMPLoopDirective &S, OMPPrivateScope &LoopScope,
- const OMPLoopArguments &LoopArgs,
- const CodeGenLoopTy &CodeGenLoop,
- const CodeGenOrderedTy &CodeGenOrdered);
- void EmitOMPForOuterLoop(const OpenMPScheduleTy &ScheduleKind,
- bool IsMonotonic, const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope, bool Ordered,
- const OMPLoopArguments &LoopArgs,
- const CodeGenDispatchBoundsTy &CGDispatchBounds);
- void EmitOMPDistributeOuterLoop(OpenMPDistScheduleClauseKind ScheduleKind,
- const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope,
- const OMPLoopArguments &LoopArgs,
- const CodeGenLoopTy &CodeGenLoopContent);
- /// Emit code for sections directive.
- void EmitSections(const OMPExecutableDirective &S);
-
-public:
-
- //===--------------------------------------------------------------------===//
- // LValue Expression Emission
- //===--------------------------------------------------------------------===//
-
- /// GetUndefRValue - Get an appropriate 'undef' rvalue for the given type.
- RValue GetUndefRValue(QualType Ty);
-
- /// EmitUnsupportedRValue - Emit a dummy r-value using the type of E
- /// and issue an ErrorUnsupported style diagnostic (using the
- /// provided Name).
- RValue EmitUnsupportedRValue(const Expr *E,
- const char *Name);
-
- /// EmitUnsupportedLValue - Emit a dummy l-value using the type of E and issue
- /// an ErrorUnsupported style diagnostic (using the provided Name).
- LValue EmitUnsupportedLValue(const Expr *E,
- const char *Name);
-
- /// EmitLValue - Emit code to compute a designator that specifies the location
- /// of the expression.
- ///
- /// This can return one of two things: a simple address or a bitfield
- /// reference. In either case, the LLVM Value* in the LValue structure is
- /// guaranteed to be an LLVM pointer type.
- ///
- /// If this returns a bitfield reference, nothing about the pointee type of
- /// the LLVM value is known: For example, it may not be a pointer to an
- /// integer.
- ///
- /// If this returns a normal address, and if the lvalue's C type is fixed
- /// size, this method guarantees that the returned pointer type will point to
- /// an LLVM type of the same size of the lvalue's type. If the lvalue has a
- /// variable length type, this is not possible.
- ///
- LValue EmitLValue(const Expr *E);
-
- /// Same as EmitLValue but additionally we generate checking code to
- /// guard against undefined behavior. This is only suitable when we know
- /// that the address will be used to access the object.
- LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK);
-
- RValue convertTempToRValue(Address addr, QualType type,
- SourceLocation Loc);
-
- void EmitAtomicInit(Expr *E, LValue lvalue);
-
- bool LValueIsSuitableForInlineAtomic(LValue Src);
-
- RValue EmitAtomicLoad(LValue LV, SourceLocation SL,
- AggValueSlot Slot = AggValueSlot::ignored());
-
- RValue EmitAtomicLoad(LValue lvalue, SourceLocation loc,
- llvm::AtomicOrdering AO, bool IsVolatile = false,
- AggValueSlot slot = AggValueSlot::ignored());
-
- void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit);
-
- void EmitAtomicStore(RValue rvalue, LValue lvalue, llvm::AtomicOrdering AO,
- bool IsVolatile, bool isInit);
-
- std::pair<RValue, llvm::Value *> EmitAtomicCompareExchange(
- LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
- llvm::AtomicOrdering Success =
- llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::AtomicOrdering Failure =
- llvm::AtomicOrdering::SequentiallyConsistent,
- bool IsWeak = false, AggValueSlot Slot = AggValueSlot::ignored());
-
- void EmitAtomicUpdate(LValue LVal, llvm::AtomicOrdering AO,
- const llvm::function_ref<RValue(RValue)> &UpdateOp,
- bool IsVolatile);
-
- /// EmitToMemory - Change a scalar value from its value
- /// representation to its in-memory representation.
- llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty);
-
- /// EmitFromMemory - Change a scalar value from its memory
- /// representation to its value representation.
- llvm::Value *EmitFromMemory(llvm::Value *Value, QualType Ty);
-
- /// Check if the scalar \p Value is within the valid range for the given
- /// type \p Ty.
- ///
- /// Returns true if a check is needed (even if the range is unknown).
- bool EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
- SourceLocation Loc);
-
- /// EmitLoadOfScalar - Load a scalar value from an address, taking
- /// care to appropriately convert from the memory representation to
- /// the LLVM value representation.
- llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty,
- SourceLocation Loc,
- AlignmentSource Source = AlignmentSource::Type,
- bool isNontemporal = false) {
- return EmitLoadOfScalar(Addr, Volatile, Ty, Loc, LValueBaseInfo(Source),
- CGM.getTBAAAccessInfo(Ty), isNontemporal);
- }
-
- llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty,
- SourceLocation Loc, LValueBaseInfo BaseInfo,
- TBAAAccessInfo TBAAInfo,
- bool isNontemporal = false);
-
- /// EmitLoadOfScalar - Load a scalar value from an address, taking
- /// care to appropriately convert from the memory representation to
- /// the LLVM value representation. The l-value must be a simple
- /// l-value.
- llvm::Value *EmitLoadOfScalar(LValue lvalue, SourceLocation Loc);
-
- /// EmitStoreOfScalar - Store a scalar value to an address, taking
- /// care to appropriately convert from the memory representation to
- /// the LLVM value representation.
- void EmitStoreOfScalar(llvm::Value *Value, Address Addr,
- bool Volatile, QualType Ty,
- AlignmentSource Source = AlignmentSource::Type,
- bool isInit = false, bool isNontemporal = false) {
- EmitStoreOfScalar(Value, Addr, Volatile, Ty, LValueBaseInfo(Source),
- CGM.getTBAAAccessInfo(Ty), isInit, isNontemporal);
- }
-
- void EmitStoreOfScalar(llvm::Value *Value, Address Addr,
- bool Volatile, QualType Ty,
- LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo,
- bool isInit = false, bool isNontemporal = false);
-
- /// EmitStoreOfScalar - Store a scalar value to an address, taking
- /// care to appropriately convert from the memory representation to
- /// the LLVM value representation. The l-value must be a simple
- /// l-value. The isInit flag indicates whether this is an initialization.
- /// If so, atomic qualifiers are ignored and the store is always non-atomic.
- void EmitStoreOfScalar(llvm::Value *value, LValue lvalue, bool isInit=false);
-
- /// EmitLoadOfLValue - Given an expression that represents a value lvalue,
- /// this method emits the address of the lvalue, then loads the result as an
- /// rvalue, returning the rvalue.
- RValue EmitLoadOfLValue(LValue V, SourceLocation Loc);
- RValue EmitLoadOfExtVectorElementLValue(LValue V);
- RValue EmitLoadOfBitfieldLValue(LValue LV, SourceLocation Loc);
- RValue EmitLoadOfGlobalRegLValue(LValue LV);
-
- /// EmitStoreThroughLValue - Store the specified rvalue into the specified
- /// lvalue, where both are guaranteed to the have the same type, and that type
- /// is 'Ty'.
- void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit = false);
- void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
- void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst);
-
- /// EmitStoreThroughBitfieldLValue - Store Src into Dst with same constraints
- /// as EmitStoreThroughLValue.
- ///
- /// \param Result [out] - If non-null, this will be set to a Value* for the
- /// bit-field contents after the store, appropriate for use as the result of
- /// an assignment to the bit-field.
- void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
- llvm::Value **Result=nullptr);
-
- /// Emit an l-value for an assignment (simple or compound) of complex type.
- LValue EmitComplexAssignmentLValue(const BinaryOperator *E);
- LValue EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E);
- LValue EmitScalarCompoundAssignWithComplex(const CompoundAssignOperator *E,
- llvm::Value *&Result);
-
- // Note: only available for agg return types
- LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
- LValue EmitCompoundAssignmentLValue(const CompoundAssignOperator *E);
- // Note: only available for agg return types
- LValue EmitCallExprLValue(const CallExpr *E);
- // Note: only available for agg return types
- LValue EmitVAArgExprLValue(const VAArgExpr *E);
- LValue EmitDeclRefLValue(const DeclRefExpr *E);
- LValue EmitStringLiteralLValue(const StringLiteral *E);
- LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E);
- LValue EmitPredefinedLValue(const PredefinedExpr *E);
- LValue EmitUnaryOpLValue(const UnaryOperator *E);
- LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
- bool Accessed = false);
- LValue EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
- bool IsLowerBound = true);
- LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E);
- LValue EmitMemberExpr(const MemberExpr *E);
- LValue EmitObjCIsaExpr(const ObjCIsaExpr *E);
- LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E);
- LValue EmitInitListLValue(const InitListExpr *E);
- LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E);
- LValue EmitCastLValue(const CastExpr *E);
- LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
- LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
-
- Address EmitExtVectorElementLValue(LValue V);
-
- RValue EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc);
-
- Address EmitArrayToPointerDecay(const Expr *Array,
- LValueBaseInfo *BaseInfo = nullptr,
- TBAAAccessInfo *TBAAInfo = nullptr);
-
- class ConstantEmission {
- llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference;
- ConstantEmission(llvm::Constant *C, bool isReference)
- : ValueAndIsReference(C, isReference) {}
- public:
- ConstantEmission() {}
- static ConstantEmission forReference(llvm::Constant *C) {
- return ConstantEmission(C, true);
- }
- static ConstantEmission forValue(llvm::Constant *C) {
- return ConstantEmission(C, false);
- }
-
- explicit operator bool() const {
- return ValueAndIsReference.getOpaqueValue() != nullptr;
- }
-
- bool isReference() const { return ValueAndIsReference.getInt(); }
- LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const {
- assert(isReference());
- return CGF.MakeNaturalAlignAddrLValue(ValueAndIsReference.getPointer(),
- refExpr->getType());
- }
-
- llvm::Constant *getValue() const {
- assert(!isReference());
- return ValueAndIsReference.getPointer();
- }
- };
-
- ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr);
- ConstantEmission tryEmitAsConstant(const MemberExpr *ME);
- llvm::Value *emitScalarConstant(const ConstantEmission &Constant, Expr *E);
-
- RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e,
- AggValueSlot slot = AggValueSlot::ignored());
- LValue EmitPseudoObjectLValue(const PseudoObjectExpr *e);
-
- llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar);
- LValue EmitLValueForField(LValue Base, const FieldDecl* Field);
- LValue EmitLValueForLambdaField(const FieldDecl *Field);
-
- /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that
- /// if the Field is a reference, this will return the address of the reference
- /// and not the address of the value stored in the reference.
- LValue EmitLValueForFieldInitialization(LValue Base,
- const FieldDecl* Field);
-
- LValue EmitLValueForIvar(QualType ObjectTy,
- llvm::Value* Base, const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers);
-
- LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
- LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
- LValue EmitLambdaLValue(const LambdaExpr *E);
- LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E);
- LValue EmitCXXUuidofLValue(const CXXUuidofExpr *E);
-
- LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
- LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
- LValue EmitStmtExprLValue(const StmtExpr *E);
- LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E);
- LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E);
- void EmitDeclRefExprDbgValue(const DeclRefExpr *E, const APValue &Init);
-
- //===--------------------------------------------------------------------===//
- // Scalar Expression Emission
- //===--------------------------------------------------------------------===//
-
- /// EmitCall - Generate a call of the given function, expecting the given
- /// result type, and using the given argument list which specifies both the
- /// LLVM arguments and the types they were derived from.
- RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
- ReturnValueSlot ReturnValue, const CallArgList &Args,
- llvm::Instruction **callOrInvoke, SourceLocation Loc);
- RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
- ReturnValueSlot ReturnValue, const CallArgList &Args,
- llvm::Instruction **callOrInvoke = nullptr) {
- return EmitCall(CallInfo, Callee, ReturnValue, Args, callOrInvoke,
- SourceLocation());
- }
- RValue EmitCall(QualType FnType, const CGCallee &Callee, const CallExpr *E,
- ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr);
- RValue EmitCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue = ReturnValueSlot());
- RValue EmitSimpleCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue);
- CGCallee EmitCallee(const Expr *E);
-
- void checkTargetFeatures(const CallExpr *E, const FunctionDecl *TargetDecl);
-
- llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
- const Twine &name = "");
- llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
- ArrayRef<llvm::Value*> args,
- const Twine &name = "");
- llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
- const Twine &name = "");
- llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
- ArrayRef<llvm::Value*> args,
- const Twine &name = "");
-
- SmallVector<llvm::OperandBundleDef, 1>
- getBundlesForFunclet(llvm::Value *Callee);
-
- llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
- ArrayRef<llvm::Value *> Args,
- const Twine &Name = "");
- llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
- ArrayRef<llvm::Value*> args,
- const Twine &name = "");
- llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
- const Twine &name = "");
- void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
- ArrayRef<llvm::Value*> args);
-
- CGCallee BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
- NestedNameSpecifier *Qual,
- llvm::Type *Ty);
-
- CGCallee BuildAppleKextVirtualDestructorCall(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const CXXRecordDecl *RD);
-
- // Return the copy constructor name with the prefix "__copy_constructor_"
- // removed.
- static std::string getNonTrivialCopyConstructorStr(QualType QT,
- CharUnits Alignment,
- bool IsVolatile,
- ASTContext &Ctx);
-
- // Return the destructor name with the prefix "__destructor_" removed.
- static std::string getNonTrivialDestructorStr(QualType QT,
- CharUnits Alignment,
- bool IsVolatile,
- ASTContext &Ctx);
-
- // These functions emit calls to the special functions of non-trivial C
- // structs.
- void defaultInitNonTrivialCStructVar(LValue Dst);
- void callCStructDefaultConstructor(LValue Dst);
- void callCStructDestructor(LValue Dst);
- void callCStructCopyConstructor(LValue Dst, LValue Src);
- void callCStructMoveConstructor(LValue Dst, LValue Src);
- void callCStructCopyAssignmentOperator(LValue Dst, LValue Src);
- void callCStructMoveAssignmentOperator(LValue Dst, LValue Src);
-
- RValue
- EmitCXXMemberOrOperatorCall(const CXXMethodDecl *Method,
- const CGCallee &Callee,
- ReturnValueSlot ReturnValue, llvm::Value *This,
- llvm::Value *ImplicitParam,
- QualType ImplicitParamTy, const CallExpr *E,
- CallArgList *RtlArgs);
- RValue EmitCXXDestructorCall(const CXXDestructorDecl *DD,
- const CGCallee &Callee,
- llvm::Value *This, llvm::Value *ImplicitParam,
- QualType ImplicitParamTy, const CallExpr *E,
- StructorType Type);
- RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
- ReturnValueSlot ReturnValue);
- RValue EmitCXXMemberOrOperatorMemberCallExpr(const CallExpr *CE,
- const CXXMethodDecl *MD,
- ReturnValueSlot ReturnValue,
- bool HasQualifier,
- NestedNameSpecifier *Qualifier,
- bool IsArrow, const Expr *Base);
- // Compute the object pointer.
- Address EmitCXXMemberDataPointerAddress(const Expr *E, Address base,
- llvm::Value *memberPtr,
- const MemberPointerType *memberPtrType,
- LValueBaseInfo *BaseInfo = nullptr,
- TBAAAccessInfo *TBAAInfo = nullptr);
- RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
- ReturnValueSlot ReturnValue);
-
- RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
- const CXXMethodDecl *MD,
- ReturnValueSlot ReturnValue);
- RValue EmitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E);
-
- RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
- ReturnValueSlot ReturnValue);
-
- RValue EmitNVPTXDevicePrintfCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue);
-
- RValue EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
- const CallExpr *E, ReturnValueSlot ReturnValue);
-
- RValue emitRotate(const CallExpr *E, bool IsRotateRight);
-
- /// Emit IR for __builtin_os_log_format.
- RValue emitBuiltinOSLogFormat(const CallExpr &E);
-
- llvm::Function *generateBuiltinOSLogHelperFunction(
- const analyze_os_log::OSLogBufferLayout &Layout,
- CharUnits BufferAlignment);
-
- RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue);
-
- /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call
- /// is unhandled by the current target.
- llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
-
- llvm::Value *EmitAArch64CompareBuiltinExpr(llvm::Value *Op, llvm::Type *Ty,
- const llvm::CmpInst::Predicate Fp,
- const llvm::CmpInst::Predicate Ip,
- const llvm::Twine &Name = "");
- llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
- llvm::Triple::ArchType Arch);
-
- llvm::Value *EmitCommonNeonBuiltinExpr(unsigned BuiltinID,
- unsigned LLVMIntrinsic,
- unsigned AltLLVMIntrinsic,
- const char *NameHint,
- unsigned Modifier,
- const CallExpr *E,
- SmallVectorImpl<llvm::Value *> &Ops,
- Address PtrOp0, Address PtrOp1,
- llvm::Triple::ArchType Arch);
-
- llvm::Value *EmitISOVolatileLoad(const CallExpr *E);
- llvm::Value *EmitISOVolatileStore(const CallExpr *E);
-
- llvm::Function *LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
- unsigned Modifier, llvm::Type *ArgTy,
- const CallExpr *E);
- llvm::Value *EmitNeonCall(llvm::Function *F,
- SmallVectorImpl<llvm::Value*> &O,
- const char *name,
- unsigned shift = 0, bool rightshift = false);
- llvm::Value *EmitNeonSplat(llvm::Value *V, llvm::Constant *Idx);
- llvm::Value *EmitNeonShiftVector(llvm::Value *V, llvm::Type *Ty,
- bool negateForRightShift);
- llvm::Value *EmitNeonRShiftImm(llvm::Value *Vec, llvm::Value *Amt,
- llvm::Type *Ty, bool usgn, const char *name);
- llvm::Value *vectorWrapScalar16(llvm::Value *Op);
- llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E,
- llvm::Triple::ArchType Arch);
-
- llvm::Value *BuildVector(ArrayRef<llvm::Value*> Ops);
- llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
- llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
- llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
- llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
- llvm::Value *EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
- llvm::Value *EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E);
- llvm::Value *EmitHexagonBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
-
-private:
- enum class MSVCIntrin;
-
-public:
- llvm::Value *EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, const CallExpr *E);
-
- llvm::Value *EmitBuiltinAvailable(ArrayRef<llvm::Value *> Args);
-
- llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
- llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
- llvm::Value *EmitObjCBoxedExpr(const ObjCBoxedExpr *E);
- llvm::Value *EmitObjCArrayLiteral(const ObjCArrayLiteral *E);
- llvm::Value *EmitObjCDictionaryLiteral(const ObjCDictionaryLiteral *E);
- llvm::Value *EmitObjCCollectionLiteral(const Expr *E,
- const ObjCMethodDecl *MethodWithObjects);
- llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
- RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
- ReturnValueSlot Return = ReturnValueSlot());
-
- /// Retrieves the default cleanup kind for an ARC cleanup.
- /// Except under -fobjc-arc-eh, ARC cleanups are normal-only.
- CleanupKind getARCCleanupKind() {
- return CGM.getCodeGenOpts().ObjCAutoRefCountExceptions
- ? NormalAndEHCleanup : NormalCleanup;
- }
-
- // ARC primitives.
- void EmitARCInitWeak(Address addr, llvm::Value *value);
- void EmitARCDestroyWeak(Address addr);
- llvm::Value *EmitARCLoadWeak(Address addr);
- llvm::Value *EmitARCLoadWeakRetained(Address addr);
- llvm::Value *EmitARCStoreWeak(Address addr, llvm::Value *value, bool ignored);
- void emitARCCopyAssignWeak(QualType Ty, Address DstAddr, Address SrcAddr);
- void emitARCMoveAssignWeak(QualType Ty, Address DstAddr, Address SrcAddr);
- void EmitARCCopyWeak(Address dst, Address src);
- void EmitARCMoveWeak(Address dst, Address src);
- llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
- llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
- llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value,
- bool resultIgnored);
- llvm::Value *EmitARCStoreStrongCall(Address addr, llvm::Value *value,
- bool resultIgnored);
- llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
- llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
- llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
- void EmitARCDestroyStrong(Address addr, ARCPreciseLifetime_t precise);
- void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
- llvm::Value *EmitARCAutorelease(llvm::Value *value);
- llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
- llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
- llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
- llvm::Value *EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value);
-
- llvm::Value *EmitObjCAutorelease(llvm::Value *value, llvm::Type *returnType);
- llvm::Value *EmitObjCRetainNonBlock(llvm::Value *value,
- llvm::Type *returnType);
- void EmitObjCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
-
- std::pair<LValue,llvm::Value*>
- EmitARCStoreAutoreleasing(const BinaryOperator *e);
- std::pair<LValue,llvm::Value*>
- EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
- std::pair<LValue,llvm::Value*>
- EmitARCStoreUnsafeUnretained(const BinaryOperator *e, bool ignored);
-
- llvm::Value *EmitObjCAlloc(llvm::Value *value,
- llvm::Type *returnType);
- llvm::Value *EmitObjCAllocWithZone(llvm::Value *value,
- llvm::Type *returnType);
- llvm::Value *EmitObjCThrowOperand(const Expr *expr);
- llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
- llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
-
- llvm::Value *EmitARCExtendBlockObject(const Expr *expr);
- llvm::Value *EmitARCReclaimReturnedObject(const Expr *e,
- bool allowUnsafeClaim);
- llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
- llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
- llvm::Value *EmitARCUnsafeUnretainedScalarExpr(const Expr *expr);
-
- void EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values);
-
- static Destroyer destroyARCStrongImprecise;
- static Destroyer destroyARCStrongPrecise;
- static Destroyer destroyARCWeak;
- static Destroyer emitARCIntrinsicUse;
- static Destroyer destroyNonTrivialCStruct;
-
- void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
- llvm::Value *EmitObjCAutoreleasePoolPush();
- llvm::Value *EmitObjCMRRAutoreleasePoolPush();
- void EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr);
- void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr);
-
- /// Emits a reference binding to the passed in expression.
- RValue EmitReferenceBindingToExpr(const Expr *E);
-
- //===--------------------------------------------------------------------===//
- // Expression Emission
- //===--------------------------------------------------------------------===//
-
- // Expressions are broken into three classes: scalar, complex, aggregate.
-
- /// EmitScalarExpr - Emit the computation of the specified expression of LLVM
- /// scalar type, returning the result.
- llvm::Value *EmitScalarExpr(const Expr *E , bool IgnoreResultAssign = false);
-
- /// Emit a conversion from the specified type to the specified destination
- /// type, both of which are LLVM scalar types.
- llvm::Value *EmitScalarConversion(llvm::Value *Src, QualType SrcTy,
- QualType DstTy, SourceLocation Loc);
-
- /// Emit a conversion from the specified complex type to the specified
- /// destination type, where the destination type is an LLVM scalar type.
- llvm::Value *EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy,
- QualType DstTy,
- SourceLocation Loc);
-
- /// EmitAggExpr - Emit the computation of the specified expression
- /// of aggregate type. The result is computed into the given slot,
- /// which may be null to indicate that the value is not needed.
- void EmitAggExpr(const Expr *E, AggValueSlot AS);
-
- /// EmitAggExprToLValue - Emit the computation of the specified expression of
- /// aggregate type into a temporary LValue.
- LValue EmitAggExprToLValue(const Expr *E);
-
- /// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
- /// make sure it survives garbage collection until this point.
- void EmitExtendGCLifetime(llvm::Value *object);
-
- /// EmitComplexExpr - Emit the computation of the specified expression of
- /// complex type, returning the result.
- ComplexPairTy EmitComplexExpr(const Expr *E,
- bool IgnoreReal = false,
- bool IgnoreImag = false);
-
- /// EmitComplexExprIntoLValue - Emit the given expression of complex
- /// type and place its result into the specified l-value.
- void EmitComplexExprIntoLValue(const Expr *E, LValue dest, bool isInit);
-
- /// EmitStoreOfComplex - Store a complex number into the specified l-value.
- void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit);
-
- /// EmitLoadOfComplex - Load a complex number from the specified l-value.
- ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc);
-
- Address emitAddrOfRealComponent(Address complex, QualType complexType);
- Address emitAddrOfImagComponent(Address complex, QualType complexType);
-
- /// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
- /// global variable that has already been created for it. If the initializer
- /// has a different type than GV does, this may free GV and return a different
- /// one. Otherwise it just returns GV.
- llvm::GlobalVariable *
- AddInitializerToStaticVarDecl(const VarDecl &D,
- llvm::GlobalVariable *GV);
-
- // Emit an @llvm.invariant.start call for the given memory region.
- void EmitInvariantStart(llvm::Constant *Addr, CharUnits Size);
-
- /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
- /// variable with global storage.
- void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr,
- bool PerformInit);
-
- llvm::Constant *createAtExitStub(const VarDecl &VD, llvm::Constant *Dtor,
- llvm::Constant *Addr);
-
- /// Call atexit() with a function that passes the given argument to
- /// the given function.
- void registerGlobalDtorWithAtExit(const VarDecl &D, llvm::Constant *fn,
- llvm::Constant *addr);
-
- /// Call atexit() with function dtorStub.
- void registerGlobalDtorWithAtExit(llvm::Constant *dtorStub);
-
- /// Emit code in this function to perform a guarded variable
- /// initialization. Guarded initializations are used when it's not
- /// possible to prove that an initialization will be done exactly
- /// once, e.g. with a static local variable or a static data member
- /// of a class template.
- void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr,
- bool PerformInit);
-
- enum class GuardKind { VariableGuard, TlsGuard };
-
- /// Emit a branch to select whether or not to perform guarded initialization.
- void EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
- llvm::BasicBlock *InitBlock,
- llvm::BasicBlock *NoInitBlock,
- GuardKind Kind, const VarDecl *D);
-
- /// GenerateCXXGlobalInitFunc - Generates code for initializing global
- /// variables.
- void
- GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- ArrayRef<llvm::Function *> CXXThreadLocals,
- ConstantAddress Guard = ConstantAddress::invalid());
-
- /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
- /// variables.
- void GenerateCXXGlobalDtorsFunc(
- llvm::Function *Fn,
- const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>>
- &DtorsAndObjects);
-
- void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
- const VarDecl *D,
- llvm::GlobalVariable *Addr,
- bool PerformInit);
-
- void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest);
-
- void EmitSynthesizedCXXCopyCtor(Address Dest, Address Src, const Expr *Exp);
-
- void enterFullExpression(const FullExpr *E) {
- if (const auto *EWC = dyn_cast<ExprWithCleanups>(E))
- if (EWC->getNumObjects() == 0)
- return;
- enterNonTrivialFullExpression(E);
- }
- void enterNonTrivialFullExpression(const FullExpr *E);
-
- void EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint = true);
-
- void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest);
-
- RValue EmitAtomicExpr(AtomicExpr *E);
-
- //===--------------------------------------------------------------------===//
- // Annotations Emission
- //===--------------------------------------------------------------------===//
-
- /// Emit an annotation call (intrinsic or builtin).
- llvm::Value *EmitAnnotationCall(llvm::Value *AnnotationFn,
- llvm::Value *AnnotatedVal,
- StringRef AnnotationStr,
- SourceLocation Location);
-
- /// Emit local annotations for the local variable V, declared by D.
- void EmitVarAnnotations(const VarDecl *D, llvm::Value *V);
-
- /// Emit field annotations for the given field & value. Returns the
- /// annotation result.
- Address EmitFieldAnnotations(const FieldDecl *D, Address V);
-
- //===--------------------------------------------------------------------===//
- // Internal Helpers
- //===--------------------------------------------------------------------===//
-
- /// ContainsLabel - Return true if the statement contains a label in it. If
- /// this statement is not executed normally, it not containing a label means
- /// that we can just remove the code.
- static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false);
-
- /// containsBreak - Return true if the statement contains a break out of it.
- /// If the statement (recursively) contains a switch or loop with a break
- /// inside of it, this is fine.
- static bool containsBreak(const Stmt *S);
-
- /// Determine if the given statement might introduce a declaration into the
- /// current scope, by being a (possibly-labelled) DeclStmt.
- static bool mightAddDeclToScope(const Stmt *S);
-
- /// ConstantFoldsToSimpleInteger - If the specified expression does not fold
- /// to a constant, or if it does but contains a label, return false. If it
- /// constant folds return true and set the boolean result in Result.
- bool ConstantFoldsToSimpleInteger(const Expr *Cond, bool &Result,
- bool AllowLabels = false);
-
- /// ConstantFoldsToSimpleInteger - If the specified expression does not fold
- /// to a constant, or if it does but contains a label, return false. If it
- /// constant folds return true and set the folded value.
- bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt &Result,
- bool AllowLabels = false);
-
- /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an
- /// if statement) to the specified blocks. Based on the condition, this might
- /// try to simplify the codegen of the conditional based on the branch.
- /// TrueCount should be the number of times we expect the condition to
- /// evaluate to true based on PGO data.
- void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
- llvm::BasicBlock *FalseBlock, uint64_t TrueCount);
-
- /// Given an assignment `*LHS = RHS`, emit a test that checks if \p RHS is
- /// nonnull, if \p LHS is marked _Nonnull.
- void EmitNullabilityCheck(LValue LHS, llvm::Value *RHS, SourceLocation Loc);
-
- /// An enumeration which makes it easier to specify whether or not an
- /// operation is a subtraction.
- enum { NotSubtraction = false, IsSubtraction = true };
-
- /// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
- /// detect undefined behavior when the pointer overflow sanitizer is enabled.
- /// \p SignedIndices indicates whether any of the GEP indices are signed.
- /// \p IsSubtraction indicates whether the expression used to form the GEP
- /// is a subtraction.
- llvm::Value *EmitCheckedInBoundsGEP(llvm::Value *Ptr,
- ArrayRef<llvm::Value *> IdxList,
- bool SignedIndices,
- bool IsSubtraction,
- SourceLocation Loc,
- const Twine &Name = "");
-
- /// Specifies which type of sanitizer check to apply when handling a
- /// particular builtin.
- enum BuiltinCheckKind {
- BCK_CTZPassedZero,
- BCK_CLZPassedZero,
- };
-
- /// Emits an argument for a call to a builtin. If the builtin sanitizer is
- /// enabled, a runtime check specified by \p Kind is also emitted.
- llvm::Value *EmitCheckedArgForBuiltin(const Expr *E, BuiltinCheckKind Kind);
-
- /// Emit a description of a type in a format suitable for passing to
- /// a runtime sanitizer handler.
- llvm::Constant *EmitCheckTypeDescriptor(QualType T);
-
- /// Convert a value into a format suitable for passing to a runtime
- /// sanitizer handler.
- llvm::Value *EmitCheckValue(llvm::Value *V);
-
- /// Emit a description of a source location in a format suitable for
- /// passing to a runtime sanitizer handler.
- llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
-
- /// Create a basic block that will call a handler function in a
- /// sanitizer runtime with the provided arguments, and create a conditional
- /// branch to it.
- void EmitCheck(ArrayRef<std::pair<llvm::Value *, SanitizerMask>> Checked,
- SanitizerHandler Check, ArrayRef<llvm::Constant *> StaticArgs,
- ArrayRef<llvm::Value *> DynamicArgs);
-
- /// Emit a slow path cross-DSO CFI check which calls __cfi_slowpath
- /// if Cond if false.
- void EmitCfiSlowPathCheck(SanitizerMask Kind, llvm::Value *Cond,
- llvm::ConstantInt *TypeId, llvm::Value *Ptr,
- ArrayRef<llvm::Constant *> StaticArgs);
-
- /// Emit a reached-unreachable diagnostic if \p Loc is valid and runtime
- /// checking is enabled. Otherwise, just emit an unreachable instruction.
- void EmitUnreachable(SourceLocation Loc);
-
- /// Create a basic block that will call the trap intrinsic, and emit a
- /// conditional branch to it, for the -ftrapv checks.
- void EmitTrapCheck(llvm::Value *Checked);
-
- /// Emit a call to trap or debugtrap and attach function attribute
- /// "trap-func-name" if specified.
- llvm::CallInst *EmitTrapCall(llvm::Intrinsic::ID IntrID);
-
- /// Emit a stub for the cross-DSO CFI check function.
- void EmitCfiCheckStub();
-
- /// Emit a cross-DSO CFI failure handling function.
- void EmitCfiCheckFail();
-
- /// Create a check for a function parameter that may potentially be
- /// declared as non-null.
- void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc,
- AbstractCallee AC, unsigned ParmNum);
-
- /// EmitCallArg - Emit a single call argument.
- void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
-
- /// EmitDelegateCallArg - We are performing a delegate call; that
- /// is, the current function is delegating to another one. Produce
- /// a r-value suitable for passing the given parameter.
- void EmitDelegateCallArg(CallArgList &args, const VarDecl *param,
- SourceLocation loc);
-
- /// SetFPAccuracy - Set the minimum required accuracy of the given floating
- /// point operation, expressed as the maximum relative error in ulp.
- void SetFPAccuracy(llvm::Value *Val, float Accuracy);
-
-private:
- llvm::MDNode *getRangeForLoadFromType(QualType Ty);
- void EmitReturnOfRValue(RValue RV, QualType Ty);
-
- void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New);
-
- llvm::SmallVector<std::pair<llvm::Instruction *, llvm::Value *>, 4>
- DeferredReplacements;
-
- /// Set the address of a local variable.
- void setAddrOfLocalVar(const VarDecl *VD, Address Addr) {
- assert(!LocalDeclMap.count(VD) && "Decl already exists in LocalDeclMap!");
- LocalDeclMap.insert({VD, Addr});
- }
-
- /// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty
- /// from function arguments into \arg Dst. See ABIArgInfo::Expand.
- ///
- /// \param AI - The first function argument of the expansion.
- void ExpandTypeFromArgs(QualType Ty, LValue Dst,
- SmallVectorImpl<llvm::Value *>::iterator &AI);
-
- /// ExpandTypeToArgs - Expand an CallArg \arg Arg, with the LLVM type for \arg
- /// Ty, into individual arguments on the provided vector \arg IRCallArgs,
- /// starting at index \arg IRCallArgPos. See ABIArgInfo::Expand.
- void ExpandTypeToArgs(QualType Ty, CallArg Arg, llvm::FunctionType *IRFuncTy,
- SmallVectorImpl<llvm::Value *> &IRCallArgs,
- unsigned &IRCallArgPos);
-
- llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
- const Expr *InputExpr, std::string &ConstraintStr);
-
- llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
- LValue InputValue, QualType InputType,
- std::string &ConstraintStr,
- SourceLocation Loc);
-
- /// Attempts to statically evaluate the object size of E. If that
- /// fails, emits code to figure the size of E out for us. This is
- /// pass_object_size aware.
- ///
- /// If EmittedExpr is non-null, this will use that instead of re-emitting E.
- llvm::Value *evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType,
- llvm::Value *EmittedE);
-
- /// Emits the size of E, as required by __builtin_object_size. This
- /// function is aware of pass_object_size parameters, and will act accordingly
- /// if E is a parameter with the pass_object_size attribute.
- llvm::Value *emitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType,
- llvm::Value *EmittedE);
-
-public:
-#ifndef NDEBUG
- // Determine whether the given argument is an Objective-C method
- // that may have type parameters in its signature.
- static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) {
- const DeclContext *dc = method->getDeclContext();
- if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) {
- return classDecl->getTypeParamListAsWritten();
- }
-
- if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) {
- return catDecl->getTypeParamList();
- }
-
- return false;
- }
-
- template<typename T>
- static bool isObjCMethodWithTypeParams(const T *) { return false; }
-#endif
-
- enum class EvaluationOrder {
- ///! No language constraints on evaluation order.
- Default,
- ///! Language semantics require left-to-right evaluation.
- ForceLeftToRight,
- ///! Language semantics require right-to-left evaluation.
- ForceRightToLeft
- };
-
- /// EmitCallArgs - Emit call arguments for a function.
- template <typename T>
- void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
- llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
- AbstractCallee AC = AbstractCallee(),
- unsigned ParamsToSkip = 0,
- EvaluationOrder Order = EvaluationOrder::Default) {
- SmallVector<QualType, 16> ArgTypes;
- CallExpr::const_arg_iterator Arg = ArgRange.begin();
-
- assert((ParamsToSkip == 0 || CallArgTypeInfo) &&
- "Can't skip parameters if type info is not provided");
- if (CallArgTypeInfo) {
-#ifndef NDEBUG
- bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo);
-#endif
-
- // First, use the argument types that the type info knows about
- for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip,
- E = CallArgTypeInfo->param_type_end();
- I != E; ++I, ++Arg) {
- assert(Arg != ArgRange.end() && "Running over edge of argument list!");
- assert((isGenericMethod ||
- ((*I)->isVariablyModifiedType() ||
- (*I).getNonReferenceType()->isObjCRetainableType() ||
- getContext()
- .getCanonicalType((*I).getNonReferenceType())
- .getTypePtr() ==
- getContext()
- .getCanonicalType((*Arg)->getType())
- .getTypePtr())) &&
- "type mismatch in call argument!");
- ArgTypes.push_back(*I);
- }
- }
-
- // Either we've emitted all the call args, or we have a call to variadic
- // function.
- assert((Arg == ArgRange.end() || !CallArgTypeInfo ||
- CallArgTypeInfo->isVariadic()) &&
- "Extra arguments in non-variadic function!");
-
- // If we still have any arguments, emit them using the type of the argument.
- for (auto *A : llvm::make_range(Arg, ArgRange.end()))
- ArgTypes.push_back(CallArgTypeInfo ? getVarArgType(A) : A->getType());
-
- EmitCallArgs(Args, ArgTypes, ArgRange, AC, ParamsToSkip, Order);
- }
-
- void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
- llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
- AbstractCallee AC = AbstractCallee(),
- unsigned ParamsToSkip = 0,
- EvaluationOrder Order = EvaluationOrder::Default);
-
- /// EmitPointerWithAlignment - Given an expression with a pointer type,
- /// emit the value and compute our best estimate of the alignment of the
- /// pointee.
- ///
- /// \param BaseInfo - If non-null, this will be initialized with
- /// information about the source of the alignment and the may-alias
- /// attribute. Note that this function will conservatively fall back on
- /// the type when it doesn't recognize the expression and may-alias will
- /// be set to false.
- ///
- /// One reasonable way to use this information is when there's a language
- /// guarantee that the pointer must be aligned to some stricter value, and
- /// we're simply trying to ensure that sufficiently obvious uses of under-
- /// aligned objects don't get miscompiled; for example, a placement new
- /// into the address of a local variable. In such a case, it's quite
- /// reasonable to just ignore the returned alignment when it isn't from an
- /// explicit source.
- Address EmitPointerWithAlignment(const Expr *Addr,
- LValueBaseInfo *BaseInfo = nullptr,
- TBAAAccessInfo *TBAAInfo = nullptr);
-
- /// If \p E references a parameter with pass_object_size info or a constant
- /// array size modifier, emit the object size divided by the size of \p EltTy.
- /// Otherwise return null.
- llvm::Value *LoadPassedObjectSize(const Expr *E, QualType EltTy);
-
- void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
-
- struct MultiVersionResolverOption {
- llvm::Function *Function;
- FunctionDecl *FD;
- struct Conds {
- StringRef Architecture;
- llvm::SmallVector<StringRef, 8> Features;
-
- Conds(StringRef Arch, ArrayRef<StringRef> Feats)
- : Architecture(Arch), Features(Feats.begin(), Feats.end()) {}
- } Conditions;
-
- MultiVersionResolverOption(llvm::Function *F, StringRef Arch,
- ArrayRef<StringRef> Feats)
- : Function(F), Conditions(Arch, Feats) {}
- };
-
- // Emits the body of a multiversion function's resolver. Assumes that the
- // options are already sorted in the proper order, with the 'default' option
- // last (if it exists).
- void EmitMultiVersionResolver(llvm::Function *Resolver,
- ArrayRef<MultiVersionResolverOption> Options);
-
- static uint64_t GetX86CpuSupportsMask(ArrayRef<StringRef> FeatureStrs);
-
-private:
- QualType getVarArgType(const Expr *Arg);
-
- void EmitDeclMetadata();
-
- BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType,
- const AutoVarEmission &emission);
-
- void AddObjCARCExceptionMetadata(llvm::Instruction *Inst);
-
- llvm::Value *GetValueForARMHint(unsigned BuiltinID);
- llvm::Value *EmitX86CpuIs(const CallExpr *E);
- llvm::Value *EmitX86CpuIs(StringRef CPUStr);
- llvm::Value *EmitX86CpuSupports(const CallExpr *E);
- llvm::Value *EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs);
- llvm::Value *EmitX86CpuSupports(uint64_t Mask);
- llvm::Value *EmitX86CpuInit();
- llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO);
-};
-
-inline DominatingLLVMValue::saved_type
-DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) {
- if (!needsSaving(value)) return saved_type(value, false);
-
- // Otherwise, we need an alloca.
- auto align = CharUnits::fromQuantity(
- CGF.CGM.getDataLayout().getPrefTypeAlignment(value->getType()));
- Address alloca =
- CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save");
- CGF.Builder.CreateStore(value, alloca);
-
- return saved_type(alloca.getPointer(), true);
-}
-
-inline llvm::Value *DominatingLLVMValue::restore(CodeGenFunction &CGF,
- saved_type value) {
- // If the value says it wasn't saved, trust that it's still dominating.
- if (!value.getInt()) return value.getPointer();
-
- // Otherwise, it should be an alloca instruction, as set up in save().
- auto alloca = cast<llvm::AllocaInst>(value.getPointer());
- return CGF.Builder.CreateAlignedLoad(alloca, alloca->getAlignment());
-}
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp
deleted file mode 100644
index 2ac59fb4de2..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp
+++ /dev/null
@@ -1,5511 +0,0 @@
-//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This coordinates the per-module state used while generating code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenModule.h"
-#include "CGBlocks.h"
-#include "CGCUDARuntime.h"
-#include "CGCXXABI.h"
-#include "CGCall.h"
-#include "CGDebugInfo.h"
-#include "CGObjCRuntime.h"
-#include "CGOpenCLRuntime.h"
-#include "CGOpenMPRuntime.h"
-#include "CGOpenMPRuntimeNVPTX.h"
-#include "CodeGenFunction.h"
-#include "CodeGenPGO.h"
-#include "ConstantEmitter.h"
-#include "CoverageMappingGen.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Mangle.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/CharInfo.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/Module.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/Version.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Analysis/TargetLibraryInfo.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/CallingConv.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/ProfileData/InstrProfReader.h"
-#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MD5.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-static llvm::cl::opt<bool> LimitedCoverage(
- "limited-coverage-experimental", llvm::cl::ZeroOrMore, llvm::cl::Hidden,
- llvm::cl::desc("Emit limited coverage mapping information (experimental)"),
- llvm::cl::init(false));
-
-static const char AnnotationSection[] = "llvm.metadata";
-
-static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
- switch (CGM.getTarget().getCXXABI().getKind()) {
- case TargetCXXABI::GenericAArch64:
- case TargetCXXABI::GenericARM:
- case TargetCXXABI::iOS:
- case TargetCXXABI::iOS64:
- case TargetCXXABI::WatchOS:
- case TargetCXXABI::GenericMIPS:
- case TargetCXXABI::GenericItanium:
- case TargetCXXABI::WebAssembly:
- return CreateItaniumCXXABI(CGM);
- case TargetCXXABI::Microsoft:
- return CreateMicrosoftCXXABI(CGM);
- }
-
- llvm_unreachable("invalid C++ ABI kind");
-}
-
-CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
- const PreprocessorOptions &PPO,
- const CodeGenOptions &CGO, llvm::Module &M,
- DiagnosticsEngine &diags,
- CoverageSourceInfo *CoverageInfo)
- : Context(C), LangOpts(C.getLangOpts()), HeaderSearchOpts(HSO),
- PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags),
- Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
- VMContext(M.getContext()), Types(*this), VTables(*this),
- SanitizerMD(new SanitizerMetadata(*this)) {
-
- // Initialize the type cache.
- llvm::LLVMContext &LLVMContext = M.getContext();
- VoidTy = llvm::Type::getVoidTy(LLVMContext);
- Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
- Int16Ty = llvm::Type::getInt16Ty(LLVMContext);
- Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
- Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
- HalfTy = llvm::Type::getHalfTy(LLVMContext);
- FloatTy = llvm::Type::getFloatTy(LLVMContext);
- DoubleTy = llvm::Type::getDoubleTy(LLVMContext);
- PointerWidthInBits = C.getTargetInfo().getPointerWidth(0);
- PointerAlignInBytes =
- C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity();
- SizeSizeInBytes =
- C.toCharUnitsFromBits(C.getTargetInfo().getMaxPointerWidth()).getQuantity();
- IntAlignInBytes =
- C.toCharUnitsFromBits(C.getTargetInfo().getIntAlign()).getQuantity();
- IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth());
- IntPtrTy = llvm::IntegerType::get(LLVMContext,
- C.getTargetInfo().getMaxPointerWidth());
- Int8PtrTy = Int8Ty->getPointerTo(0);
- Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
- AllocaInt8PtrTy = Int8Ty->getPointerTo(
- M.getDataLayout().getAllocaAddrSpace());
- ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace();
-
- RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
-
- if (LangOpts.ObjC)
- createObjCRuntime();
- if (LangOpts.OpenCL)
- createOpenCLRuntime();
- if (LangOpts.OpenMP)
- createOpenMPRuntime();
- if (LangOpts.CUDA)
- createCUDARuntime();
-
- // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (LangOpts.Sanitize.has(SanitizerKind::Thread) ||
- (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
- TBAA.reset(new CodeGenTBAA(Context, TheModule, CodeGenOpts, getLangOpts(),
- getCXXABI().getMangleContext()));
-
- // If debug info or coverage generation is enabled, create the CGDebugInfo
- // object.
- if (CodeGenOpts.getDebugInfo() != codegenoptions::NoDebugInfo ||
- CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)
- DebugInfo.reset(new CGDebugInfo(*this));
-
- Block.GlobalUniqueCount = 0;
-
- if (C.getLangOpts().ObjC)
- ObjCData.reset(new ObjCEntrypoints());
-
- if (CodeGenOpts.hasProfileClangUse()) {
- auto ReaderOrErr = llvm::IndexedInstrProfReader::create(
- CodeGenOpts.ProfileInstrumentUsePath, CodeGenOpts.ProfileRemappingFile);
- if (auto E = ReaderOrErr.takeError()) {
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "Could not read profile %0: %1");
- llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) {
- getDiags().Report(DiagID) << CodeGenOpts.ProfileInstrumentUsePath
- << EI.message();
- });
- } else
- PGOReader = std::move(ReaderOrErr.get());
- }
-
- // If coverage mapping generation is enabled, create the
- // CoverageMappingModuleGen object.
- if (CodeGenOpts.CoverageMapping)
- CoverageMapping.reset(new CoverageMappingModuleGen(*this, *CoverageInfo));
-}
-
-CodeGenModule::~CodeGenModule() {}
-
-void CodeGenModule::createObjCRuntime() {
- // This is just isGNUFamily(), but we want to force implementors of
- // new ABIs to decide how best to do this.
- switch (LangOpts.ObjCRuntime.getKind()) {
- case ObjCRuntime::GNUstep:
- case ObjCRuntime::GCC:
- case ObjCRuntime::ObjFW:
- ObjCRuntime.reset(CreateGNUObjCRuntime(*this));
- return;
-
- case ObjCRuntime::FragileMacOSX:
- case ObjCRuntime::MacOSX:
- case ObjCRuntime::iOS:
- case ObjCRuntime::WatchOS:
- ObjCRuntime.reset(CreateMacObjCRuntime(*this));
- return;
- }
- llvm_unreachable("bad runtime kind");
-}
-
-void CodeGenModule::createOpenCLRuntime() {
- OpenCLRuntime.reset(new CGOpenCLRuntime(*this));
-}
-
-void CodeGenModule::createOpenMPRuntime() {
- // Select a specialized code generation class based on the target, if any.
- // If it does not exist use the default implementation.
- switch (getTriple().getArch()) {
- case llvm::Triple::nvptx:
- case llvm::Triple::nvptx64:
- assert(getLangOpts().OpenMPIsDevice &&
- "OpenMP NVPTX is only prepared to deal with device code.");
- OpenMPRuntime.reset(new CGOpenMPRuntimeNVPTX(*this));
- break;
- default:
- if (LangOpts.OpenMPSimd)
- OpenMPRuntime.reset(new CGOpenMPSIMDRuntime(*this));
- else
- OpenMPRuntime.reset(new CGOpenMPRuntime(*this));
- break;
- }
-}
-
-void CodeGenModule::createCUDARuntime() {
- CUDARuntime.reset(CreateNVCUDARuntime(*this));
-}
-
-void CodeGenModule::addReplacement(StringRef Name, llvm::Constant *C) {
- Replacements[Name] = C;
-}
-
-void CodeGenModule::applyReplacements() {
- for (auto &I : Replacements) {
- StringRef MangledName = I.first();
- llvm::Constant *Replacement = I.second;
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- if (!Entry)
- continue;
- auto *OldF = cast<llvm::Function>(Entry);
- auto *NewF = dyn_cast<llvm::Function>(Replacement);
- if (!NewF) {
- if (auto *Alias = dyn_cast<llvm::GlobalAlias>(Replacement)) {
- NewF = dyn_cast<llvm::Function>(Alias->getAliasee());
- } else {
- auto *CE = cast<llvm::ConstantExpr>(Replacement);
- assert(CE->getOpcode() == llvm::Instruction::BitCast ||
- CE->getOpcode() == llvm::Instruction::GetElementPtr);
- NewF = dyn_cast<llvm::Function>(CE->getOperand(0));
- }
- }
-
- // Replace old with new, but keep the old order.
- OldF->replaceAllUsesWith(Replacement);
- if (NewF) {
- NewF->removeFromParent();
- OldF->getParent()->getFunctionList().insertAfter(OldF->getIterator(),
- NewF);
- }
- OldF->eraseFromParent();
- }
-}
-
-void CodeGenModule::addGlobalValReplacement(llvm::GlobalValue *GV, llvm::Constant *C) {
- GlobalValReplacements.push_back(std::make_pair(GV, C));
-}
-
-void CodeGenModule::applyGlobalValReplacements() {
- for (auto &I : GlobalValReplacements) {
- llvm::GlobalValue *GV = I.first;
- llvm::Constant *C = I.second;
-
- GV->replaceAllUsesWith(C);
- GV->eraseFromParent();
- }
-}
-
-// This is only used in aliases that we created and we know they have a
-// linear structure.
-static const llvm::GlobalObject *getAliasedGlobal(
- const llvm::GlobalIndirectSymbol &GIS) {
- llvm::SmallPtrSet<const llvm::GlobalIndirectSymbol*, 4> Visited;
- const llvm::Constant *C = &GIS;
- for (;;) {
- C = C->stripPointerCasts();
- if (auto *GO = dyn_cast<llvm::GlobalObject>(C))
- return GO;
- // stripPointerCasts will not walk over weak aliases.
- auto *GIS2 = dyn_cast<llvm::GlobalIndirectSymbol>(C);
- if (!GIS2)
- return nullptr;
- if (!Visited.insert(GIS2).second)
- return nullptr;
- C = GIS2->getIndirectSymbol();
- }
-}
-
-void CodeGenModule::checkAliases() {
- // Check if the constructed aliases are well formed. It is really unfortunate
- // that we have to do this in CodeGen, but we only construct mangled names
- // and aliases during codegen.
- bool Error = false;
- DiagnosticsEngine &Diags = getDiags();
- for (const GlobalDecl &GD : Aliases) {
- const auto *D = cast<ValueDecl>(GD.getDecl());
- SourceLocation Location;
- bool IsIFunc = D->hasAttr<IFuncAttr>();
- if (const Attr *A = D->getDefiningAttr())
- Location = A->getLocation();
- else
- llvm_unreachable("Not an alias or ifunc?");
- StringRef MangledName = getMangledName(GD);
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- auto *Alias = cast<llvm::GlobalIndirectSymbol>(Entry);
- const llvm::GlobalValue *GV = getAliasedGlobal(*Alias);
- if (!GV) {
- Error = true;
- Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc;
- } else if (GV->isDeclaration()) {
- Error = true;
- Diags.Report(Location, diag::err_alias_to_undefined)
- << IsIFunc << IsIFunc;
- } else if (IsIFunc) {
- // Check resolver function type.
- llvm::FunctionType *FTy = dyn_cast<llvm::FunctionType>(
- GV->getType()->getPointerElementType());
- assert(FTy);
- if (!FTy->getReturnType()->isPointerTy())
- Diags.Report(Location, diag::err_ifunc_resolver_return);
- }
-
- llvm::Constant *Aliasee = Alias->getIndirectSymbol();
- llvm::GlobalValue *AliaseeGV;
- if (auto CE = dyn_cast<llvm::ConstantExpr>(Aliasee))
- AliaseeGV = cast<llvm::GlobalValue>(CE->getOperand(0));
- else
- AliaseeGV = cast<llvm::GlobalValue>(Aliasee);
-
- if (const SectionAttr *SA = D->getAttr<SectionAttr>()) {
- StringRef AliasSection = SA->getName();
- if (AliasSection != AliaseeGV->getSection())
- Diags.Report(SA->getLocation(), diag::warn_alias_with_section)
- << AliasSection << IsIFunc << IsIFunc;
- }
-
- // We have to handle alias to weak aliases in here. LLVM itself disallows
- // this since the object semantics would not match the IL one. For
- // compatibility with gcc we implement it by just pointing the alias
- // to its aliasee's aliasee. We also warn, since the user is probably
- // expecting the link to be weak.
- if (auto GA = dyn_cast<llvm::GlobalIndirectSymbol>(AliaseeGV)) {
- if (GA->isInterposable()) {
- Diags.Report(Location, diag::warn_alias_to_weak_alias)
- << GV->getName() << GA->getName() << IsIFunc;
- Aliasee = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
- GA->getIndirectSymbol(), Alias->getType());
- Alias->setIndirectSymbol(Aliasee);
- }
- }
- }
- if (!Error)
- return;
-
- for (const GlobalDecl &GD : Aliases) {
- StringRef MangledName = getMangledName(GD);
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- auto *Alias = dyn_cast<llvm::GlobalIndirectSymbol>(Entry);
- Alias->replaceAllUsesWith(llvm::UndefValue::get(Alias->getType()));
- Alias->eraseFromParent();
- }
-}
-
-void CodeGenModule::clear() {
- DeferredDeclsToEmit.clear();
- if (OpenMPRuntime)
- OpenMPRuntime->clear();
-}
-
-void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags,
- StringRef MainFile) {
- if (!hasDiagnostics())
- return;
- if (VisitedInMainFile > 0 && VisitedInMainFile == MissingInMainFile) {
- if (MainFile.empty())
- MainFile = "<stdin>";
- Diags.Report(diag::warn_profile_data_unprofiled) << MainFile;
- } else {
- if (Mismatched > 0)
- Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Mismatched;
-
- if (Missing > 0)
- Diags.Report(diag::warn_profile_data_missing) << Visited << Missing;
- }
-}
-
-void CodeGenModule::Release() {
- EmitDeferred();
- EmitVTablesOpportunistically();
- applyGlobalValReplacements();
- applyReplacements();
- checkAliases();
- emitMultiVersionFunctions();
- EmitCXXGlobalInitFunc();
- EmitCXXGlobalDtorFunc();
- registerGlobalDtorsWithAtExit();
- EmitCXXThreadLocalInitFunc();
- if (ObjCRuntime)
- if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction())
- AddGlobalCtor(ObjCInitFunction);
- if (Context.getLangOpts().CUDA && !Context.getLangOpts().CUDAIsDevice &&
- CUDARuntime) {
- if (llvm::Function *CudaCtorFunction =
- CUDARuntime->makeModuleCtorFunction())
- AddGlobalCtor(CudaCtorFunction);
- }
- if (OpenMPRuntime) {
- if (llvm::Function *OpenMPRegistrationFunction =
- OpenMPRuntime->emitRegistrationFunction()) {
- auto ComdatKey = OpenMPRegistrationFunction->hasComdat() ?
- OpenMPRegistrationFunction : nullptr;
- AddGlobalCtor(OpenMPRegistrationFunction, 0, ComdatKey);
- }
- OpenMPRuntime->clear();
- }
- if (PGOReader) {
- getModule().setProfileSummary(PGOReader->getSummary().getMD(VMContext));
- if (PGOStats.hasDiagnostics())
- PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName);
- }
- EmitCtorList(GlobalCtors, "llvm.global_ctors");
- EmitCtorList(GlobalDtors, "llvm.global_dtors");
- EmitGlobalAnnotations();
- EmitStaticExternCAliases();
- EmitDeferredUnusedCoverageMappings();
- if (CoverageMapping)
- CoverageMapping->emit();
- if (CodeGenOpts.SanitizeCfiCrossDso) {
- CodeGenFunction(*this).EmitCfiCheckFail();
- CodeGenFunction(*this).EmitCfiCheckStub();
- }
- emitAtAvailableLinkGuard();
- emitLLVMUsed();
- if (SanStats)
- SanStats->finish();
-
- if (CodeGenOpts.Autolink &&
- (Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
- EmitModuleLinkOptions();
- }
-
- // Record mregparm value now so it is visible through rest of codegen.
- if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
- getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters",
- CodeGenOpts.NumRegisterParameters);
-
- if (CodeGenOpts.DwarfVersion) {
- // We actually want the latest version when there are conflicts.
- // We can change from Warning to Latest if such mode is supported.
- getModule().addModuleFlag(llvm::Module::Warning, "Dwarf Version",
- CodeGenOpts.DwarfVersion);
- }
- if (CodeGenOpts.EmitCodeView) {
- // Indicate that we want CodeView in the metadata.
- getModule().addModuleFlag(llvm::Module::Warning, "CodeView", 1);
- }
- if (CodeGenOpts.CodeViewGHash) {
- getModule().addModuleFlag(llvm::Module::Warning, "CodeViewGHash", 1);
- }
- if (CodeGenOpts.ControlFlowGuard) {
- // We want function ID tables for Control Flow Guard.
- getModule().addModuleFlag(llvm::Module::Warning, "cfguardtable", 1);
- }
- if (CodeGenOpts.OptimizationLevel > 0 && CodeGenOpts.StrictVTablePointers) {
- // We don't support LTO with 2 with different StrictVTablePointers
- // FIXME: we could support it by stripping all the information introduced
- // by StrictVTablePointers.
-
- getModule().addModuleFlag(llvm::Module::Error, "StrictVTablePointers",1);
-
- llvm::Metadata *Ops[2] = {
- llvm::MDString::get(VMContext, "StrictVTablePointers"),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), 1))};
-
- getModule().addModuleFlag(llvm::Module::Require,
- "StrictVTablePointersRequirement",
- llvm::MDNode::get(VMContext, Ops));
- }
- if (DebugInfo)
- // We support a single version in the linked module. The LLVM
- // parser will drop debug info with a different version number
- // (and warn about it, too).
- getModule().addModuleFlag(llvm::Module::Warning, "Debug Info Version",
- llvm::DEBUG_METADATA_VERSION);
-
- // We need to record the widths of enums and wchar_t, so that we can generate
- // the correct build attributes in the ARM backend. wchar_size is also used by
- // TargetLibraryInfo.
- uint64_t WCharWidth =
- Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity();
- getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth);
-
- llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
- if ( Arch == llvm::Triple::arm
- || Arch == llvm::Triple::armeb
- || Arch == llvm::Triple::thumb
- || Arch == llvm::Triple::thumbeb) {
- // The minimum width of an enum in bytes
- uint64_t EnumWidth = Context.getLangOpts().ShortEnums ? 1 : 4;
- getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
- }
-
- if (CodeGenOpts.SanitizeCfiCrossDso) {
- // Indicate that we want cross-DSO control flow integrity checks.
- getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1);
- }
-
- if (CodeGenOpts.CFProtectionReturn &&
- Target.checkCFProtectionReturnSupported(getDiags())) {
- // Indicate that we want to instrument return control flow protection.
- getModule().addModuleFlag(llvm::Module::Override, "cf-protection-return",
- 1);
- }
-
- if (CodeGenOpts.CFProtectionBranch &&
- Target.checkCFProtectionBranchSupported(getDiags())) {
- // Indicate that we want to instrument branch control flow protection.
- getModule().addModuleFlag(llvm::Module::Override, "cf-protection-branch",
- 1);
- }
-
- if (LangOpts.CUDAIsDevice && getTriple().isNVPTX()) {
- // Indicate whether __nvvm_reflect should be configured to flush denormal
- // floating point values to 0. (This corresponds to its "__CUDA_FTZ"
- // property.)
- getModule().addModuleFlag(llvm::Module::Override, "nvvm-reflect-ftz",
- CodeGenOpts.FlushDenorm ? 1 : 0);
- }
-
- // Emit OpenCL specific module metadata: OpenCL/SPIR version.
- if (LangOpts.OpenCL) {
- EmitOpenCLMetadata();
- // Emit SPIR version.
- if (getTriple().getArch() == llvm::Triple::spir ||
- getTriple().getArch() == llvm::Triple::spir64) {
- // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the
- // opencl.spir.version named metadata.
- llvm::Metadata *SPIRVerElts[] = {
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, LangOpts.OpenCLVersion / 100)),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, (LangOpts.OpenCLVersion / 100 > 1) ? 0 : 2))};
- llvm::NamedMDNode *SPIRVerMD =
- TheModule.getOrInsertNamedMetadata("opencl.spir.version");
- llvm::LLVMContext &Ctx = TheModule.getContext();
- SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts));
- }
- }
-
- if (uint32_t PLevel = Context.getLangOpts().PICLevel) {
- assert(PLevel < 3 && "Invalid PIC Level");
- getModule().setPICLevel(static_cast<llvm::PICLevel::Level>(PLevel));
- if (Context.getLangOpts().PIE)
- getModule().setPIELevel(static_cast<llvm::PIELevel::Level>(PLevel));
- }
-
- if (getCodeGenOpts().CodeModel.size() > 0) {
- unsigned CM = llvm::StringSwitch<unsigned>(getCodeGenOpts().CodeModel)
- .Case("tiny", llvm::CodeModel::Tiny)
- .Case("small", llvm::CodeModel::Small)
- .Case("kernel", llvm::CodeModel::Kernel)
- .Case("medium", llvm::CodeModel::Medium)
- .Case("large", llvm::CodeModel::Large)
- .Default(~0u);
- if (CM != ~0u) {
- llvm::CodeModel::Model codeModel = static_cast<llvm::CodeModel::Model>(CM);
- getModule().setCodeModel(codeModel);
- }
- }
-
- if (CodeGenOpts.NoPLT)
- getModule().setRtLibUseGOT();
-
- SimplifyPersonality();
-
- if (getCodeGenOpts().EmitDeclMetadata)
- EmitDeclMetadata();
-
- if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes)
- EmitCoverageFile();
-
- if (DebugInfo)
- DebugInfo->finalize();
-
- if (getCodeGenOpts().EmitVersionIdentMetadata)
- EmitVersionIdentMetadata();
-
- if (!getCodeGenOpts().RecordCommandLine.empty())
- EmitCommandLineMetadata();
-
- EmitTargetMetadata();
-}
-
-void CodeGenModule::EmitOpenCLMetadata() {
- // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
- // opencl.ocl.version named metadata node.
- llvm::Metadata *OCLVerElts[] = {
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, LangOpts.OpenCLVersion / 100)),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, (LangOpts.OpenCLVersion % 100) / 10))};
- llvm::NamedMDNode *OCLVerMD =
- TheModule.getOrInsertNamedMetadata("opencl.ocl.version");
- llvm::LLVMContext &Ctx = TheModule.getContext();
- OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
-}
-
-void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
- // Make sure that this type is translated.
- Types.UpdateCompletedType(TD);
-}
-
-void CodeGenModule::RefreshTypeCacheForClass(const CXXRecordDecl *RD) {
- // Make sure that this type is translated.
- Types.RefreshTypeCacheForClass(RD);
-}
-
-llvm::MDNode *CodeGenModule::getTBAATypeInfo(QualType QTy) {
- if (!TBAA)
- return nullptr;
- return TBAA->getTypeInfo(QTy);
-}
-
-TBAAAccessInfo CodeGenModule::getTBAAAccessInfo(QualType AccessType) {
- if (!TBAA)
- return TBAAAccessInfo();
- return TBAA->getAccessInfo(AccessType);
-}
-
-TBAAAccessInfo
-CodeGenModule::getTBAAVTablePtrAccessInfo(llvm::Type *VTablePtrType) {
- if (!TBAA)
- return TBAAAccessInfo();
- return TBAA->getVTablePtrAccessInfo(VTablePtrType);
-}
-
-llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
- if (!TBAA)
- return nullptr;
- return TBAA->getTBAAStructInfo(QTy);
-}
-
-llvm::MDNode *CodeGenModule::getTBAABaseTypeInfo(QualType QTy) {
- if (!TBAA)
- return nullptr;
- return TBAA->getBaseTypeInfo(QTy);
-}
-
-llvm::MDNode *CodeGenModule::getTBAAAccessTagInfo(TBAAAccessInfo Info) {
- if (!TBAA)
- return nullptr;
- return TBAA->getAccessTagInfo(Info);
-}
-
-TBAAAccessInfo CodeGenModule::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
- TBAAAccessInfo TargetInfo) {
- if (!TBAA)
- return TBAAAccessInfo();
- return TBAA->mergeTBAAInfoForCast(SourceInfo, TargetInfo);
-}
-
-TBAAAccessInfo
-CodeGenModule::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
- TBAAAccessInfo InfoB) {
- if (!TBAA)
- return TBAAAccessInfo();
- return TBAA->mergeTBAAInfoForConditionalOperator(InfoA, InfoB);
-}
-
-TBAAAccessInfo
-CodeGenModule::mergeTBAAInfoForMemoryTransfer(TBAAAccessInfo DestInfo,
- TBAAAccessInfo SrcInfo) {
- if (!TBAA)
- return TBAAAccessInfo();
- return TBAA->mergeTBAAInfoForConditionalOperator(DestInfo, SrcInfo);
-}
-
-void CodeGenModule::DecorateInstructionWithTBAA(llvm::Instruction *Inst,
- TBAAAccessInfo TBAAInfo) {
- if (llvm::MDNode *Tag = getTBAAAccessTagInfo(TBAAInfo))
- Inst->setMetadata(llvm::LLVMContext::MD_tbaa, Tag);
-}
-
-void CodeGenModule::DecorateInstructionWithInvariantGroup(
- llvm::Instruction *I, const CXXRecordDecl *RD) {
- I->setMetadata(llvm::LLVMContext::MD_invariant_group,
- llvm::MDNode::get(getLLVMContext(), {}));
-}
-
-void CodeGenModule::Error(SourceLocation loc, StringRef message) {
- unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "%0");
- getDiags().Report(Context.getFullLoc(loc), diagID) << message;
-}
-
-/// ErrorUnsupported - Print out an error that codegen doesn't support the
-/// specified stmt yet.
-void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot compile this %0 yet");
- std::string Msg = Type;
- getDiags().Report(Context.getFullLoc(S->getBeginLoc()), DiagID)
- << Msg << S->getSourceRange();
-}
-
-/// ErrorUnsupported - Print out an error that codegen doesn't support the
-/// specified decl yet.
-void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot compile this %0 yet");
- std::string Msg = Type;
- getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
-}
-
-llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) {
- return llvm::ConstantInt::get(SizeTy, size.getQuantity());
-}
-
-void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
- const NamedDecl *D) const {
- if (GV->hasDLLImportStorageClass())
- return;
- // Internal definitions always have default visibility.
- if (GV->hasLocalLinkage()) {
- GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
- return;
- }
- if (!D)
- return;
- // Set visibility for definitions.
- LinkageInfo LV = D->getLinkageAndVisibility();
- if (LV.isVisibilityExplicit() || !GV->isDeclarationForLinker())
- GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
-}
-
-static bool shouldAssumeDSOLocal(const CodeGenModule &CGM,
- llvm::GlobalValue *GV) {
- if (GV->hasLocalLinkage())
- return true;
-
- if (!GV->hasDefaultVisibility() && !GV->hasExternalWeakLinkage())
- return true;
-
- // DLLImport explicitly marks the GV as external.
- if (GV->hasDLLImportStorageClass())
- return false;
-
- const llvm::Triple &TT = CGM.getTriple();
- if (TT.isWindowsGNUEnvironment()) {
- // In MinGW, variables without DLLImport can still be automatically
- // imported from a DLL by the linker; don't mark variables that
- // potentially could come from another DLL as DSO local.
- if (GV->isDeclarationForLinker() && isa<llvm::GlobalVariable>(GV) &&
- !GV->isThreadLocal())
- return false;
- }
- // Every other GV is local on COFF.
- // Make an exception for windows OS in the triple: Some firmware builds use
- // *-win32-macho triples. This (accidentally?) produced windows relocations
- // without GOT tables in older clang versions; Keep this behaviour.
- // FIXME: even thread local variables?
- if (TT.isOSBinFormatCOFF() || (TT.isOSWindows() && TT.isOSBinFormatMachO()))
- return true;
-
- // Only handle COFF and ELF for now.
- if (!TT.isOSBinFormatELF())
- return false;
-
- // If this is not an executable, don't assume anything is local.
- const auto &CGOpts = CGM.getCodeGenOpts();
- llvm::Reloc::Model RM = CGOpts.RelocationModel;
- const auto &LOpts = CGM.getLangOpts();
- if (RM != llvm::Reloc::Static && !LOpts.PIE)
- return false;
-
- // A definition cannot be preempted from an executable.
- if (!GV->isDeclarationForLinker())
- return true;
-
- // Most PIC code sequences that assume that a symbol is local cannot produce a
- // 0 if it turns out the symbol is undefined. While this is ABI and relocation
- // depended, it seems worth it to handle it here.
- if (RM == llvm::Reloc::PIC_ && GV->hasExternalWeakLinkage())
- return false;
-
- // PPC has no copy relocations and cannot use a plt entry as a symbol address.
- llvm::Triple::ArchType Arch = TT.getArch();
- if (Arch == llvm::Triple::ppc || Arch == llvm::Triple::ppc64 ||
- Arch == llvm::Triple::ppc64le)
- return false;
-
- // If we can use copy relocations we can assume it is local.
- if (auto *Var = dyn_cast<llvm::GlobalVariable>(GV))
- if (!Var->isThreadLocal() &&
- (RM == llvm::Reloc::Static || CGOpts.PIECopyRelocations))
- return true;
-
- // If we can use a plt entry as the symbol address we can assume it
- // is local.
- // FIXME: This should work for PIE, but the gold linker doesn't support it.
- if (isa<llvm::Function>(GV) && !CGOpts.NoPLT && RM == llvm::Reloc::Static)
- return true;
-
- // Otherwise don't assue it is local.
- return false;
-}
-
-void CodeGenModule::setDSOLocal(llvm::GlobalValue *GV) const {
- GV->setDSOLocal(shouldAssumeDSOLocal(*this, GV));
-}
-
-void CodeGenModule::setDLLImportDLLExport(llvm::GlobalValue *GV,
- GlobalDecl GD) const {
- const auto *D = dyn_cast<NamedDecl>(GD.getDecl());
- // C++ destructors have a few C++ ABI specific special cases.
- if (const auto *Dtor = dyn_cast_or_null<CXXDestructorDecl>(D)) {
- getCXXABI().setCXXDestructorDLLStorage(GV, Dtor, GD.getDtorType());
- return;
- }
- setDLLImportDLLExport(GV, D);
-}
-
-void CodeGenModule::setDLLImportDLLExport(llvm::GlobalValue *GV,
- const NamedDecl *D) const {
- if (D && D->isExternallyVisible()) {
- if (D->hasAttr<DLLImportAttr>())
- GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
- else if (D->hasAttr<DLLExportAttr>() && !GV->isDeclarationForLinker())
- GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
- }
-}
-
-void CodeGenModule::setGVProperties(llvm::GlobalValue *GV,
- GlobalDecl GD) const {
- setDLLImportDLLExport(GV, GD);
- setGlobalVisibilityAndLocal(GV, dyn_cast<NamedDecl>(GD.getDecl()));
-}
-
-void CodeGenModule::setGVProperties(llvm::GlobalValue *GV,
- const NamedDecl *D) const {
- setDLLImportDLLExport(GV, D);
- setGlobalVisibilityAndLocal(GV, D);
-}
-
-void CodeGenModule::setGlobalVisibilityAndLocal(llvm::GlobalValue *GV,
- const NamedDecl *D) const {
- setGlobalVisibility(GV, D);
- setDSOLocal(GV);
-}
-
-static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(StringRef S) {
- return llvm::StringSwitch<llvm::GlobalVariable::ThreadLocalMode>(S)
- .Case("global-dynamic", llvm::GlobalVariable::GeneralDynamicTLSModel)
- .Case("local-dynamic", llvm::GlobalVariable::LocalDynamicTLSModel)
- .Case("initial-exec", llvm::GlobalVariable::InitialExecTLSModel)
- .Case("local-exec", llvm::GlobalVariable::LocalExecTLSModel);
-}
-
-static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(
- CodeGenOptions::TLSModel M) {
- switch (M) {
- case CodeGenOptions::GeneralDynamicTLSModel:
- return llvm::GlobalVariable::GeneralDynamicTLSModel;
- case CodeGenOptions::LocalDynamicTLSModel:
- return llvm::GlobalVariable::LocalDynamicTLSModel;
- case CodeGenOptions::InitialExecTLSModel:
- return llvm::GlobalVariable::InitialExecTLSModel;
- case CodeGenOptions::LocalExecTLSModel:
- return llvm::GlobalVariable::LocalExecTLSModel;
- }
- llvm_unreachable("Invalid TLS model!");
-}
-
-void CodeGenModule::setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const {
- assert(D.getTLSKind() && "setting TLS mode on non-TLS var!");
-
- llvm::GlobalValue::ThreadLocalMode TLM;
- TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel());
-
- // Override the TLS model if it is explicitly specified.
- if (const TLSModelAttr *Attr = D.getAttr<TLSModelAttr>()) {
- TLM = GetLLVMTLSModel(Attr->getModel());
- }
-
- GV->setThreadLocalMode(TLM);
-}
-
-static std::string getCPUSpecificMangling(const CodeGenModule &CGM,
- StringRef Name) {
- const TargetInfo &Target = CGM.getTarget();
- return (Twine('.') + Twine(Target.CPUSpecificManglingCharacter(Name))).str();
-}
-
-static void AppendCPUSpecificCPUDispatchMangling(const CodeGenModule &CGM,
- const CPUSpecificAttr *Attr,
- unsigned CPUIndex,
- raw_ostream &Out) {
- // cpu_specific gets the current name, dispatch gets the resolver if IFunc is
- // supported.
- if (Attr)
- Out << getCPUSpecificMangling(CGM, Attr->getCPUName(CPUIndex)->getName());
- else if (CGM.getTarget().supportsIFunc())
- Out << ".resolver";
-}
-
-static void AppendTargetMangling(const CodeGenModule &CGM,
- const TargetAttr *Attr, raw_ostream &Out) {
- if (Attr->isDefaultVersion())
- return;
-
- Out << '.';
- const TargetInfo &Target = CGM.getTarget();
- TargetAttr::ParsedTargetAttr Info =
- Attr->parse([&Target](StringRef LHS, StringRef RHS) {
- // Multiversioning doesn't allow "no-${feature}", so we can
- // only have "+" prefixes here.
- assert(LHS.startswith("+") && RHS.startswith("+") &&
- "Features should always have a prefix.");
- return Target.multiVersionSortPriority(LHS.substr(1)) >
- Target.multiVersionSortPriority(RHS.substr(1));
- });
-
- bool IsFirst = true;
-
- if (!Info.Architecture.empty()) {
- IsFirst = false;
- Out << "arch_" << Info.Architecture;
- }
-
- for (StringRef Feat : Info.Features) {
- if (!IsFirst)
- Out << '_';
- IsFirst = false;
- Out << Feat.substr(1);
- }
-}
-
-static std::string getMangledNameImpl(const CodeGenModule &CGM, GlobalDecl GD,
- const NamedDecl *ND,
- bool OmitMultiVersionMangling = false) {
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- MangleContext &MC = CGM.getCXXABI().getMangleContext();
- if (MC.shouldMangleDeclName(ND)) {
- llvm::raw_svector_ostream Out(Buffer);
- if (const auto *D = dyn_cast<CXXConstructorDecl>(ND))
- MC.mangleCXXCtor(D, GD.getCtorType(), Out);
- else if (const auto *D = dyn_cast<CXXDestructorDecl>(ND))
- MC.mangleCXXDtor(D, GD.getDtorType(), Out);
- else
- MC.mangleName(ND, Out);
- } else {
- IdentifierInfo *II = ND->getIdentifier();
- assert(II && "Attempt to mangle unnamed decl.");
- const auto *FD = dyn_cast<FunctionDecl>(ND);
-
- if (FD &&
- FD->getType()->castAs<FunctionType>()->getCallConv() == CC_X86RegCall) {
- llvm::raw_svector_ostream Out(Buffer);
- Out << "__regcall3__" << II->getName();
- } else {
- Out << II->getName();
- }
- }
-
- if (const auto *FD = dyn_cast<FunctionDecl>(ND))
- if (FD->isMultiVersion() && !OmitMultiVersionMangling) {
- switch (FD->getMultiVersionKind()) {
- case MultiVersionKind::CPUDispatch:
- case MultiVersionKind::CPUSpecific:
- AppendCPUSpecificCPUDispatchMangling(CGM,
- FD->getAttr<CPUSpecificAttr>(),
- GD.getMultiVersionIndex(), Out);
- break;
- case MultiVersionKind::Target:
- AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out);
- break;
- case MultiVersionKind::None:
- llvm_unreachable("None multiversion type isn't valid here");
- }
- }
-
- return Out.str();
-}
-
-void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD,
- const FunctionDecl *FD) {
- if (!FD->isMultiVersion())
- return;
-
- // Get the name of what this would be without the 'target' attribute. This
- // allows us to lookup the version that was emitted when this wasn't a
- // multiversion function.
- std::string NonTargetName =
- getMangledNameImpl(*this, GD, FD, /*OmitMultiVersionMangling=*/true);
- GlobalDecl OtherGD;
- if (lookupRepresentativeDecl(NonTargetName, OtherGD)) {
- assert(OtherGD.getCanonicalDecl()
- .getDecl()
- ->getAsFunction()
- ->isMultiVersion() &&
- "Other GD should now be a multiversioned function");
- // OtherFD is the version of this function that was mangled BEFORE
- // becoming a MultiVersion function. It potentially needs to be updated.
- const FunctionDecl *OtherFD = OtherGD.getCanonicalDecl()
- .getDecl()
- ->getAsFunction()
- ->getMostRecentDecl();
- std::string OtherName = getMangledNameImpl(*this, OtherGD, OtherFD);
- // This is so that if the initial version was already the 'default'
- // version, we don't try to update it.
- if (OtherName != NonTargetName) {
- // Remove instead of erase, since others may have stored the StringRef
- // to this.
- const auto ExistingRecord = Manglings.find(NonTargetName);
- if (ExistingRecord != std::end(Manglings))
- Manglings.remove(&(*ExistingRecord));
- auto Result = Manglings.insert(std::make_pair(OtherName, OtherGD));
- MangledDeclNames[OtherGD.getCanonicalDecl()] = Result.first->first();
- if (llvm::GlobalValue *Entry = GetGlobalValue(NonTargetName))
- Entry->setName(OtherName);
- }
- }
-}
-
-StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
- GlobalDecl CanonicalGD = GD.getCanonicalDecl();
-
- // Some ABIs don't have constructor variants. Make sure that base and
- // complete constructors get mangled the same.
- if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
- if (!getTarget().getCXXABI().hasConstructorVariants()) {
- CXXCtorType OrigCtorType = GD.getCtorType();
- assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
- if (OrigCtorType == Ctor_Base)
- CanonicalGD = GlobalDecl(CD, Ctor_Complete);
- }
- }
-
- auto FoundName = MangledDeclNames.find(CanonicalGD);
- if (FoundName != MangledDeclNames.end())
- return FoundName->second;
-
- // Keep the first result in the case of a mangling collision.
- const auto *ND = cast<NamedDecl>(GD.getDecl());
- auto Result =
- Manglings.insert(std::make_pair(getMangledNameImpl(*this, GD, ND), GD));
- return MangledDeclNames[CanonicalGD] = Result.first->first();
-}
-
-StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD,
- const BlockDecl *BD) {
- MangleContext &MangleCtx = getCXXABI().getMangleContext();
- const Decl *D = GD.getDecl();
-
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- if (!D)
- MangleCtx.mangleGlobalBlock(BD,
- dyn_cast_or_null<VarDecl>(initializedGlobalDecl.getDecl()), Out);
- else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D))
- MangleCtx.mangleCtorBlock(CD, GD.getCtorType(), BD, Out);
- else if (const auto *DD = dyn_cast<CXXDestructorDecl>(D))
- MangleCtx.mangleDtorBlock(DD, GD.getDtorType(), BD, Out);
- else
- MangleCtx.mangleBlock(cast<DeclContext>(D), BD, Out);
-
- auto Result = Manglings.insert(std::make_pair(Out.str(), BD));
- return Result.first->first();
-}
-
-llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) {
- return getModule().getNamedValue(Name);
-}
-
-/// AddGlobalCtor - Add a function to the list that will be called before
-/// main() runs.
-void CodeGenModule::AddGlobalCtor(llvm::Function *Ctor, int Priority,
- llvm::Constant *AssociatedData) {
- // FIXME: Type coercion of void()* types.
- GlobalCtors.push_back(Structor(Priority, Ctor, AssociatedData));
-}
-
-/// AddGlobalDtor - Add a function to the list that will be called
-/// when the module is unloaded.
-void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority) {
- if (CodeGenOpts.RegisterGlobalDtorsWithAtExit) {
- DtorsUsingAtExit[Priority].push_back(Dtor);
- return;
- }
-
- // FIXME: Type coercion of void()* types.
- GlobalDtors.push_back(Structor(Priority, Dtor, nullptr));
-}
-
-void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
- if (Fns.empty()) return;
-
- // Ctor function type is void()*.
- llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
- llvm::Type *CtorPFTy = llvm::PointerType::get(CtorFTy,
- TheModule.getDataLayout().getProgramAddressSpace());
-
- // Get the type of a ctor entry, { i32, void ()*, i8* }.
- llvm::StructType *CtorStructTy = llvm::StructType::get(
- Int32Ty, CtorPFTy, VoidPtrTy);
-
- // Construct the constructor and destructor arrays.
- ConstantInitBuilder builder(*this);
- auto ctors = builder.beginArray(CtorStructTy);
- for (const auto &I : Fns) {
- auto ctor = ctors.beginStruct(CtorStructTy);
- ctor.addInt(Int32Ty, I.Priority);
- ctor.add(llvm::ConstantExpr::getBitCast(I.Initializer, CtorPFTy));
- if (I.AssociatedData)
- ctor.add(llvm::ConstantExpr::getBitCast(I.AssociatedData, VoidPtrTy));
- else
- ctor.addNullPointer(VoidPtrTy);
- ctor.finishAndAddTo(ctors);
- }
-
- auto list =
- ctors.finishAndCreateGlobal(GlobalName, getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::AppendingLinkage);
-
- // The LTO linker doesn't seem to like it when we set an alignment
- // on appending variables. Take it off as a workaround.
- list->setAlignment(0);
-
- Fns.clear();
-}
-
-llvm::GlobalValue::LinkageTypes
-CodeGenModule::getFunctionLinkage(GlobalDecl GD) {
- const auto *D = cast<FunctionDecl>(GD.getDecl());
-
- GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
-
- if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(D))
- return getCXXABI().getCXXDestructorLinkage(Linkage, Dtor, GD.getDtorType());
-
- if (isa<CXXConstructorDecl>(D) &&
- cast<CXXConstructorDecl>(D)->isInheritingConstructor() &&
- Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- // Our approach to inheriting constructors is fundamentally different from
- // that used by the MS ABI, so keep our inheriting constructor thunks
- // internal rather than trying to pick an unambiguous mangling for them.
- return llvm::GlobalValue::InternalLinkage;
- }
-
- return getLLVMLinkageForDeclarator(D, Linkage, /*isConstantVariable=*/false);
-}
-
-llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
- llvm::MDString *MDS = dyn_cast<llvm::MDString>(MD);
- if (!MDS) return nullptr;
-
- return llvm::ConstantInt::get(Int64Ty, llvm::MD5Hash(MDS->getString()));
-}
-
-void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,
- const CGFunctionInfo &Info,
- llvm::Function *F) {
- unsigned CallingConv;
- llvm::AttributeList PAL;
- ConstructAttributeList(F->getName(), Info, GD, PAL, CallingConv, false);
- F->setAttributes(PAL);
- F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
-}
-
-/// Determines whether the language options require us to model
-/// unwind exceptions. We treat -fexceptions as mandating this
-/// except under the fragile ObjC ABI with only ObjC exceptions
-/// enabled. This means, for example, that C with -fexceptions
-/// enables this.
-static bool hasUnwindExceptions(const LangOptions &LangOpts) {
- // If exceptions are completely disabled, obviously this is false.
- if (!LangOpts.Exceptions) return false;
-
- // If C++ exceptions are enabled, this is true.
- if (LangOpts.CXXExceptions) return true;
-
- // If ObjC exceptions are enabled, this depends on the ABI.
- if (LangOpts.ObjCExceptions) {
- return LangOpts.ObjCRuntime.hasUnwindExceptions();
- }
-
- return true;
-}
-
-static bool requiresMemberFunctionPointerTypeMetadata(CodeGenModule &CGM,
- const CXXMethodDecl *MD) {
- // Check that the type metadata can ever actually be used by a call.
- if (!CGM.getCodeGenOpts().LTOUnit ||
- !CGM.HasHiddenLTOVisibility(MD->getParent()))
- return false;
-
- // Only functions whose address can be taken with a member function pointer
- // need this sort of type metadata.
- return !MD->isStatic() && !MD->isVirtual() && !isa<CXXConstructorDecl>(MD) &&
- !isa<CXXDestructorDecl>(MD);
-}
-
-std::vector<const CXXRecordDecl *>
-CodeGenModule::getMostBaseClasses(const CXXRecordDecl *RD) {
- llvm::SetVector<const CXXRecordDecl *> MostBases;
-
- std::function<void (const CXXRecordDecl *)> CollectMostBases;
- CollectMostBases = [&](const CXXRecordDecl *RD) {
- if (RD->getNumBases() == 0)
- MostBases.insert(RD);
- for (const CXXBaseSpecifier &B : RD->bases())
- CollectMostBases(B.getType()->getAsCXXRecordDecl());
- };
- CollectMostBases(RD);
- return MostBases.takeVector();
-}
-
-void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
- llvm::Function *F) {
- llvm::AttrBuilder B;
-
- if (CodeGenOpts.UnwindTables)
- B.addAttribute(llvm::Attribute::UWTable);
-
- if (!hasUnwindExceptions(LangOpts))
- B.addAttribute(llvm::Attribute::NoUnwind);
-
- if (!D || !D->hasAttr<NoStackProtectorAttr>()) {
- if (LangOpts.getStackProtector() == LangOptions::SSPOn)
- B.addAttribute(llvm::Attribute::StackProtect);
- else if (LangOpts.getStackProtector() == LangOptions::SSPStrong)
- B.addAttribute(llvm::Attribute::StackProtectStrong);
- else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- B.addAttribute(llvm::Attribute::StackProtectReq);
- }
-
- if (!D) {
- // If we don't have a declaration to control inlining, the function isn't
- // explicitly marked as alwaysinline for semantic reasons, and inlining is
- // disabled, mark the function as noinline.
- if (!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
- CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining)
- B.addAttribute(llvm::Attribute::NoInline);
-
- F->addAttributes(llvm::AttributeList::FunctionIndex, B);
- return;
- }
-
- // Track whether we need to add the optnone LLVM attribute,
- // starting with the default for this optimization level.
- bool ShouldAddOptNone =
- !CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0;
- // We can't add optnone in the following cases, it won't pass the verifier.
- ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
- ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline);
- ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();
-
- if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) {
- B.addAttribute(llvm::Attribute::OptimizeNone);
-
- // OptimizeNone implies noinline; we should not be inlining such functions.
- B.addAttribute(llvm::Attribute::NoInline);
- assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
- "OptimizeNone and AlwaysInline on same function!");
-
- // We still need to handle naked functions even though optnone subsumes
- // much of their semantics.
- if (D->hasAttr<NakedAttr>())
- B.addAttribute(llvm::Attribute::Naked);
-
- // OptimizeNone wins over OptimizeForSize and MinSize.
- F->removeFnAttr(llvm::Attribute::OptimizeForSize);
- F->removeFnAttr(llvm::Attribute::MinSize);
- } else if (D->hasAttr<NakedAttr>()) {
- // Naked implies noinline: we should not be inlining such functions.
- B.addAttribute(llvm::Attribute::Naked);
- B.addAttribute(llvm::Attribute::NoInline);
- } else if (D->hasAttr<NoDuplicateAttr>()) {
- B.addAttribute(llvm::Attribute::NoDuplicate);
- } else if (D->hasAttr<NoInlineAttr>()) {
- B.addAttribute(llvm::Attribute::NoInline);
- } else if (D->hasAttr<AlwaysInlineAttr>() &&
- !F->hasFnAttribute(llvm::Attribute::NoInline)) {
- // (noinline wins over always_inline, and we can't specify both in IR)
- B.addAttribute(llvm::Attribute::AlwaysInline);
- } else if (CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {
- // If we're not inlining, then force everything that isn't always_inline to
- // carry an explicit noinline attribute.
- if (!F->hasFnAttribute(llvm::Attribute::AlwaysInline))
- B.addAttribute(llvm::Attribute::NoInline);
- } else {
- // Otherwise, propagate the inline hint attribute and potentially use its
- // absence to mark things as noinline.
- if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- // Search function and template pattern redeclarations for inline.
- auto CheckForInline = [](const FunctionDecl *FD) {
- auto CheckRedeclForInline = [](const FunctionDecl *Redecl) {
- return Redecl->isInlineSpecified();
- };
- if (any_of(FD->redecls(), CheckRedeclForInline))
- return true;
- const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern();
- if (!Pattern)
- return false;
- return any_of(Pattern->redecls(), CheckRedeclForInline);
- };
- if (CheckForInline(FD)) {
- B.addAttribute(llvm::Attribute::InlineHint);
- } else if (CodeGenOpts.getInlining() ==
- CodeGenOptions::OnlyHintInlining &&
- !FD->isInlined() &&
- !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
- B.addAttribute(llvm::Attribute::NoInline);
- }
- }
- }
-
- // Add other optimization related attributes if we are optimizing this
- // function.
- if (!D->hasAttr<OptimizeNoneAttr>()) {
- if (D->hasAttr<ColdAttr>()) {
- if (!ShouldAddOptNone)
- B.addAttribute(llvm::Attribute::OptimizeForSize);
- B.addAttribute(llvm::Attribute::Cold);
- }
-
- if (D->hasAttr<MinSizeAttr>())
- B.addAttribute(llvm::Attribute::MinSize);
- }
-
- F->addAttributes(llvm::AttributeList::FunctionIndex, B);
-
- unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
- if (alignment)
- F->setAlignment(alignment);
-
- if (!D->hasAttr<AlignedAttr>())
- if (LangOpts.FunctionAlignment)
- F->setAlignment(1 << LangOpts.FunctionAlignment);
-
- // Some C++ ABIs require 2-byte alignment for member functions, in order to
- // reserve a bit for differentiating between virtual and non-virtual member
- // functions. If the current target's C++ ABI requires this and this is a
- // member function, set its alignment accordingly.
- if (getTarget().getCXXABI().areMemberFunctionsAligned()) {
- if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
- F->setAlignment(2);
- }
-
- // In the cross-dso CFI mode, we want !type attributes on definitions only.
- if (CodeGenOpts.SanitizeCfiCrossDso)
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- CreateFunctionTypeMetadataForIcall(FD, F);
-
- // Emit type metadata on member functions for member function pointer checks.
- // These are only ever necessary on definitions; we're guaranteed that the
- // definition will be present in the LTO unit as a result of LTO visibility.
- auto *MD = dyn_cast<CXXMethodDecl>(D);
- if (MD && requiresMemberFunctionPointerTypeMetadata(*this, MD)) {
- for (const CXXRecordDecl *Base : getMostBaseClasses(MD->getParent())) {
- llvm::Metadata *Id =
- CreateMetadataIdentifierForType(Context.getMemberPointerType(
- MD->getType(), Context.getRecordType(Base).getTypePtr()));
- F->addTypeMetadata(0, Id);
- }
- }
-}
-
-void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) {
- const Decl *D = GD.getDecl();
- if (dyn_cast_or_null<NamedDecl>(D))
- setGVProperties(GV, GD);
- else
- GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
-
- if (D && D->hasAttr<UsedAttr>())
- addUsedGlobal(GV);
-
- if (CodeGenOpts.KeepStaticConsts && D && isa<VarDecl>(D)) {
- const auto *VD = cast<VarDecl>(D);
- if (VD->getType().isConstQualified() &&
- VD->getStorageDuration() == SD_Static)
- addUsedGlobal(GV);
- }
-}
-
-bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
- llvm::AttrBuilder &Attrs) {
- // Add target-cpu and target-features attributes to functions. If
- // we have a decl for the function and it has a target attribute then
- // parse that and add it to the feature set.
- StringRef TargetCPU = getTarget().getTargetOpts().CPU;
- std::vector<std::string> Features;
- const auto *FD = dyn_cast_or_null<FunctionDecl>(GD.getDecl());
- FD = FD ? FD->getMostRecentDecl() : FD;
- const auto *TD = FD ? FD->getAttr<TargetAttr>() : nullptr;
- const auto *SD = FD ? FD->getAttr<CPUSpecificAttr>() : nullptr;
- bool AddedAttr = false;
- if (TD || SD) {
- llvm::StringMap<bool> FeatureMap;
- getFunctionFeatureMap(FeatureMap, GD);
-
- // Produce the canonical string for this set of features.
- for (const llvm::StringMap<bool>::value_type &Entry : FeatureMap)
- Features.push_back((Entry.getValue() ? "+" : "-") + Entry.getKey().str());
-
- // Now add the target-cpu and target-features to the function.
- // While we populated the feature map above, we still need to
- // get and parse the target attribute so we can get the cpu for
- // the function.
- if (TD) {
- TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
- if (ParsedAttr.Architecture != "" &&
- getTarget().isValidCPUName(ParsedAttr.Architecture))
- TargetCPU = ParsedAttr.Architecture;
- }
- } else {
- // Otherwise just add the existing target cpu and target features to the
- // function.
- Features = getTarget().getTargetOpts().Features;
- }
-
- if (TargetCPU != "") {
- Attrs.addAttribute("target-cpu", TargetCPU);
- AddedAttr = true;
- }
- if (!Features.empty()) {
- llvm::sort(Features);
- Attrs.addAttribute("target-features", llvm::join(Features, ","));
- AddedAttr = true;
- }
-
- return AddedAttr;
-}
-
-void CodeGenModule::setNonAliasAttributes(GlobalDecl GD,
- llvm::GlobalObject *GO) {
- const Decl *D = GD.getDecl();
- SetCommonAttributes(GD, GO);
-
- if (D) {
- if (auto *GV = dyn_cast<llvm::GlobalVariable>(GO)) {
- if (auto *SA = D->getAttr<PragmaClangBSSSectionAttr>())
- GV->addAttribute("bss-section", SA->getName());
- if (auto *SA = D->getAttr<PragmaClangDataSectionAttr>())
- GV->addAttribute("data-section", SA->getName());
- if (auto *SA = D->getAttr<PragmaClangRodataSectionAttr>())
- GV->addAttribute("rodata-section", SA->getName());
- }
-
- if (auto *F = dyn_cast<llvm::Function>(GO)) {
- if (auto *SA = D->getAttr<PragmaClangTextSectionAttr>())
- if (!D->getAttr<SectionAttr>())
- F->addFnAttr("implicit-section-name", SA->getName());
-
- llvm::AttrBuilder Attrs;
- if (GetCPUAndFeaturesAttributes(GD, Attrs)) {
- // We know that GetCPUAndFeaturesAttributes will always have the
- // newest set, since it has the newest possible FunctionDecl, so the
- // new ones should replace the old.
- F->removeFnAttr("target-cpu");
- F->removeFnAttr("target-features");
- F->addAttributes(llvm::AttributeList::FunctionIndex, Attrs);
- }
- }
-
- if (const auto *CSA = D->getAttr<CodeSegAttr>())
- GO->setSection(CSA->getName());
- else if (const auto *SA = D->getAttr<SectionAttr>())
- GO->setSection(SA->getName());
- }
-
- getTargetCodeGenInfo().setTargetAttributes(D, GO, *this);
-}
-
-void CodeGenModule::SetInternalFunctionAttributes(GlobalDecl GD,
- llvm::Function *F,
- const CGFunctionInfo &FI) {
- const Decl *D = GD.getDecl();
- SetLLVMFunctionAttributes(GD, FI, F);
- SetLLVMFunctionAttributesForDefinition(D, F);
-
- F->setLinkage(llvm::Function::InternalLinkage);
-
- setNonAliasAttributes(GD, F);
-}
-
-static void setLinkageForGV(llvm::GlobalValue *GV, const NamedDecl *ND) {
- // Set linkage and visibility in case we never see a definition.
- LinkageInfo LV = ND->getLinkageAndVisibility();
- // Don't set internal linkage on declarations.
- // "extern_weak" is overloaded in LLVM; we probably should have
- // separate linkage types for this.
- if (isExternallyVisible(LV.getLinkage()) &&
- (ND->hasAttr<WeakAttr>() || ND->isWeakImported()))
- GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
-}
-
-void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
- llvm::Function *F) {
- // Only if we are checking indirect calls.
- if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
- return;
-
- // Non-static class methods are handled via vtable or member function pointer
- // checks elsewhere.
- if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
- return;
-
- // Additionally, if building with cross-DSO support...
- if (CodeGenOpts.SanitizeCfiCrossDso) {
- // Skip available_externally functions. They won't be codegen'ed in the
- // current module anyway.
- if (getContext().GetGVALinkageForFunction(FD) == GVA_AvailableExternally)
- return;
- }
-
- llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
- F->addTypeMetadata(0, MD);
- F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
-
- // Emit a hash-based bit set entry for cross-DSO calls.
- if (CodeGenOpts.SanitizeCfiCrossDso)
- if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
- F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
-}
-
-void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
- bool IsIncompleteFunction,
- bool IsThunk) {
-
- if (llvm::Intrinsic::ID IID = F->getIntrinsicID()) {
- // If this is an intrinsic function, set the function's attributes
- // to the intrinsic's attributes.
- F->setAttributes(llvm::Intrinsic::getAttributes(getLLVMContext(), IID));
- return;
- }
-
- const auto *FD = cast<FunctionDecl>(GD.getDecl());
-
- if (!IsIncompleteFunction) {
- SetLLVMFunctionAttributes(GD, getTypes().arrangeGlobalDeclaration(GD), F);
- // Setup target-specific attributes.
- if (F->isDeclaration())
- getTargetCodeGenInfo().setTargetAttributes(FD, F, *this);
- }
-
- // Add the Returned attribute for "this", except for iOS 5 and earlier
- // where substantial code, including the libstdc++ dylib, was compiled with
- // GCC and does not actually return "this".
- if (!IsThunk && getCXXABI().HasThisReturn(GD) &&
- !(getTriple().isiOS() && getTriple().isOSVersionLT(6))) {
- assert(!F->arg_empty() &&
- F->arg_begin()->getType()
- ->canLosslesslyBitCastTo(F->getReturnType()) &&
- "unexpected this return");
- F->addAttribute(1, llvm::Attribute::Returned);
- }
-
- // Only a few attributes are set on declarations; these may later be
- // overridden by a definition.
-
- setLinkageForGV(F, FD);
- setGVProperties(F, FD);
-
- if (const auto *CSA = FD->getAttr<CodeSegAttr>())
- F->setSection(CSA->getName());
- else if (const auto *SA = FD->getAttr<SectionAttr>())
- F->setSection(SA->getName());
-
- if (FD->isReplaceableGlobalAllocationFunction()) {
- // A replaceable global allocation function does not act like a builtin by
- // default, only if it is invoked by a new-expression or delete-expression.
- F->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoBuiltin);
-
- // A sane operator new returns a non-aliasing pointer.
- // FIXME: Also add NonNull attribute to the return value
- // for the non-nothrow forms?
- auto Kind = FD->getDeclName().getCXXOverloadedOperator();
- if (getCodeGenOpts().AssumeSaneOperatorNew &&
- (Kind == OO_New || Kind == OO_Array_New))
- F->addAttribute(llvm::AttributeList::ReturnIndex,
- llvm::Attribute::NoAlias);
- }
-
- if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD))
- F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- else if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
- if (MD->isVirtual())
- F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- // Don't emit entries for function declarations in the cross-DSO mode. This
- // is handled with better precision by the receiving DSO.
- if (!CodeGenOpts.SanitizeCfiCrossDso)
- CreateFunctionTypeMetadataForIcall(FD, F);
-
- if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
- getOpenMPRuntime().emitDeclareSimdFunction(FD, F);
-}
-
-void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
- assert(!GV->isDeclaration() &&
- "Only globals with definition can force usage.");
- LLVMUsed.emplace_back(GV);
-}
-
-void CodeGenModule::addCompilerUsedGlobal(llvm::GlobalValue *GV) {
- assert(!GV->isDeclaration() &&
- "Only globals with definition can force usage.");
- LLVMCompilerUsed.emplace_back(GV);
-}
-
-static void emitUsed(CodeGenModule &CGM, StringRef Name,
- std::vector<llvm::WeakTrackingVH> &List) {
- // Don't create llvm.used if there is no need.
- if (List.empty())
- return;
-
- // Convert List to what ConstantArray needs.
- SmallVector<llvm::Constant*, 8> UsedArray;
- UsedArray.resize(List.size());
- for (unsigned i = 0, e = List.size(); i != e; ++i) {
- UsedArray[i] =
- llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
- cast<llvm::Constant>(&*List[i]), CGM.Int8PtrTy);
- }
-
- if (UsedArray.empty())
- return;
- llvm::ArrayType *ATy = llvm::ArrayType::get(CGM.Int8PtrTy, UsedArray.size());
-
- auto *GV = new llvm::GlobalVariable(
- CGM.getModule(), ATy, false, llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(ATy, UsedArray), Name);
-
- GV->setSection("llvm.metadata");
-}
-
-void CodeGenModule::emitLLVMUsed() {
- emitUsed(*this, "llvm.used", LLVMUsed);
- emitUsed(*this, "llvm.compiler.used", LLVMCompilerUsed);
-}
-
-void CodeGenModule::AppendLinkerOptions(StringRef Opts) {
- auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opts);
- LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
-}
-
-void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) {
- llvm::SmallString<32> Opt;
- getTargetCodeGenInfo().getDetectMismatchOption(Name, Value, Opt);
- auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
- LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
-}
-
-void CodeGenModule::AddELFLibDirective(StringRef Lib) {
- auto &C = getLLVMContext();
- LinkerOptionsMetadata.push_back(llvm::MDNode::get(
- C, {llvm::MDString::get(C, "lib"), llvm::MDString::get(C, Lib)}));
-}
-
-void CodeGenModule::AddDependentLib(StringRef Lib) {
- llvm::SmallString<24> Opt;
- getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt);
- auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
- LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
-}
-
-/// Add link options implied by the given module, including modules
-/// it depends on, using a postorder walk.
-static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
- SmallVectorImpl<llvm::MDNode *> &Metadata,
- llvm::SmallPtrSet<Module *, 16> &Visited) {
- // Import this module's parent.
- if (Mod->Parent && Visited.insert(Mod->Parent).second) {
- addLinkOptionsPostorder(CGM, Mod->Parent, Metadata, Visited);
- }
-
- // Import this module's dependencies.
- for (unsigned I = Mod->Imports.size(); I > 0; --I) {
- if (Visited.insert(Mod->Imports[I - 1]).second)
- addLinkOptionsPostorder(CGM, Mod->Imports[I-1], Metadata, Visited);
- }
-
- // Add linker options to link against the libraries/frameworks
- // described by this module.
- llvm::LLVMContext &Context = CGM.getLLVMContext();
- bool IsELF = CGM.getTarget().getTriple().isOSBinFormatELF();
- bool IsPS4 = CGM.getTarget().getTriple().isPS4();
-
- // For modules that use export_as for linking, use that module
- // name instead.
- if (Mod->UseExportAsModuleLinkName)
- return;
-
- for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) {
- // Link against a framework. Frameworks are currently Darwin only, so we
- // don't to ask TargetCodeGenInfo for the spelling of the linker option.
- if (Mod->LinkLibraries[I-1].IsFramework) {
- llvm::Metadata *Args[2] = {
- llvm::MDString::get(Context, "-framework"),
- llvm::MDString::get(Context, Mod->LinkLibraries[I - 1].Library)};
-
- Metadata.push_back(llvm::MDNode::get(Context, Args));
- continue;
- }
-
- // Link against a library.
- if (IsELF && !IsPS4) {
- llvm::Metadata *Args[2] = {
- llvm::MDString::get(Context, "lib"),
- llvm::MDString::get(Context, Mod->LinkLibraries[I - 1].Library),
- };
- Metadata.push_back(llvm::MDNode::get(Context, Args));
- } else {
- llvm::SmallString<24> Opt;
- CGM.getTargetCodeGenInfo().getDependentLibraryOption(
- Mod->LinkLibraries[I - 1].Library, Opt);
- auto *OptString = llvm::MDString::get(Context, Opt);
- Metadata.push_back(llvm::MDNode::get(Context, OptString));
- }
- }
-}
-
-void CodeGenModule::EmitModuleLinkOptions() {
- // Collect the set of all of the modules we want to visit to emit link
- // options, which is essentially the imported modules and all of their
- // non-explicit child modules.
- llvm::SetVector<clang::Module *> LinkModules;
- llvm::SmallPtrSet<clang::Module *, 16> Visited;
- SmallVector<clang::Module *, 16> Stack;
-
- // Seed the stack with imported modules.
- for (Module *M : ImportedModules) {
- // Do not add any link flags when an implementation TU of a module imports
- // a header of that same module.
- if (M->getTopLevelModuleName() == getLangOpts().CurrentModule &&
- !getLangOpts().isCompilingModule())
- continue;
- if (Visited.insert(M).second)
- Stack.push_back(M);
- }
-
- // Find all of the modules to import, making a little effort to prune
- // non-leaf modules.
- while (!Stack.empty()) {
- clang::Module *Mod = Stack.pop_back_val();
-
- bool AnyChildren = false;
-
- // Visit the submodules of this module.
- for (const auto &SM : Mod->submodules()) {
- // Skip explicit children; they need to be explicitly imported to be
- // linked against.
- if (SM->IsExplicit)
- continue;
-
- if (Visited.insert(SM).second) {
- Stack.push_back(SM);
- AnyChildren = true;
- }
- }
-
- // We didn't find any children, so add this module to the list of
- // modules to link against.
- if (!AnyChildren) {
- LinkModules.insert(Mod);
- }
- }
-
- // Add link options for all of the imported modules in reverse topological
- // order. We don't do anything to try to order import link flags with respect
- // to linker options inserted by things like #pragma comment().
- SmallVector<llvm::MDNode *, 16> MetadataArgs;
- Visited.clear();
- for (Module *M : LinkModules)
- if (Visited.insert(M).second)
- addLinkOptionsPostorder(*this, M, MetadataArgs, Visited);
- std::reverse(MetadataArgs.begin(), MetadataArgs.end());
- LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end());
-
- // Add the linker options metadata flag.
- auto *NMD = getModule().getOrInsertNamedMetadata("llvm.linker.options");
- for (auto *MD : LinkerOptionsMetadata)
- NMD->addOperand(MD);
-}
-
-void CodeGenModule::EmitDeferred() {
- // Emit deferred declare target declarations.
- if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd)
- getOpenMPRuntime().emitDeferredTargetDecls();
-
- // Emit code for any potentially referenced deferred decls. Since a
- // previously unused static decl may become used during the generation of code
- // for a static function, iterate until no changes are made.
-
- if (!DeferredVTables.empty()) {
- EmitDeferredVTables();
-
- // Emitting a vtable doesn't directly cause more vtables to
- // become deferred, although it can cause functions to be
- // emitted that then need those vtables.
- assert(DeferredVTables.empty());
- }
-
- // Stop if we're out of both deferred vtables and deferred declarations.
- if (DeferredDeclsToEmit.empty())
- return;
-
- // Grab the list of decls to emit. If EmitGlobalDefinition schedules more
- // work, it will not interfere with this.
- std::vector<GlobalDecl> CurDeclsToEmit;
- CurDeclsToEmit.swap(DeferredDeclsToEmit);
-
- for (GlobalDecl &D : CurDeclsToEmit) {
- // We should call GetAddrOfGlobal with IsForDefinition set to true in order
- // to get GlobalValue with exactly the type we need, not something that
- // might had been created for another decl with the same mangled name but
- // different type.
- llvm::GlobalValue *GV = dyn_cast<llvm::GlobalValue>(
- GetAddrOfGlobal(D, ForDefinition));
-
- // In case of different address spaces, we may still get a cast, even with
- // IsForDefinition equal to true. Query mangled names table to get
- // GlobalValue.
- if (!GV)
- GV = GetGlobalValue(getMangledName(D));
-
- // Make sure GetGlobalValue returned non-null.
- assert(GV);
-
- // Check to see if we've already emitted this. This is necessary
- // for a couple of reasons: first, decls can end up in the
- // deferred-decls queue multiple times, and second, decls can end
- // up with definitions in unusual ways (e.g. by an extern inline
- // function acquiring a strong function redefinition). Just
- // ignore these cases.
- if (!GV->isDeclaration())
- continue;
-
- // Otherwise, emit the definition and move on to the next one.
- EmitGlobalDefinition(D, GV);
-
- // If we found out that we need to emit more decls, do that recursively.
- // This has the advantage that the decls are emitted in a DFS and related
- // ones are close together, which is convenient for testing.
- if (!DeferredVTables.empty() || !DeferredDeclsToEmit.empty()) {
- EmitDeferred();
- assert(DeferredVTables.empty() && DeferredDeclsToEmit.empty());
- }
- }
-}
-
-void CodeGenModule::EmitVTablesOpportunistically() {
- // Try to emit external vtables as available_externally if they have emitted
- // all inlined virtual functions. It runs after EmitDeferred() and therefore
- // is not allowed to create new references to things that need to be emitted
- // lazily. Note that it also uses fact that we eagerly emitting RTTI.
-
- assert((OpportunisticVTables.empty() || shouldOpportunisticallyEmitVTables())
- && "Only emit opportunistic vtables with optimizations");
-
- for (const CXXRecordDecl *RD : OpportunisticVTables) {
- assert(getVTables().isVTableExternal(RD) &&
- "This queue should only contain external vtables");
- if (getCXXABI().canSpeculativelyEmitVTable(RD))
- VTables.GenerateClassData(RD);
- }
- OpportunisticVTables.clear();
-}
-
-void CodeGenModule::EmitGlobalAnnotations() {
- if (Annotations.empty())
- return;
-
- // Create a new global variable for the ConstantStruct in the Module.
- llvm::Constant *Array = llvm::ConstantArray::get(llvm::ArrayType::get(
- Annotations[0]->getType(), Annotations.size()), Annotations);
- auto *gv = new llvm::GlobalVariable(getModule(), Array->getType(), false,
- llvm::GlobalValue::AppendingLinkage,
- Array, "llvm.global.annotations");
- gv->setSection(AnnotationSection);
-}
-
-llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) {
- llvm::Constant *&AStr = AnnotationStrings[Str];
- if (AStr)
- return AStr;
-
- // Not found yet, create a new global.
- llvm::Constant *s = llvm::ConstantDataArray::getString(getLLVMContext(), Str);
- auto *gv =
- new llvm::GlobalVariable(getModule(), s->getType(), true,
- llvm::GlobalValue::PrivateLinkage, s, ".str");
- gv->setSection(AnnotationSection);
- gv->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- AStr = gv;
- return gv;
-}
-
-llvm::Constant *CodeGenModule::EmitAnnotationUnit(SourceLocation Loc) {
- SourceManager &SM = getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
- if (PLoc.isValid())
- return EmitAnnotationString(PLoc.getFilename());
- return EmitAnnotationString(SM.getBufferName(Loc));
-}
-
-llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) {
- SourceManager &SM = getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(L);
- unsigned LineNo = PLoc.isValid() ? PLoc.getLine() :
- SM.getExpansionLineNumber(L);
- return llvm::ConstantInt::get(Int32Ty, LineNo);
-}
-
-llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV,
- const AnnotateAttr *AA,
- SourceLocation L) {
- // Get the globals for file name, annotation, and the line number.
- llvm::Constant *AnnoGV = EmitAnnotationString(AA->getAnnotation()),
- *UnitGV = EmitAnnotationUnit(L),
- *LineNoCst = EmitAnnotationLineNo(L);
-
- // Create the ConstantStruct for the global annotation.
- llvm::Constant *Fields[4] = {
- llvm::ConstantExpr::getBitCast(GV, Int8PtrTy),
- llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy),
- llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy),
- LineNoCst
- };
- return llvm::ConstantStruct::getAnon(Fields);
-}
-
-void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
- llvm::GlobalValue *GV) {
- assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
- // Get the struct elements for these annotations.
- for (const auto *I : D->specific_attrs<AnnotateAttr>())
- Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
-}
-
-bool CodeGenModule::isInSanitizerBlacklist(SanitizerMask Kind,
- llvm::Function *Fn,
- SourceLocation Loc) const {
- const auto &SanitizerBL = getContext().getSanitizerBlacklist();
- // Blacklist by function name.
- if (SanitizerBL.isBlacklistedFunction(Kind, Fn->getName()))
- return true;
- // Blacklist by location.
- if (Loc.isValid())
- return SanitizerBL.isBlacklistedLocation(Kind, Loc);
- // If location is unknown, this may be a compiler-generated function. Assume
- // it's located in the main file.
- auto &SM = Context.getSourceManager();
- if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- return SanitizerBL.isBlacklistedFile(Kind, MainFile->getName());
- }
- return false;
-}
-
-bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
- SourceLocation Loc, QualType Ty,
- StringRef Category) const {
- // For now globals can be blacklisted only in ASan and KASan.
- const SanitizerMask EnabledAsanMask = LangOpts.Sanitize.Mask &
- (SanitizerKind::Address | SanitizerKind::KernelAddress |
- SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress);
- if (!EnabledAsanMask)
- return false;
- const auto &SanitizerBL = getContext().getSanitizerBlacklist();
- if (SanitizerBL.isBlacklistedGlobal(EnabledAsanMask, GV->getName(), Category))
- return true;
- if (SanitizerBL.isBlacklistedLocation(EnabledAsanMask, Loc, Category))
- return true;
- // Check global type.
- if (!Ty.isNull()) {
- // Drill down the array types: if global variable of a fixed type is
- // blacklisted, we also don't instrument arrays of them.
- while (auto AT = dyn_cast<ArrayType>(Ty.getTypePtr()))
- Ty = AT->getElementType();
- Ty = Ty.getCanonicalType().getUnqualifiedType();
- // We allow to blacklist only record types (classes, structs etc.)
- if (Ty->isRecordType()) {
- std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy());
- if (SanitizerBL.isBlacklistedType(EnabledAsanMask, TypeStr, Category))
- return true;
- }
- }
- return false;
-}
-
-bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
- StringRef Category) const {
- const auto &XRayFilter = getContext().getXRayFilter();
- using ImbueAttr = XRayFunctionFilter::ImbueAttribute;
- auto Attr = ImbueAttr::NONE;
- if (Loc.isValid())
- Attr = XRayFilter.shouldImbueLocation(Loc, Category);
- if (Attr == ImbueAttr::NONE)
- Attr = XRayFilter.shouldImbueFunction(Fn->getName());
- switch (Attr) {
- case ImbueAttr::NONE:
- return false;
- case ImbueAttr::ALWAYS:
- Fn->addFnAttr("function-instrument", "xray-always");
- break;
- case ImbueAttr::ALWAYS_ARG1:
- Fn->addFnAttr("function-instrument", "xray-always");
- Fn->addFnAttr("xray-log-args", "1");
- break;
- case ImbueAttr::NEVER:
- Fn->addFnAttr("function-instrument", "xray-never");
- break;
- }
- return true;
-}
-
-bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
- // Never defer when EmitAllDecls is specified.
- if (LangOpts.EmitAllDecls)
- return true;
-
- if (CodeGenOpts.KeepStaticConsts) {
- const auto *VD = dyn_cast<VarDecl>(Global);
- if (VD && VD->getType().isConstQualified() &&
- VD->getStorageDuration() == SD_Static)
- return true;
- }
-
- return getContext().DeclMustBeEmitted(Global);
-}
-
-bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
- if (const auto *FD = dyn_cast<FunctionDecl>(Global))
- if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- // Implicit template instantiations may change linkage if they are later
- // explicitly instantiated, so they should not be emitted eagerly.
- return false;
- if (const auto *VD = dyn_cast<VarDecl>(Global))
- if (Context.getInlineVariableDefinitionKind(VD) ==
- ASTContext::InlineVariableDefinitionKind::WeakUnknown)
- // A definition of an inline constexpr static data member may change
- // linkage later if it's redeclared outside the class.
- return false;
- // If OpenMP is enabled and threadprivates must be generated like TLS, delay
- // codegen for global variables, because they may be marked as threadprivate.
- if (LangOpts.OpenMP && LangOpts.OpenMPUseTLS &&
- getContext().getTargetInfo().isTLSSupported() && isa<VarDecl>(Global) &&
- !isTypeConstant(Global->getType(), false) &&
- !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Global))
- return false;
-
- return true;
-}
-
-ConstantAddress CodeGenModule::GetAddrOfUuidDescriptor(
- const CXXUuidofExpr* E) {
- // Sema has verified that IIDSource has a __declspec(uuid()), and that its
- // well-formed.
- StringRef Uuid = E->getUuidStr();
- std::string Name = "_GUID_" + Uuid.lower();
- std::replace(Name.begin(), Name.end(), '-', '_');
-
- // The UUID descriptor should be pointer aligned.
- CharUnits Alignment = CharUnits::fromQuantity(PointerAlignInBytes);
-
- // Look for an existing global.
- if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name))
- return ConstantAddress(GV, Alignment);
-
- llvm::Constant *Init = EmitUuidofInitializer(Uuid);
- assert(Init && "failed to initialize as constant");
-
- auto *GV = new llvm::GlobalVariable(
- getModule(), Init->getType(),
- /*isConstant=*/true, llvm::GlobalValue::LinkOnceODRLinkage, Init, Name);
- if (supportsCOMDAT())
- GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
- setDSOLocal(GV);
- return ConstantAddress(GV, Alignment);
-}
-
-ConstantAddress CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
- const AliasAttr *AA = VD->getAttr<AliasAttr>();
- assert(AA && "No alias?");
-
- CharUnits Alignment = getContext().getDeclAlign(VD);
- llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType());
-
- // See if there is already something with the target's name in the module.
- llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee());
- if (Entry) {
- unsigned AS = getContext().getTargetAddressSpace(VD->getType());
- auto Ptr = llvm::ConstantExpr::getBitCast(Entry, DeclTy->getPointerTo(AS));
- return ConstantAddress(Ptr, Alignment);
- }
-
- llvm::Constant *Aliasee;
- if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy,
- GlobalDecl(cast<FunctionDecl>(VD)),
- /*ForVTable=*/false);
- else
- Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
- llvm::PointerType::getUnqual(DeclTy),
- nullptr);
-
- auto *F = cast<llvm::GlobalValue>(Aliasee);
- F->setLinkage(llvm::Function::ExternalWeakLinkage);
- WeakRefReferences.insert(F);
-
- return ConstantAddress(Aliasee, Alignment);
-}
-
-void CodeGenModule::EmitGlobal(GlobalDecl GD) {
- const auto *Global = cast<ValueDecl>(GD.getDecl());
-
- // Weak references don't produce any output by themselves.
- if (Global->hasAttr<WeakRefAttr>())
- return;
-
- // If this is an alias definition (which otherwise looks like a declaration)
- // emit it now.
- if (Global->hasAttr<AliasAttr>())
- return EmitAliasDefinition(GD);
-
- // IFunc like an alias whose value is resolved at runtime by calling resolver.
- if (Global->hasAttr<IFuncAttr>())
- return emitIFuncDefinition(GD);
-
- // If this is a cpu_dispatch multiversion function, emit the resolver.
- if (Global->hasAttr<CPUDispatchAttr>())
- return emitCPUDispatchDefinition(GD);
-
- // If this is CUDA, be selective about which declarations we emit.
- if (LangOpts.CUDA) {
- if (LangOpts.CUDAIsDevice) {
- if (!Global->hasAttr<CUDADeviceAttr>() &&
- !Global->hasAttr<CUDAGlobalAttr>() &&
- !Global->hasAttr<CUDAConstantAttr>() &&
- !Global->hasAttr<CUDASharedAttr>())
- return;
- } else {
- // We need to emit host-side 'shadows' for all global
- // device-side variables because the CUDA runtime needs their
- // size and host-side address in order to provide access to
- // their device-side incarnations.
-
- // So device-only functions are the only things we skip.
- if (isa<FunctionDecl>(Global) && !Global->hasAttr<CUDAHostAttr>() &&
- Global->hasAttr<CUDADeviceAttr>())
- return;
-
- assert((isa<FunctionDecl>(Global) || isa<VarDecl>(Global)) &&
- "Expected Variable or Function");
- }
- }
-
- if (LangOpts.OpenMP) {
- // If this is OpenMP device, check if it is legal to emit this global
- // normally.
- if (OpenMPRuntime && OpenMPRuntime->emitTargetGlobal(GD))
- return;
- if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Global)) {
- if (MustBeEmitted(Global))
- EmitOMPDeclareReduction(DRD);
- return;
- }
- }
-
- // Ignore declarations, they will be emitted on their first use.
- if (const auto *FD = dyn_cast<FunctionDecl>(Global)) {
- // Forward declarations are emitted lazily on first use.
- if (!FD->doesThisDeclarationHaveABody()) {
- if (!FD->doesDeclarationForceExternallyVisibleDefinition())
- return;
-
- StringRef MangledName = getMangledName(GD);
-
- // Compute the function info and LLVM type.
- const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
- llvm::Type *Ty = getTypes().GetFunctionType(FI);
-
- GetOrCreateLLVMFunction(MangledName, Ty, GD, /*ForVTable=*/false,
- /*DontDefer=*/false);
- return;
- }
- } else {
- const auto *VD = cast<VarDecl>(Global);
- assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- if (VD->isThisDeclarationADefinition() != VarDecl::Definition &&
- !Context.isMSStaticDataMemberInlineDefinition(VD)) {
- if (LangOpts.OpenMP) {
- // Emit declaration of the must-be-emitted declare target variable.
- if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
- if (*Res == OMPDeclareTargetDeclAttr::MT_To) {
- (void)GetAddrOfGlobalVar(VD);
- } else {
- assert(*Res == OMPDeclareTargetDeclAttr::MT_Link &&
- "link claue expected.");
- (void)getOpenMPRuntime().getAddrOfDeclareTargetLink(VD);
- }
- return;
- }
- }
- // If this declaration may have caused an inline variable definition to
- // change linkage, make sure that it's emitted.
- if (Context.getInlineVariableDefinitionKind(VD) ==
- ASTContext::InlineVariableDefinitionKind::Strong)
- GetAddrOfGlobalVar(VD);
- return;
- }
- }
-
- // Defer code generation to first use when possible, e.g. if this is an inline
- // function. If the global must always be emitted, do it eagerly if possible
- // to benefit from cache locality.
- if (MustBeEmitted(Global) && MayBeEmittedEagerly(Global)) {
- // Emit the definition if it can't be deferred.
- EmitGlobalDefinition(GD);
- return;
- }
-
- // If we're deferring emission of a C++ variable with an
- // initializer, remember the order in which it appeared in the file.
- if (getLangOpts().CPlusPlus && isa<VarDecl>(Global) &&
- cast<VarDecl>(Global)->hasInit()) {
- DelayedCXXInitPosition[Global] = CXXGlobalInits.size();
- CXXGlobalInits.push_back(nullptr);
- }
-
- StringRef MangledName = getMangledName(GD);
- if (GetGlobalValue(MangledName) != nullptr) {
- // The value has already been used and should therefore be emitted.
- addDeferredDeclToEmit(GD);
- } else if (MustBeEmitted(Global)) {
- // The value must be emitted, but cannot be emitted eagerly.
- assert(!MayBeEmittedEagerly(Global));
- addDeferredDeclToEmit(GD);
- } else {
- // Otherwise, remember that we saw a deferred decl with this name. The
- // first use of the mangled name will cause it to move into
- // DeferredDeclsToEmit.
- DeferredDecls[MangledName] = GD;
- }
-}
-
-// Check if T is a class type with a destructor that's not dllimport.
-static bool HasNonDllImportDtor(QualType T) {
- if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>())
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- if (RD->getDestructor() && !RD->getDestructor()->hasAttr<DLLImportAttr>())
- return true;
-
- return false;
-}
-
-namespace {
- struct FunctionIsDirectlyRecursive :
- public RecursiveASTVisitor<FunctionIsDirectlyRecursive> {
- const StringRef Name;
- const Builtin::Context &BI;
- bool Result;
- FunctionIsDirectlyRecursive(StringRef N, const Builtin::Context &C) :
- Name(N), BI(C), Result(false) {
- }
- typedef RecursiveASTVisitor<FunctionIsDirectlyRecursive> Base;
-
- bool TraverseCallExpr(CallExpr *E) {
- const FunctionDecl *FD = E->getDirectCallee();
- if (!FD)
- return true;
- AsmLabelAttr *Attr = FD->getAttr<AsmLabelAttr>();
- if (Attr && Name == Attr->getLabel()) {
- Result = true;
- return false;
- }
- unsigned BuiltinID = FD->getBuiltinID();
- if (!BuiltinID || !BI.isLibFunction(BuiltinID))
- return true;
- StringRef BuiltinName = BI.getName(BuiltinID);
- if (BuiltinName.startswith("__builtin_") &&
- Name == BuiltinName.slice(strlen("__builtin_"), StringRef::npos)) {
- Result = true;
- return false;
- }
- return true;
- }
- };
-
- // Make sure we're not referencing non-imported vars or functions.
- struct DLLImportFunctionVisitor
- : public RecursiveASTVisitor<DLLImportFunctionVisitor> {
- bool SafeToInline = true;
-
- bool shouldVisitImplicitCode() const { return true; }
-
- bool VisitVarDecl(VarDecl *VD) {
- if (VD->getTLSKind()) {
- // A thread-local variable cannot be imported.
- SafeToInline = false;
- return SafeToInline;
- }
-
- // A variable definition might imply a destructor call.
- if (VD->isThisDeclarationADefinition())
- SafeToInline = !HasNonDllImportDtor(VD->getType());
-
- return SafeToInline;
- }
-
- bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
- if (const auto *D = E->getTemporary()->getDestructor())
- SafeToInline = D->hasAttr<DLLImportAttr>();
- return SafeToInline;
- }
-
- bool VisitDeclRefExpr(DeclRefExpr *E) {
- ValueDecl *VD = E->getDecl();
- if (isa<FunctionDecl>(VD))
- SafeToInline = VD->hasAttr<DLLImportAttr>();
- else if (VarDecl *V = dyn_cast<VarDecl>(VD))
- SafeToInline = !V->hasGlobalStorage() || V->hasAttr<DLLImportAttr>();
- return SafeToInline;
- }
-
- bool VisitCXXConstructExpr(CXXConstructExpr *E) {
- SafeToInline = E->getConstructor()->hasAttr<DLLImportAttr>();
- return SafeToInline;
- }
-
- bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
- CXXMethodDecl *M = E->getMethodDecl();
- if (!M) {
- // Call through a pointer to member function. This is safe to inline.
- SafeToInline = true;
- } else {
- SafeToInline = M->hasAttr<DLLImportAttr>();
- }
- return SafeToInline;
- }
-
- bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
- SafeToInline = E->getOperatorDelete()->hasAttr<DLLImportAttr>();
- return SafeToInline;
- }
-
- bool VisitCXXNewExpr(CXXNewExpr *E) {
- SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
- return SafeToInline;
- }
- };
-}
-
-// isTriviallyRecursive - Check if this function calls another
-// decl that, because of the asm attribute or the other decl being a builtin,
-// ends up pointing to itself.
-bool
-CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) {
- StringRef Name;
- if (getCXXABI().getMangleContext().shouldMangleDeclName(FD)) {
- // asm labels are a special kind of mangling we have to support.
- AsmLabelAttr *Attr = FD->getAttr<AsmLabelAttr>();
- if (!Attr)
- return false;
- Name = Attr->getLabel();
- } else {
- Name = FD->getName();
- }
-
- FunctionIsDirectlyRecursive Walker(Name, Context.BuiltinInfo);
- Walker.TraverseFunctionDecl(const_cast<FunctionDecl*>(FD));
- return Walker.Result;
-}
-
-bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
- if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
- return true;
- const auto *F = cast<FunctionDecl>(GD.getDecl());
- if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr<AlwaysInlineAttr>())
- return false;
-
- if (F->hasAttr<DLLImportAttr>()) {
- // Check whether it would be safe to inline this dllimport function.
- DLLImportFunctionVisitor Visitor;
- Visitor.TraverseFunctionDecl(const_cast<FunctionDecl*>(F));
- if (!Visitor.SafeToInline)
- return false;
-
- if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(F)) {
- // Implicit destructor invocations aren't captured in the AST, so the
- // check above can't see them. Check for them manually here.
- for (const Decl *Member : Dtor->getParent()->decls())
- if (isa<FieldDecl>(Member))
- if (HasNonDllImportDtor(cast<FieldDecl>(Member)->getType()))
- return false;
- for (const CXXBaseSpecifier &B : Dtor->getParent()->bases())
- if (HasNonDllImportDtor(B.getType()))
- return false;
- }
- }
-
- // PR9614. Avoid cases where the source code is lying to us. An available
- // externally function should have an equivalent function somewhere else,
- // but a function that calls itself is clearly not equivalent to the real
- // implementation.
- // This happens in glibc's btowc and in some configure checks.
- return !isTriviallyRecursive(F);
-}
-
-bool CodeGenModule::shouldOpportunisticallyEmitVTables() {
- return CodeGenOpts.OptimizationLevel > 0;
-}
-
-void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
- llvm::GlobalValue *GV) {
- const auto *FD = cast<FunctionDecl>(GD.getDecl());
-
- if (FD->isCPUSpecificMultiVersion()) {
- auto *Spec = FD->getAttr<CPUSpecificAttr>();
- for (unsigned I = 0; I < Spec->cpus_size(); ++I)
- EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
- // Requires multiple emits.
- } else
- EmitGlobalFunctionDefinition(GD, GV);
-}
-
-void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
- const auto *D = cast<ValueDecl>(GD.getDecl());
-
- PrettyStackTraceDecl CrashInfo(const_cast<ValueDecl *>(D), D->getLocation(),
- Context.getSourceManager(),
- "Generating code for declaration");
-
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- // At -O0, don't generate IR for functions with available_externally
- // linkage.
- if (!shouldEmitFunction(GD))
- return;
-
- if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) {
- // Make sure to emit the definition(s) before we emit the thunks.
- // This is necessary for the generation of certain thunks.
- if (const auto *CD = dyn_cast<CXXConstructorDecl>(Method))
- ABI->emitCXXStructor(CD, getFromCtorType(GD.getCtorType()));
- else if (const auto *DD = dyn_cast<CXXDestructorDecl>(Method))
- ABI->emitCXXStructor(DD, getFromDtorType(GD.getDtorType()));
- else if (FD->isMultiVersion())
- EmitMultiVersionFunctionDefinition(GD, GV);
- else
- EmitGlobalFunctionDefinition(GD, GV);
-
- if (Method->isVirtual())
- getVTables().EmitThunks(GD);
-
- return;
- }
-
- if (FD->isMultiVersion())
- return EmitMultiVersionFunctionDefinition(GD, GV);
- return EmitGlobalFunctionDefinition(GD, GV);
- }
-
- if (const auto *VD = dyn_cast<VarDecl>(D))
- return EmitGlobalVarDefinition(VD, !VD->hasDefinition());
-
- llvm_unreachable("Invalid argument to EmitGlobalDefinition()");
-}
-
-static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
- llvm::Function *NewFn);
-
-static unsigned
-TargetMVPriority(const TargetInfo &TI,
- const CodeGenFunction::MultiVersionResolverOption &RO) {
- unsigned Priority = 0;
- for (StringRef Feat : RO.Conditions.Features)
- Priority = std::max(Priority, TI.multiVersionSortPriority(Feat));
-
- if (!RO.Conditions.Architecture.empty())
- Priority = std::max(
- Priority, TI.multiVersionSortPriority(RO.Conditions.Architecture));
- return Priority;
-}
-
-void CodeGenModule::emitMultiVersionFunctions() {
- for (GlobalDecl GD : MultiVersionFuncs) {
- SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
- const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
- getContext().forEachMultiversionedFunctionVersion(
- FD, [this, &GD, &Options](const FunctionDecl *CurFD) {
- GlobalDecl CurGD{
- (CurFD->isDefined() ? CurFD->getDefinition() : CurFD)};
- StringRef MangledName = getMangledName(CurGD);
- llvm::Constant *Func = GetGlobalValue(MangledName);
- if (!Func) {
- if (CurFD->isDefined()) {
- EmitGlobalFunctionDefinition(CurGD, nullptr);
- Func = GetGlobalValue(MangledName);
- } else {
- const CGFunctionInfo &FI =
- getTypes().arrangeGlobalDeclaration(GD);
- llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
- Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
- /*DontDefer=*/false, ForDefinition);
- }
- assert(Func && "This should have just been created");
- }
-
- const auto *TA = CurFD->getAttr<TargetAttr>();
- llvm::SmallVector<StringRef, 8> Feats;
- TA->getAddedFeatures(Feats);
-
- Options.emplace_back(cast<llvm::Function>(Func),
- TA->getArchitecture(), Feats);
- });
-
- llvm::Function *ResolverFunc;
- const TargetInfo &TI = getTarget();
-
- if (TI.supportsIFunc() || FD->isTargetMultiVersion())
- ResolverFunc = cast<llvm::Function>(
- GetGlobalValue((getMangledName(GD) + ".resolver").str()));
- else
- ResolverFunc = cast<llvm::Function>(GetGlobalValue(getMangledName(GD)));
-
- if (supportsCOMDAT())
- ResolverFunc->setComdat(
- getModule().getOrInsertComdat(ResolverFunc->getName()));
-
- std::stable_sort(
- Options.begin(), Options.end(),
- [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS,
- const CodeGenFunction::MultiVersionResolverOption &RHS) {
- return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS);
- });
- CodeGenFunction CGF(*this);
- CGF.EmitMultiVersionResolver(ResolverFunc, Options);
- }
-}
-
-void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
- const auto *FD = cast<FunctionDecl>(GD.getDecl());
- assert(FD && "Not a FunctionDecl?");
- const auto *DD = FD->getAttr<CPUDispatchAttr>();
- assert(DD && "Not a cpu_dispatch Function?");
- QualType CanonTy = Context.getCanonicalType(FD->getType());
- llvm::Type *DeclTy = getTypes().ConvertFunctionType(CanonTy, FD);
-
- if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) {
- const CGFunctionInfo &FInfo = getTypes().arrangeCXXMethodDeclaration(CXXFD);
- DeclTy = getTypes().GetFunctionType(FInfo);
- }
-
- StringRef ResolverName = getMangledName(GD);
-
- llvm::Type *ResolverType;
- GlobalDecl ResolverGD;
- if (getTarget().supportsIFunc())
- ResolverType = llvm::FunctionType::get(
- llvm::PointerType::get(DeclTy,
- Context.getTargetAddressSpace(FD->getType())),
- false);
- else {
- ResolverType = DeclTy;
- ResolverGD = GD;
- }
-
- auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
- ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
-
- SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
- const TargetInfo &Target = getTarget();
- unsigned Index = 0;
- for (const IdentifierInfo *II : DD->cpus()) {
- // Get the name of the target function so we can look it up/create it.
- std::string MangledName = getMangledNameImpl(*this, GD, FD, true) +
- getCPUSpecificMangling(*this, II->getName());
-
- llvm::Constant *Func = GetGlobalValue(MangledName);
-
- if (!Func) {
- GlobalDecl ExistingDecl = Manglings.lookup(MangledName);
- if (ExistingDecl.getDecl() &&
- ExistingDecl.getDecl()->getAsFunction()->isDefined()) {
- EmitGlobalFunctionDefinition(ExistingDecl, nullptr);
- Func = GetGlobalValue(MangledName);
- } else {
- if (!ExistingDecl.getDecl())
- ExistingDecl = GD.getWithMultiVersionIndex(Index);
-
- Func = GetOrCreateLLVMFunction(
- MangledName, DeclTy, ExistingDecl,
- /*ForVTable=*/false, /*DontDefer=*/true,
- /*IsThunk=*/false, llvm::AttributeList(), ForDefinition);
- }
- }
-
- llvm::SmallVector<StringRef, 32> Features;
- Target.getCPUSpecificCPUDispatchFeatures(II->getName(), Features);
- llvm::transform(Features, Features.begin(),
- [](StringRef Str) { return Str.substr(1); });
- Features.erase(std::remove_if(
- Features.begin(), Features.end(), [&Target](StringRef Feat) {
- return !Target.validateCpuSupports(Feat);
- }), Features.end());
- Options.emplace_back(cast<llvm::Function>(Func), StringRef{}, Features);
- ++Index;
- }
-
- llvm::sort(
- Options, [](const CodeGenFunction::MultiVersionResolverOption &LHS,
- const CodeGenFunction::MultiVersionResolverOption &RHS) {
- return CodeGenFunction::GetX86CpuSupportsMask(LHS.Conditions.Features) >
- CodeGenFunction::GetX86CpuSupportsMask(RHS.Conditions.Features);
- });
-
- // If the list contains multiple 'default' versions, such as when it contains
- // 'pentium' and 'generic', don't emit the call to the generic one (since we
- // always run on at least a 'pentium'). We do this by deleting the 'least
- // advanced' (read, lowest mangling letter).
- while (Options.size() > 1 &&
- CodeGenFunction::GetX86CpuSupportsMask(
- (Options.end() - 2)->Conditions.Features) == 0) {
- StringRef LHSName = (Options.end() - 2)->Function->getName();
- StringRef RHSName = (Options.end() - 1)->Function->getName();
- if (LHSName.compare(RHSName) < 0)
- Options.erase(Options.end() - 2);
- else
- Options.erase(Options.end() - 1);
- }
-
- CodeGenFunction CGF(*this);
- CGF.EmitMultiVersionResolver(ResolverFunc, Options);
-}
-
-/// If a dispatcher for the specified mangled name is not in the module, create
-/// and return an llvm Function with the specified type.
-llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(
- GlobalDecl GD, llvm::Type *DeclTy, const FunctionDecl *FD) {
- std::string MangledName =
- getMangledNameImpl(*this, GD, FD, /*OmitMultiVersionMangling=*/true);
-
- // Holds the name of the resolver, in ifunc mode this is the ifunc (which has
- // a separate resolver).
- std::string ResolverName = MangledName;
- if (getTarget().supportsIFunc())
- ResolverName += ".ifunc";
- else if (FD->isTargetMultiVersion())
- ResolverName += ".resolver";
-
- // If this already exists, just return that one.
- if (llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName))
- return ResolverGV;
-
- // Since this is the first time we've created this IFunc, make sure
- // that we put this multiversioned function into the list to be
- // replaced later if necessary (target multiversioning only).
- if (!FD->isCPUDispatchMultiVersion() && !FD->isCPUSpecificMultiVersion())
- MultiVersionFuncs.push_back(GD);
-
- if (getTarget().supportsIFunc()) {
- llvm::Type *ResolverType = llvm::FunctionType::get(
- llvm::PointerType::get(
- DeclTy, getContext().getTargetAddressSpace(FD->getType())),
- false);
- llvm::Constant *Resolver = GetOrCreateLLVMFunction(
- MangledName + ".resolver", ResolverType, GlobalDecl{},
- /*ForVTable=*/false);
- llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(
- DeclTy, 0, llvm::Function::ExternalLinkage, "", Resolver, &getModule());
- GIF->setName(ResolverName);
- SetCommonAttributes(FD, GIF);
-
- return GIF;
- }
-
- llvm::Constant *Resolver = GetOrCreateLLVMFunction(
- ResolverName, DeclTy, GlobalDecl{}, /*ForVTable=*/false);
- assert(isa<llvm::GlobalValue>(Resolver) &&
- "Resolver should be created for the first time");
- SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
- return Resolver;
-}
-
-/// GetOrCreateLLVMFunction - If the specified mangled name is not in the
-/// module, create and return an llvm Function with the specified type. If there
-/// is something in the module with the specified name, return it potentially
-/// bitcasted to the right type.
-///
-/// If D is non-null, it specifies a decl that correspond to this. This is used
-/// to set the attributes on the function when it is first created.
-llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
- StringRef MangledName, llvm::Type *Ty, GlobalDecl GD, bool ForVTable,
- bool DontDefer, bool IsThunk, llvm::AttributeList ExtraAttrs,
- ForDefinition_t IsForDefinition) {
- const Decl *D = GD.getDecl();
-
- // Any attempts to use a MultiVersion function should result in retrieving
- // the iFunc instead. Name Mangling will handle the rest of the changes.
- if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D)) {
- // For the device mark the function as one that should be emitted.
- if (getLangOpts().OpenMPIsDevice && OpenMPRuntime &&
- !OpenMPRuntime->markAsGlobalTarget(GD) && FD->isDefined() &&
- !DontDefer && !IsForDefinition) {
- if (const FunctionDecl *FDDef = FD->getDefinition()) {
- GlobalDecl GDDef;
- if (const auto *CD = dyn_cast<CXXConstructorDecl>(FDDef))
- GDDef = GlobalDecl(CD, GD.getCtorType());
- else if (const auto *DD = dyn_cast<CXXDestructorDecl>(FDDef))
- GDDef = GlobalDecl(DD, GD.getDtorType());
- else
- GDDef = GlobalDecl(FDDef);
- EmitGlobal(GDDef);
- }
- }
-
- if (FD->isMultiVersion()) {
- const auto *TA = FD->getAttr<TargetAttr>();
- if (TA && TA->isDefaultVersion())
- UpdateMultiVersionNames(GD, FD);
- if (!IsForDefinition)
- return GetOrCreateMultiVersionResolver(GD, Ty, FD);
- }
- }
-
- // Lookup the entry, lazily creating it if necessary.
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- if (Entry) {
- if (WeakRefReferences.erase(Entry)) {
- const FunctionDecl *FD = cast_or_null<FunctionDecl>(D);
- if (FD && !FD->hasAttr<WeakAttr>())
- Entry->setLinkage(llvm::Function::ExternalLinkage);
- }
-
- // Handle dropped DLL attributes.
- if (D && !D->hasAttr<DLLImportAttr>() && !D->hasAttr<DLLExportAttr>()) {
- Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
- setDSOLocal(Entry);
- }
-
- // If there are two attempts to define the same mangled name, issue an
- // error.
- if (IsForDefinition && !Entry->isDeclaration()) {
- GlobalDecl OtherGD;
- // Check that GD is not yet in DiagnosedConflictingDefinitions is required
- // to make sure that we issue an error only once.
- if (lookupRepresentativeDecl(MangledName, OtherGD) &&
- (GD.getCanonicalDecl().getDecl() !=
- OtherGD.getCanonicalDecl().getDecl()) &&
- DiagnosedConflictingDefinitions.insert(GD).second) {
- getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name)
- << MangledName;
- getDiags().Report(OtherGD.getDecl()->getLocation(),
- diag::note_previous_definition);
- }
- }
-
- if ((isa<llvm::Function>(Entry) || isa<llvm::GlobalAlias>(Entry)) &&
- (Entry->getType()->getElementType() == Ty)) {
- return Entry;
- }
-
- // Make sure the result is of the correct type.
- // (If function is requested for a definition, we always need to create a new
- // function, not just return a bitcast.)
- if (!IsForDefinition)
- return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo());
- }
-
- // This function doesn't have a complete type (for example, the return
- // type is an incomplete struct). Use a fake type instead, and make
- // sure not to try to set attributes.
- bool IsIncompleteFunction = false;
-
- llvm::FunctionType *FTy;
- if (isa<llvm::FunctionType>(Ty)) {
- FTy = cast<llvm::FunctionType>(Ty);
- } else {
- FTy = llvm::FunctionType::get(VoidTy, false);
- IsIncompleteFunction = true;
- }
-
- llvm::Function *F =
- llvm::Function::Create(FTy, llvm::Function::ExternalLinkage,
- Entry ? StringRef() : MangledName, &getModule());
-
- // If we already created a function with the same mangled name (but different
- // type) before, take its name and add it to the list of functions to be
- // replaced with F at the end of CodeGen.
- //
- // This happens if there is a prototype for a function (e.g. "int f()") and
- // then a definition of a different type (e.g. "int f(int x)").
- if (Entry) {
- F->takeName(Entry);
-
- // This might be an implementation of a function without a prototype, in
- // which case, try to do special replacement of calls which match the new
- // prototype. The really key thing here is that we also potentially drop
- // arguments from the call site so as to make a direct call, which makes the
- // inliner happier and suppresses a number of optimizer warnings (!) about
- // dropping arguments.
- if (!Entry->use_empty()) {
- ReplaceUsesOfNonProtoTypeWithRealFunction(Entry, F);
- Entry->removeDeadConstantUsers();
- }
-
- llvm::Constant *BC = llvm::ConstantExpr::getBitCast(
- F, Entry->getType()->getElementType()->getPointerTo());
- addGlobalValReplacement(Entry, BC);
- }
-
- assert(F->getName() == MangledName && "name was uniqued!");
- if (D)
- SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk);
- if (ExtraAttrs.hasAttributes(llvm::AttributeList::FunctionIndex)) {
- llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex);
- F->addAttributes(llvm::AttributeList::FunctionIndex, B);
- }
-
- if (!DontDefer) {
- // All MSVC dtors other than the base dtor are linkonce_odr and delegate to
- // each other bottoming out with the base dtor. Therefore we emit non-base
- // dtors on usage, even if there is no dtor definition in the TU.
- if (D && isa<CXXDestructorDecl>(D) &&
- getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
- GD.getDtorType()))
- addDeferredDeclToEmit(GD);
-
- // This is the first use or definition of a mangled name. If there is a
- // deferred decl with this name, remember that we need to emit it at the end
- // of the file.
- auto DDI = DeferredDecls.find(MangledName);
- if (DDI != DeferredDecls.end()) {
- // Move the potentially referenced deferred decl to the
- // DeferredDeclsToEmit list, and remove it from DeferredDecls (since we
- // don't need it anymore).
- addDeferredDeclToEmit(DDI->second);
- DeferredDecls.erase(DDI);
-
- // Otherwise, there are cases we have to worry about where we're
- // using a declaration for which we must emit a definition but where
- // we might not find a top-level definition:
- // - member functions defined inline in their classes
- // - friend functions defined inline in some class
- // - special member functions with implicit definitions
- // If we ever change our AST traversal to walk into class methods,
- // this will be unnecessary.
- //
- // We also don't emit a definition for a function if it's going to be an
- // entry in a vtable, unless it's already marked as used.
- } else if (getLangOpts().CPlusPlus && D) {
- // Look for a declaration that's lexically in a record.
- for (const auto *FD = cast<FunctionDecl>(D)->getMostRecentDecl(); FD;
- FD = FD->getPreviousDecl()) {
- if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
- if (FD->doesThisDeclarationHaveABody()) {
- addDeferredDeclToEmit(GD.getWithDecl(FD));
- break;
- }
- }
- }
- }
- }
-
- // Make sure the result is of the requested type.
- if (!IsIncompleteFunction) {
- assert(F->getType()->getElementType() == Ty);
- return F;
- }
-
- llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
- return llvm::ConstantExpr::getBitCast(F, PTy);
-}
-
-/// GetAddrOfFunction - Return the address of the given function. If Ty is
-/// non-null, then this function will use the specified type if it has to
-/// create it (this occurs when we see a definition of the function).
-llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
- llvm::Type *Ty,
- bool ForVTable,
- bool DontDefer,
- ForDefinition_t IsForDefinition) {
- // If there was no specific requested type, just convert it now.
- if (!Ty) {
- const auto *FD = cast<FunctionDecl>(GD.getDecl());
- auto CanonTy = Context.getCanonicalType(FD->getType());
- Ty = getTypes().ConvertFunctionType(CanonTy, FD);
- }
-
- // Devirtualized destructor calls may come through here instead of via
- // getAddrOfCXXStructor. Make sure we use the MS ABI base destructor instead
- // of the complete destructor when necessary.
- if (const auto *DD = dyn_cast<CXXDestructorDecl>(GD.getDecl())) {
- if (getTarget().getCXXABI().isMicrosoft() &&
- GD.getDtorType() == Dtor_Complete &&
- DD->getParent()->getNumVBases() == 0)
- GD = GlobalDecl(DD, Dtor_Base);
- }
-
- StringRef MangledName = getMangledName(GD);
- return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer,
- /*IsThunk=*/false, llvm::AttributeList(),
- IsForDefinition);
-}
-
-static const FunctionDecl *
-GetRuntimeFunctionDecl(ASTContext &C, StringRef Name) {
- TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
- DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
-
- IdentifierInfo &CII = C.Idents.get(Name);
- for (const auto &Result : DC->lookup(&CII))
- if (const auto FD = dyn_cast<FunctionDecl>(Result))
- return FD;
-
- if (!C.getLangOpts().CPlusPlus)
- return nullptr;
-
- // Demangle the premangled name from getTerminateFn()
- IdentifierInfo &CXXII =
- (Name == "_ZSt9terminatev" || Name == "?terminate@@YAXXZ")
- ? C.Idents.get("terminate")
- : C.Idents.get(Name);
-
- for (const auto &N : {"__cxxabiv1", "std"}) {
- IdentifierInfo &NS = C.Idents.get(N);
- for (const auto &Result : DC->lookup(&NS)) {
- NamespaceDecl *ND = dyn_cast<NamespaceDecl>(Result);
- if (auto LSD = dyn_cast<LinkageSpecDecl>(Result))
- for (const auto &Result : LSD->lookup(&NS))
- if ((ND = dyn_cast<NamespaceDecl>(Result)))
- break;
-
- if (ND)
- for (const auto &Result : ND->lookup(&CXXII))
- if (const auto *FD = dyn_cast<FunctionDecl>(Result))
- return FD;
- }
- }
-
- return nullptr;
-}
-
-/// CreateRuntimeFunction - Create a new runtime function with the specified
-/// type and name.
-llvm::Constant *
-CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name,
- llvm::AttributeList ExtraAttrs,
- bool Local) {
- llvm::Constant *C =
- GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
- /*DontDefer=*/false, /*IsThunk=*/false,
- ExtraAttrs);
-
- if (auto *F = dyn_cast<llvm::Function>(C)) {
- if (F->empty()) {
- F->setCallingConv(getRuntimeCC());
-
- if (!Local && getTriple().isOSBinFormatCOFF() &&
- !getCodeGenOpts().LTOVisibilityPublicStd &&
- !getTriple().isWindowsGNUEnvironment()) {
- const FunctionDecl *FD = GetRuntimeFunctionDecl(Context, Name);
- if (!FD || FD->hasAttr<DLLImportAttr>()) {
- F->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- F->setLinkage(llvm::GlobalValue::ExternalLinkage);
- }
- }
- setDSOLocal(F);
- }
- }
-
- return C;
-}
-
-/// CreateBuiltinFunction - Create a new builtin function with the specified
-/// type and name.
-llvm::Constant *
-CodeGenModule::CreateBuiltinFunction(llvm::FunctionType *FTy, StringRef Name,
- llvm::AttributeList ExtraAttrs) {
- return CreateRuntimeFunction(FTy, Name, ExtraAttrs, true);
-}
-
-/// isTypeConstant - Determine whether an object of this type can be emitted
-/// as a constant.
-///
-/// If ExcludeCtor is true, the duration when the object's constructor runs
-/// will not be considered. The caller will need to verify that the object is
-/// not written to during its construction.
-bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) {
- if (!Ty.isConstant(Context) && !Ty->isReferenceType())
- return false;
-
- if (Context.getLangOpts().CPlusPlus) {
- if (const CXXRecordDecl *Record
- = Context.getBaseElementType(Ty)->getAsCXXRecordDecl())
- return ExcludeCtor && !Record->hasMutableFields() &&
- Record->hasTrivialDestructor();
- }
-
- return true;
-}
-
-/// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module,
-/// create and return an llvm GlobalVariable with the specified type. If there
-/// is something in the module with the specified name, return it potentially
-/// bitcasted to the right type.
-///
-/// If D is non-null, it specifies a decl that correspond to this. This is used
-/// to set the attributes on the global when it is first created.
-///
-/// If IsForDefinition is true, it is guaranteed that an actual global with
-/// type Ty will be returned, not conversion of a variable with the same
-/// mangled name but some other type.
-llvm::Constant *
-CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
- llvm::PointerType *Ty,
- const VarDecl *D,
- ForDefinition_t IsForDefinition) {
- // Lookup the entry, lazily creating it if necessary.
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- if (Entry) {
- if (WeakRefReferences.erase(Entry)) {
- if (D && !D->hasAttr<WeakAttr>())
- Entry->setLinkage(llvm::Function::ExternalLinkage);
- }
-
- // Handle dropped DLL attributes.
- if (D && !D->hasAttr<DLLImportAttr>() && !D->hasAttr<DLLExportAttr>())
- Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
-
- if (LangOpts.OpenMP && !LangOpts.OpenMPSimd && D)
- getOpenMPRuntime().registerTargetGlobalVariable(D, Entry);
-
- if (Entry->getType() == Ty)
- return Entry;
-
- // If there are two attempts to define the same mangled name, issue an
- // error.
- if (IsForDefinition && !Entry->isDeclaration()) {
- GlobalDecl OtherGD;
- const VarDecl *OtherD;
-
- // Check that D is not yet in DiagnosedConflictingDefinitions is required
- // to make sure that we issue an error only once.
- if (D && lookupRepresentativeDecl(MangledName, OtherGD) &&
- (D->getCanonicalDecl() != OtherGD.getCanonicalDecl().getDecl()) &&
- (OtherD = dyn_cast<VarDecl>(OtherGD.getDecl())) &&
- OtherD->hasInit() &&
- DiagnosedConflictingDefinitions.insert(D).second) {
- getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name)
- << MangledName;
- getDiags().Report(OtherGD.getDecl()->getLocation(),
- diag::note_previous_definition);
- }
- }
-
- // Make sure the result is of the correct type.
- if (Entry->getType()->getAddressSpace() != Ty->getAddressSpace())
- return llvm::ConstantExpr::getAddrSpaceCast(Entry, Ty);
-
- // (If global is requested for a definition, we always need to create a new
- // global, not just return a bitcast.)
- if (!IsForDefinition)
- return llvm::ConstantExpr::getBitCast(Entry, Ty);
- }
-
- auto AddrSpace = GetGlobalVarAddressSpace(D);
- auto TargetAddrSpace = getContext().getTargetAddressSpace(AddrSpace);
-
- auto *GV = new llvm::GlobalVariable(
- getModule(), Ty->getElementType(), false,
- llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr,
- llvm::GlobalVariable::NotThreadLocal, TargetAddrSpace);
-
- // If we already created a global with the same mangled name (but different
- // type) before, take its name and remove it from its parent.
- if (Entry) {
- GV->takeName(Entry);
-
- if (!Entry->use_empty()) {
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(GV, Entry->getType());
- Entry->replaceAllUsesWith(NewPtrForOldDecl);
- }
-
- Entry->eraseFromParent();
- }
-
- // This is the first use or definition of a mangled name. If there is a
- // deferred decl with this name, remember that we need to emit it at the end
- // of the file.
- auto DDI = DeferredDecls.find(MangledName);
- if (DDI != DeferredDecls.end()) {
- // Move the potentially referenced deferred decl to the DeferredDeclsToEmit
- // list, and remove it from DeferredDecls (since we don't need it anymore).
- addDeferredDeclToEmit(DDI->second);
- DeferredDecls.erase(DDI);
- }
-
- // Handle things which are present even on external declarations.
- if (D) {
- if (LangOpts.OpenMP && !LangOpts.OpenMPSimd)
- getOpenMPRuntime().registerTargetGlobalVariable(D, GV);
-
- // FIXME: This code is overly simple and should be merged with other global
- // handling.
- GV->setConstant(isTypeConstant(D->getType(), false));
-
- GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
-
- setLinkageForGV(GV, D);
-
- if (D->getTLSKind()) {
- if (D->getTLSKind() == VarDecl::TLS_Dynamic)
- CXXThreadLocals.push_back(D);
- setTLSMode(GV, *D);
- }
-
- setGVProperties(GV, D);
-
- // If required by the ABI, treat declarations of static data members with
- // inline initializers as definitions.
- if (getContext().isMSStaticDataMemberInlineDefinition(D)) {
- EmitGlobalVarDefinition(D);
- }
-
- // Emit section information for extern variables.
- if (D->hasExternalStorage()) {
- if (const SectionAttr *SA = D->getAttr<SectionAttr>())
- GV->setSection(SA->getName());
- }
-
- // Handle XCore specific ABI requirements.
- if (getTriple().getArch() == llvm::Triple::xcore &&
- D->getLanguageLinkage() == CLanguageLinkage &&
- D->getType().isConstant(Context) &&
- isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
- GV->setSection(".cp.rodata");
-
- // Check if we a have a const declaration with an initializer, we may be
- // able to emit it as available_externally to expose it's value to the
- // optimizer.
- if (Context.getLangOpts().CPlusPlus && GV->hasExternalLinkage() &&
- D->getType().isConstQualified() && !GV->hasInitializer() &&
- !D->hasDefinition() && D->hasInit() && !D->hasAttr<DLLImportAttr>()) {
- const auto *Record =
- Context.getBaseElementType(D->getType())->getAsCXXRecordDecl();
- bool HasMutableFields = Record && Record->hasMutableFields();
- if (!HasMutableFields) {
- const VarDecl *InitDecl;
- const Expr *InitExpr = D->getAnyInitializer(InitDecl);
- if (InitExpr) {
- ConstantEmitter emitter(*this);
- llvm::Constant *Init = emitter.tryEmitForInitializer(*InitDecl);
- if (Init) {
- auto *InitType = Init->getType();
- if (GV->getType()->getElementType() != InitType) {
- // The type of the initializer does not match the definition.
- // This happens when an initializer has a different type from
- // the type of the global (because of padding at the end of a
- // structure for instance).
- GV->setName(StringRef());
- // Make a new global with the correct type, this is now guaranteed
- // to work.
- auto *NewGV = cast<llvm::GlobalVariable>(
- GetAddrOfGlobalVar(D, InitType, IsForDefinition));
-
- // Erase the old global, since it is no longer used.
- GV->eraseFromParent();
- GV = NewGV;
- } else {
- GV->setInitializer(Init);
- GV->setConstant(true);
- GV->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
- }
- emitter.finalize(GV);
- }
- }
- }
- }
- }
-
- LangAS ExpectedAS =
- D ? D->getType().getAddressSpace()
- : (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default);
- assert(getContext().getTargetAddressSpace(ExpectedAS) ==
- Ty->getPointerAddressSpace());
- if (AddrSpace != ExpectedAS)
- return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace,
- ExpectedAS, Ty);
-
- return GV;
-}
-
-llvm::Constant *
-CodeGenModule::GetAddrOfGlobal(GlobalDecl GD,
- ForDefinition_t IsForDefinition) {
- const Decl *D = GD.getDecl();
- if (isa<CXXConstructorDecl>(D))
- return getAddrOfCXXStructor(cast<CXXConstructorDecl>(D),
- getFromCtorType(GD.getCtorType()),
- /*FnInfo=*/nullptr, /*FnType=*/nullptr,
- /*DontDefer=*/false, IsForDefinition);
- else if (isa<CXXDestructorDecl>(D))
- return getAddrOfCXXStructor(cast<CXXDestructorDecl>(D),
- getFromDtorType(GD.getDtorType()),
- /*FnInfo=*/nullptr, /*FnType=*/nullptr,
- /*DontDefer=*/false, IsForDefinition);
- else if (isa<CXXMethodDecl>(D)) {
- auto FInfo = &getTypes().arrangeCXXMethodDeclaration(
- cast<CXXMethodDecl>(D));
- auto Ty = getTypes().GetFunctionType(*FInfo);
- return GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer=*/false,
- IsForDefinition);
- } else if (isa<FunctionDecl>(D)) {
- const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
- llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
- return GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer=*/false,
- IsForDefinition);
- } else
- return GetAddrOfGlobalVar(cast<VarDecl>(D), /*Ty=*/nullptr,
- IsForDefinition);
-}
-
-llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
- StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage,
- unsigned Alignment) {
- llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name);
- llvm::GlobalVariable *OldGV = nullptr;
-
- if (GV) {
- // Check if the variable has the right type.
- if (GV->getType()->getElementType() == Ty)
- return GV;
-
- // Because C++ name mangling, the only way we can end up with an already
- // existing global with the same name is if it has been declared extern "C".
- assert(GV->isDeclaration() && "Declaration has wrong type!");
- OldGV = GV;
- }
-
- // Create a new variable.
- GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true,
- Linkage, nullptr, Name);
-
- if (OldGV) {
- // Replace occurrences of the old variable if needed.
- GV->takeName(OldGV);
-
- if (!OldGV->use_empty()) {
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
- OldGV->replaceAllUsesWith(NewPtrForOldDecl);
- }
-
- OldGV->eraseFromParent();
- }
-
- if (supportsCOMDAT() && GV->isWeakForLinker() &&
- !GV->hasAvailableExternallyLinkage())
- GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
-
- GV->setAlignment(Alignment);
-
- return GV;
-}
-
-/// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the
-/// given global variable. If Ty is non-null and if the global doesn't exist,
-/// then it will be created with the specified type instead of whatever the
-/// normal requested type would be. If IsForDefinition is true, it is guaranteed
-/// that an actual global with type Ty will be returned, not conversion of a
-/// variable with the same mangled name but some other type.
-llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
- llvm::Type *Ty,
- ForDefinition_t IsForDefinition) {
- assert(D->hasGlobalStorage() && "Not a global variable");
- QualType ASTTy = D->getType();
- if (!Ty)
- Ty = getTypes().ConvertTypeForMem(ASTTy);
-
- llvm::PointerType *PTy =
- llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy));
-
- StringRef MangledName = getMangledName(D);
- return GetOrCreateLLVMGlobal(MangledName, PTy, D, IsForDefinition);
-}
-
-/// CreateRuntimeVariable - Create a new runtime global variable with the
-/// specified type and name.
-llvm::Constant *
-CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty,
- StringRef Name) {
- auto *Ret =
- GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), nullptr);
- setDSOLocal(cast<llvm::GlobalValue>(Ret->stripPointerCasts()));
- return Ret;
-}
-
-void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
- assert(!D->getInit() && "Cannot emit definite definitions here!");
-
- StringRef MangledName = getMangledName(D);
- llvm::GlobalValue *GV = GetGlobalValue(MangledName);
-
- // We already have a definition, not declaration, with the same mangled name.
- // Emitting of declaration is not required (and actually overwrites emitted
- // definition).
- if (GV && !GV->isDeclaration())
- return;
-
- // If we have not seen a reference to this variable yet, place it into the
- // deferred declarations table to be emitted if needed later.
- if (!MustBeEmitted(D) && !GV) {
- DeferredDecls[MangledName] = D;
- return;
- }
-
- // The tentative definition is the only definition.
- EmitGlobalVarDefinition(D);
-}
-
-CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
- return Context.toCharUnitsFromBits(
- getDataLayout().getTypeStoreSizeInBits(Ty));
-}
-
-LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) {
- LangAS AddrSpace = LangAS::Default;
- if (LangOpts.OpenCL) {
- AddrSpace = D ? D->getType().getAddressSpace() : LangAS::opencl_global;
- assert(AddrSpace == LangAS::opencl_global ||
- AddrSpace == LangAS::opencl_constant ||
- AddrSpace == LangAS::opencl_local ||
- AddrSpace >= LangAS::FirstTargetAddressSpace);
- return AddrSpace;
- }
-
- if (LangOpts.CUDA && LangOpts.CUDAIsDevice) {
- if (D && D->hasAttr<CUDAConstantAttr>())
- return LangAS::cuda_constant;
- else if (D && D->hasAttr<CUDASharedAttr>())
- return LangAS::cuda_shared;
- else if (D && D->hasAttr<CUDADeviceAttr>())
- return LangAS::cuda_device;
- else if (D && D->getType().isConstQualified())
- return LangAS::cuda_constant;
- else
- return LangAS::cuda_device;
- }
-
- return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D);
-}
-
-LangAS CodeGenModule::getStringLiteralAddressSpace() const {
- // OpenCL v1.2 s6.5.3: a string literal is in the constant address space.
- if (LangOpts.OpenCL)
- return LangAS::opencl_constant;
- if (auto AS = getTarget().getConstantAddressSpace())
- return AS.getValue();
- return LangAS::Default;
-}
-
-// In address space agnostic languages, string literals are in default address
-// space in AST. However, certain targets (e.g. amdgcn) request them to be
-// emitted in constant address space in LLVM IR. To be consistent with other
-// parts of AST, string literal global variables in constant address space
-// need to be casted to default address space before being put into address
-// map and referenced by other part of CodeGen.
-// In OpenCL, string literals are in constant address space in AST, therefore
-// they should not be casted to default address space.
-static llvm::Constant *
-castStringLiteralToDefaultAddressSpace(CodeGenModule &CGM,
- llvm::GlobalVariable *GV) {
- llvm::Constant *Cast = GV;
- if (!CGM.getLangOpts().OpenCL) {
- if (auto AS = CGM.getTarget().getConstantAddressSpace()) {
- if (AS != LangAS::Default)
- Cast = CGM.getTargetCodeGenInfo().performAddrSpaceCast(
- CGM, GV, AS.getValue(), LangAS::Default,
- GV->getValueType()->getPointerTo(
- CGM.getContext().getTargetAddressSpace(LangAS::Default)));
- }
- }
- return Cast;
-}
-
-template<typename SomeDecl>
-void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
- llvm::GlobalValue *GV) {
- if (!getLangOpts().CPlusPlus)
- return;
-
- // Must have 'used' attribute, or else inline assembly can't rely on
- // the name existing.
- if (!D->template hasAttr<UsedAttr>())
- return;
-
- // Must have internal linkage and an ordinary name.
- if (!D->getIdentifier() || D->getFormalLinkage() != InternalLinkage)
- return;
-
- // Must be in an extern "C" context. Entities declared directly within
- // a record are not extern "C" even if the record is in such a context.
- const SomeDecl *First = D->getFirstDecl();
- if (First->getDeclContext()->isRecord() || !First->isInExternCContext())
- return;
-
- // OK, this is an internal linkage entity inside an extern "C" linkage
- // specification. Make a note of that so we can give it the "expected"
- // mangled name if nothing else is using that name.
- std::pair<StaticExternCMap::iterator, bool> R =
- StaticExternCValues.insert(std::make_pair(D->getIdentifier(), GV));
-
- // If we have multiple internal linkage entities with the same name
- // in extern "C" regions, none of them gets that name.
- if (!R.second)
- R.first->second = nullptr;
-}
-
-static bool shouldBeInCOMDAT(CodeGenModule &CGM, const Decl &D) {
- if (!CGM.supportsCOMDAT())
- return false;
-
- if (D.hasAttr<SelectAnyAttr>())
- return true;
-
- GVALinkage Linkage;
- if (auto *VD = dyn_cast<VarDecl>(&D))
- Linkage = CGM.getContext().GetGVALinkageForVariable(VD);
- else
- Linkage = CGM.getContext().GetGVALinkageForFunction(cast<FunctionDecl>(&D));
-
- switch (Linkage) {
- case GVA_Internal:
- case GVA_AvailableExternally:
- case GVA_StrongExternal:
- return false;
- case GVA_DiscardableODR:
- case GVA_StrongODR:
- return true;
- }
- llvm_unreachable("No such linkage");
-}
-
-void CodeGenModule::maybeSetTrivialComdat(const Decl &D,
- llvm::GlobalObject &GO) {
- if (!shouldBeInCOMDAT(*this, D))
- return;
- GO.setComdat(TheModule.getOrInsertComdat(GO.getName()));
-}
-
-/// Pass IsTentative as true if you want to create a tentative definition.
-void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
- bool IsTentative) {
- // OpenCL global variables of sampler type are translated to function calls,
- // therefore no need to be translated.
- QualType ASTTy = D->getType();
- if (getLangOpts().OpenCL && ASTTy->isSamplerT())
- return;
-
- // If this is OpenMP device, check if it is legal to emit this global
- // normally.
- if (LangOpts.OpenMPIsDevice && OpenMPRuntime &&
- OpenMPRuntime->emitTargetGlobalVariable(D))
- return;
-
- llvm::Constant *Init = nullptr;
- CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
- bool NeedsGlobalCtor = false;
- bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor();
-
- const VarDecl *InitDecl;
- const Expr *InitExpr = D->getAnyInitializer(InitDecl);
-
- Optional<ConstantEmitter> emitter;
-
- // CUDA E.2.4.1 "__shared__ variables cannot have an initialization
- // as part of their declaration." Sema has already checked for
- // error cases, so we just need to set Init to UndefValue.
- bool IsCUDASharedVar =
- getLangOpts().CUDAIsDevice && D->hasAttr<CUDASharedAttr>();
- // Shadows of initialized device-side global variables are also left
- // undefined.
- bool IsCUDAShadowVar =
- !getLangOpts().CUDAIsDevice &&
- (D->hasAttr<CUDAConstantAttr>() || D->hasAttr<CUDADeviceAttr>() ||
- D->hasAttr<CUDASharedAttr>());
- if (getLangOpts().CUDA && (IsCUDASharedVar || IsCUDAShadowVar))
- Init = llvm::UndefValue::get(getTypes().ConvertType(ASTTy));
- else if (!InitExpr) {
- // This is a tentative definition; tentative definitions are
- // implicitly initialized with { 0 }.
- //
- // Note that tentative definitions are only emitted at the end of
- // a translation unit, so they should never have incomplete
- // type. In addition, EmitTentativeDefinition makes sure that we
- // never attempt to emit a tentative definition if a real one
- // exists. A use may still exists, however, so we still may need
- // to do a RAUW.
- assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
- Init = EmitNullConstant(D->getType());
- } else {
- initializedGlobalDecl = GlobalDecl(D);
- emitter.emplace(*this);
- Init = emitter->tryEmitForInitializer(*InitDecl);
-
- if (!Init) {
- QualType T = InitExpr->getType();
- if (D->getType()->isReferenceType())
- T = D->getType();
-
- if (getLangOpts().CPlusPlus) {
- Init = EmitNullConstant(T);
- NeedsGlobalCtor = true;
- } else {
- ErrorUnsupported(D, "static initializer");
- Init = llvm::UndefValue::get(getTypes().ConvertType(T));
- }
- } else {
- // We don't need an initializer, so remove the entry for the delayed
- // initializer position (just in case this entry was delayed) if we
- // also don't need to register a destructor.
- if (getLangOpts().CPlusPlus && !NeedsGlobalDtor)
- DelayedCXXInitPosition.erase(D);
- }
- }
-
- llvm::Type* InitType = Init->getType();
- llvm::Constant *Entry =
- GetAddrOfGlobalVar(D, InitType, ForDefinition_t(!IsTentative));
-
- // Strip off a bitcast if we got one back.
- if (auto *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
- assert(CE->getOpcode() == llvm::Instruction::BitCast ||
- CE->getOpcode() == llvm::Instruction::AddrSpaceCast ||
- // All zero index gep.
- CE->getOpcode() == llvm::Instruction::GetElementPtr);
- Entry = CE->getOperand(0);
- }
-
- // Entry is now either a Function or GlobalVariable.
- auto *GV = dyn_cast<llvm::GlobalVariable>(Entry);
-
- // We have a definition after a declaration with the wrong type.
- // We must make a new GlobalVariable* and update everything that used OldGV
- // (a declaration or tentative definition) with the new GlobalVariable*
- // (which will be a definition).
- //
- // This happens if there is a prototype for a global (e.g.
- // "extern int x[];") and then a definition of a different type (e.g.
- // "int x[10];"). This also happens when an initializer has a different type
- // from the type of the global (this happens with unions).
- if (!GV || GV->getType()->getElementType() != InitType ||
- GV->getType()->getAddressSpace() !=
- getContext().getTargetAddressSpace(GetGlobalVarAddressSpace(D))) {
-
- // Move the old entry aside so that we'll create a new one.
- Entry->setName(StringRef());
-
- // Make a new global with the correct type, this is now guaranteed to work.
- GV = cast<llvm::GlobalVariable>(
- GetAddrOfGlobalVar(D, InitType, ForDefinition_t(!IsTentative)));
-
- // Replace all uses of the old global with the new global
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(GV, Entry->getType());
- Entry->replaceAllUsesWith(NewPtrForOldDecl);
-
- // Erase the old global, since it is no longer used.
- cast<llvm::GlobalValue>(Entry)->eraseFromParent();
- }
-
- MaybeHandleStaticInExternC(D, GV);
-
- if (D->hasAttr<AnnotateAttr>())
- AddGlobalAnnotations(D, GV);
-
- // Set the llvm linkage type as appropriate.
- llvm::GlobalValue::LinkageTypes Linkage =
- getLLVMLinkageVarDefinition(D, GV->isConstant());
-
- // CUDA B.2.1 "The __device__ qualifier declares a variable that resides on
- // the device. [...]"
- // CUDA B.2.2 "The __constant__ qualifier, optionally used together with
- // __device__, declares a variable that: [...]
- // Is accessible from all the threads within the grid and from the host
- // through the runtime library (cudaGetSymbolAddress() / cudaGetSymbolSize()
- // / cudaMemcpyToSymbol() / cudaMemcpyFromSymbol())."
- if (GV && LangOpts.CUDA) {
- if (LangOpts.CUDAIsDevice) {
- if (D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>())
- GV->setExternallyInitialized(true);
- } else {
- // Host-side shadows of external declarations of device-side
- // global variables become internal definitions. These have to
- // be internal in order to prevent name conflicts with global
- // host variables with the same name in a different TUs.
- if (D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>()) {
- Linkage = llvm::GlobalValue::InternalLinkage;
-
- // Shadow variables and their properties must be registered
- // with CUDA runtime.
- unsigned Flags = 0;
- if (!D->hasDefinition())
- Flags |= CGCUDARuntime::ExternDeviceVar;
- if (D->hasAttr<CUDAConstantAttr>())
- Flags |= CGCUDARuntime::ConstantDeviceVar;
- // Extern global variables will be registered in the TU where they are
- // defined.
- if (!D->hasExternalStorage())
- getCUDARuntime().registerDeviceVar(*GV, Flags);
- } else if (D->hasAttr<CUDASharedAttr>())
- // __shared__ variables are odd. Shadows do get created, but
- // they are not registered with the CUDA runtime, so they
- // can't really be used to access their device-side
- // counterparts. It's not clear yet whether it's nvcc's bug or
- // a feature, but we've got to do the same for compatibility.
- Linkage = llvm::GlobalValue::InternalLinkage;
- }
- }
-
- GV->setInitializer(Init);
- if (emitter) emitter->finalize(GV);
-
- // If it is safe to mark the global 'constant', do so now.
- GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor &&
- isTypeConstant(D->getType(), true));
-
- // If it is in a read-only section, mark it 'constant'.
- if (const SectionAttr *SA = D->getAttr<SectionAttr>()) {
- const ASTContext::SectionInfo &SI = Context.SectionInfos[SA->getName()];
- if ((SI.SectionFlags & ASTContext::PSF_Write) == 0)
- GV->setConstant(true);
- }
-
- GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
-
-
- // On Darwin, if the normal linkage of a C++ thread_local variable is
- // LinkOnce or Weak, we keep the normal linkage to prevent multiple
- // copies within a linkage unit; otherwise, the backing variable has
- // internal linkage and all accesses should just be calls to the
- // Itanium-specified entry point, which has the normal linkage of the
- // variable. This is to preserve the ability to change the implementation
- // behind the scenes.
- if (!D->isStaticLocal() && D->getTLSKind() == VarDecl::TLS_Dynamic &&
- Context.getTargetInfo().getTriple().isOSDarwin() &&
- !llvm::GlobalVariable::isLinkOnceLinkage(Linkage) &&
- !llvm::GlobalVariable::isWeakLinkage(Linkage))
- Linkage = llvm::GlobalValue::InternalLinkage;
-
- GV->setLinkage(Linkage);
- if (D->hasAttr<DLLImportAttr>())
- GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
- else if (D->hasAttr<DLLExportAttr>())
- GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
- else
- GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
-
- if (Linkage == llvm::GlobalVariable::CommonLinkage) {
- // common vars aren't constant even if declared const.
- GV->setConstant(false);
- // Tentative definition of global variables may be initialized with
- // non-zero null pointers. In this case they should have weak linkage
- // since common linkage must have zero initializer and must not have
- // explicit section therefore cannot have non-zero initial value.
- if (!GV->getInitializer()->isNullValue())
- GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
- }
-
- setNonAliasAttributes(D, GV);
-
- if (D->getTLSKind() && !GV->isThreadLocal()) {
- if (D->getTLSKind() == VarDecl::TLS_Dynamic)
- CXXThreadLocals.push_back(D);
- setTLSMode(GV, *D);
- }
-
- maybeSetTrivialComdat(*D, *GV);
-
- // Emit the initializer function if necessary.
- if (NeedsGlobalCtor || NeedsGlobalDtor)
- EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
-
- SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor);
-
- // Emit global variable debug information.
- if (CGDebugInfo *DI = getModuleDebugInfo())
- if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo)
- DI->EmitGlobalVariable(GV, D);
-}
-
-static bool isVarDeclStrongDefinition(const ASTContext &Context,
- CodeGenModule &CGM, const VarDecl *D,
- bool NoCommon) {
- // Don't give variables common linkage if -fno-common was specified unless it
- // was overridden by a NoCommon attribute.
- if ((NoCommon || D->hasAttr<NoCommonAttr>()) && !D->hasAttr<CommonAttr>())
- return true;
-
- // C11 6.9.2/2:
- // A declaration of an identifier for an object that has file scope without
- // an initializer, and without a storage-class specifier or with the
- // storage-class specifier static, constitutes a tentative definition.
- if (D->getInit() || D->hasExternalStorage())
- return true;
-
- // A variable cannot be both common and exist in a section.
- if (D->hasAttr<SectionAttr>())
- return true;
-
- // A variable cannot be both common and exist in a section.
- // We don't try to determine which is the right section in the front-end.
- // If no specialized section name is applicable, it will resort to default.
- if (D->hasAttr<PragmaClangBSSSectionAttr>() ||
- D->hasAttr<PragmaClangDataSectionAttr>() ||
- D->hasAttr<PragmaClangRodataSectionAttr>())
- return true;
-
- // Thread local vars aren't considered common linkage.
- if (D->getTLSKind())
- return true;
-
- // Tentative definitions marked with WeakImportAttr are true definitions.
- if (D->hasAttr<WeakImportAttr>())
- return true;
-
- // A variable cannot be both common and exist in a comdat.
- if (shouldBeInCOMDAT(CGM, *D))
- return true;
-
- // Declarations with a required alignment do not have common linkage in MSVC
- // mode.
- if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- if (D->hasAttr<AlignedAttr>())
- return true;
- QualType VarType = D->getType();
- if (Context.isAlignmentRequired(VarType))
- return true;
-
- if (const auto *RT = VarType->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- for (const FieldDecl *FD : RD->fields()) {
- if (FD->isBitField())
- continue;
- if (FD->hasAttr<AlignedAttr>())
- return true;
- if (Context.isAlignmentRequired(FD->getType()))
- return true;
- }
- }
- }
-
- // Microsoft's link.exe doesn't support alignments greater than 32 bytes for
- // common symbols, so symbols with greater alignment requirements cannot be
- // common.
- // Other COFF linkers (ld.bfd and LLD) support arbitrary power-of-two
- // alignments for common symbols via the aligncomm directive, so this
- // restriction only applies to MSVC environments.
- if (Context.getTargetInfo().getTriple().isKnownWindowsMSVCEnvironment() &&
- Context.getTypeAlignIfKnown(D->getType()) >
- Context.toBits(CharUnits::fromQuantity(32)))
- return true;
-
- return false;
-}
-
-llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(
- const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable) {
- if (Linkage == GVA_Internal)
- return llvm::Function::InternalLinkage;
-
- if (D->hasAttr<WeakAttr>()) {
- if (IsConstantVariable)
- return llvm::GlobalVariable::WeakODRLinkage;
- else
- return llvm::GlobalVariable::WeakAnyLinkage;
- }
-
- if (const auto *FD = D->getAsFunction())
- if (FD->isMultiVersion() && Linkage == GVA_AvailableExternally)
- return llvm::GlobalVariable::LinkOnceAnyLinkage;
-
- // We are guaranteed to have a strong definition somewhere else,
- // so we can use available_externally linkage.
- if (Linkage == GVA_AvailableExternally)
- return llvm::GlobalValue::AvailableExternallyLinkage;
-
- // Note that Apple's kernel linker doesn't support symbol
- // coalescing, so we need to avoid linkonce and weak linkages there.
- // Normally, this means we just map to internal, but for explicit
- // instantiations we'll map to external.
-
- // In C++, the compiler has to emit a definition in every translation unit
- // that references the function. We should use linkonce_odr because
- // a) if all references in this translation unit are optimized away, we
- // don't need to codegen it. b) if the function persists, it needs to be
- // merged with other definitions. c) C++ has the ODR, so we know the
- // definition is dependable.
- if (Linkage == GVA_DiscardableODR)
- return !Context.getLangOpts().AppleKext ? llvm::Function::LinkOnceODRLinkage
- : llvm::Function::InternalLinkage;
-
- // An explicit instantiation of a template has weak linkage, since
- // explicit instantiations can occur in multiple translation units
- // and must all be equivalent. However, we are not allowed to
- // throw away these explicit instantiations.
- //
- // We don't currently support CUDA device code spread out across multiple TUs,
- // so say that CUDA templates are either external (for kernels) or internal.
- // This lets llvm perform aggressive inter-procedural optimizations.
- if (Linkage == GVA_StrongODR) {
- if (Context.getLangOpts().AppleKext)
- return llvm::Function::ExternalLinkage;
- if (Context.getLangOpts().CUDA && Context.getLangOpts().CUDAIsDevice)
- return D->hasAttr<CUDAGlobalAttr>() ? llvm::Function::ExternalLinkage
- : llvm::Function::InternalLinkage;
- return llvm::Function::WeakODRLinkage;
- }
-
- // C++ doesn't have tentative definitions and thus cannot have common
- // linkage.
- if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
- !isVarDeclStrongDefinition(Context, *this, cast<VarDecl>(D),
- CodeGenOpts.NoCommon))
- return llvm::GlobalVariable::CommonLinkage;
-
- // selectany symbols are externally visible, so use weak instead of
- // linkonce. MSVC optimizes away references to const selectany globals, so
- // all definitions should be the same and ODR linkage should be used.
- // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
- if (D->hasAttr<SelectAnyAttr>())
- return llvm::GlobalVariable::WeakODRLinkage;
-
- // Otherwise, we have strong external linkage.
- assert(Linkage == GVA_StrongExternal);
- return llvm::GlobalVariable::ExternalLinkage;
-}
-
-llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageVarDefinition(
- const VarDecl *VD, bool IsConstant) {
- GVALinkage Linkage = getContext().GetGVALinkageForVariable(VD);
- return getLLVMLinkageForDeclarator(VD, Linkage, IsConstant);
-}
-
-/// Replace the uses of a function that was declared with a non-proto type.
-/// We want to silently drop extra arguments from call sites
-static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
- llvm::Function *newFn) {
- // Fast path.
- if (old->use_empty()) return;
-
- llvm::Type *newRetTy = newFn->getReturnType();
- SmallVector<llvm::Value*, 4> newArgs;
- SmallVector<llvm::OperandBundleDef, 1> newBundles;
-
- for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end();
- ui != ue; ) {
- llvm::Value::use_iterator use = ui++; // Increment before the use is erased.
- llvm::User *user = use->getUser();
-
- // Recognize and replace uses of bitcasts. Most calls to
- // unprototyped functions will use bitcasts.
- if (auto *bitcast = dyn_cast<llvm::ConstantExpr>(user)) {
- if (bitcast->getOpcode() == llvm::Instruction::BitCast)
- replaceUsesOfNonProtoConstant(bitcast, newFn);
- continue;
- }
-
- // Recognize calls to the function.
- llvm::CallSite callSite(user);
- if (!callSite) continue;
- if (!callSite.isCallee(&*use)) continue;
-
- // If the return types don't match exactly, then we can't
- // transform this call unless it's dead.
- if (callSite->getType() != newRetTy && !callSite->use_empty())
- continue;
-
- // Get the call site's attribute list.
- SmallVector<llvm::AttributeSet, 8> newArgAttrs;
- llvm::AttributeList oldAttrs = callSite.getAttributes();
-
- // If the function was passed too few arguments, don't transform.
- unsigned newNumArgs = newFn->arg_size();
- if (callSite.arg_size() < newNumArgs) continue;
-
- // If extra arguments were passed, we silently drop them.
- // If any of the types mismatch, we don't transform.
- unsigned argNo = 0;
- bool dontTransform = false;
- for (llvm::Argument &A : newFn->args()) {
- if (callSite.getArgument(argNo)->getType() != A.getType()) {
- dontTransform = true;
- break;
- }
-
- // Add any parameter attributes.
- newArgAttrs.push_back(oldAttrs.getParamAttributes(argNo));
- argNo++;
- }
- if (dontTransform)
- continue;
-
- // Okay, we can transform this. Create the new call instruction and copy
- // over the required information.
- newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo);
-
- // Copy over any operand bundles.
- callSite.getOperandBundlesAsDefs(newBundles);
-
- llvm::CallSite newCall;
- if (callSite.isCall()) {
- newCall = llvm::CallInst::Create(newFn, newArgs, newBundles, "",
- callSite.getInstruction());
- } else {
- auto *oldInvoke = cast<llvm::InvokeInst>(callSite.getInstruction());
- newCall = llvm::InvokeInst::Create(newFn,
- oldInvoke->getNormalDest(),
- oldInvoke->getUnwindDest(),
- newArgs, newBundles, "",
- callSite.getInstruction());
- }
- newArgs.clear(); // for the next iteration
-
- if (!newCall->getType()->isVoidTy())
- newCall->takeName(callSite.getInstruction());
- newCall.setAttributes(llvm::AttributeList::get(
- newFn->getContext(), oldAttrs.getFnAttributes(),
- oldAttrs.getRetAttributes(), newArgAttrs));
- newCall.setCallingConv(callSite.getCallingConv());
-
- // Finally, remove the old call, replacing any uses with the new one.
- if (!callSite->use_empty())
- callSite->replaceAllUsesWith(newCall.getInstruction());
-
- // Copy debug location attached to CI.
- if (callSite->getDebugLoc())
- newCall->setDebugLoc(callSite->getDebugLoc());
-
- callSite->eraseFromParent();
- }
-}
-
-/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we
-/// implement a function with no prototype, e.g. "int foo() {}". If there are
-/// existing call uses of the old function in the module, this adjusts them to
-/// call the new function directly.
-///
-/// This is not just a cleanup: the always_inline pass requires direct calls to
-/// functions to be able to inline them. If there is a bitcast in the way, it
-/// won't inline them. Instcombine normally deletes these calls, but it isn't
-/// run at -O0.
-static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
- llvm::Function *NewFn) {
- // If we're redefining a global as a function, don't transform it.
- if (!isa<llvm::Function>(Old)) return;
-
- replaceUsesOfNonProtoConstant(Old, NewFn);
-}
-
-void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
- auto DK = VD->isThisDeclarationADefinition();
- if (DK == VarDecl::Definition && VD->hasAttr<DLLImportAttr>())
- return;
-
- TemplateSpecializationKind TSK = VD->getTemplateSpecializationKind();
- // If we have a definition, this might be a deferred decl. If the
- // instantiation is explicit, make sure we emit it at the end.
- if (VD->getDefinition() && TSK == TSK_ExplicitInstantiationDefinition)
- GetAddrOfGlobalVar(VD);
-
- EmitTopLevelDecl(VD);
-}
-
-void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
- llvm::GlobalValue *GV) {
- const auto *D = cast<FunctionDecl>(GD.getDecl());
-
- // Compute the function info and LLVM type.
- const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
- llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
-
- // Get or create the prototype for the function.
- if (!GV || (GV->getType()->getElementType() != Ty))
- GV = cast<llvm::GlobalValue>(GetAddrOfFunction(GD, Ty, /*ForVTable=*/false,
- /*DontDefer=*/true,
- ForDefinition));
-
- // Already emitted.
- if (!GV->isDeclaration())
- return;
-
- // We need to set linkage and visibility on the function before
- // generating code for it because various parts of IR generation
- // want to propagate this information down (e.g. to local static
- // declarations).
- auto *Fn = cast<llvm::Function>(GV);
- setFunctionLinkage(GD, Fn);
-
- // FIXME: this is redundant with part of setFunctionDefinitionAttributes
- setGVProperties(Fn, GD);
-
- MaybeHandleStaticInExternC(D, Fn);
-
-
- maybeSetTrivialComdat(*D, *Fn);
-
- CodeGenFunction(*this).GenerateCode(D, Fn, FI);
-
- setNonAliasAttributes(GD, Fn);
- SetLLVMFunctionAttributesForDefinition(D, Fn);
-
- if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
- AddGlobalCtor(Fn, CA->getPriority());
- if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
- AddGlobalDtor(Fn, DA->getPriority());
- if (D->hasAttr<AnnotateAttr>())
- AddGlobalAnnotations(D, Fn);
-}
-
-void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
- const auto *D = cast<ValueDecl>(GD.getDecl());
- const AliasAttr *AA = D->getAttr<AliasAttr>();
- assert(AA && "Not an alias?");
-
- StringRef MangledName = getMangledName(GD);
-
- if (AA->getAliasee() == MangledName) {
- Diags.Report(AA->getLocation(), diag::err_cyclic_alias) << 0;
- return;
- }
-
- // If there is a definition in the module, then it wins over the alias.
- // This is dubious, but allow it to be safe. Just ignore the alias.
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- if (Entry && !Entry->isDeclaration())
- return;
-
- Aliases.push_back(GD);
-
- llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
-
- // Create a reference to the named value. This ensures that it is emitted
- // if a deferred decl.
- llvm::Constant *Aliasee;
- if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD,
- /*ForVTable=*/false);
- else
- Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
- llvm::PointerType::getUnqual(DeclTy),
- /*D=*/nullptr);
-
- // Create the new alias itself, but don't set a name yet.
- auto *GA = llvm::GlobalAlias::create(
- DeclTy, 0, llvm::Function::ExternalLinkage, "", Aliasee, &getModule());
-
- if (Entry) {
- if (GA->getAliasee() == Entry) {
- Diags.Report(AA->getLocation(), diag::err_cyclic_alias) << 0;
- return;
- }
-
- assert(Entry->isDeclaration());
-
- // If there is a declaration in the module, then we had an extern followed
- // by the alias, as in:
- // extern int test6();
- // ...
- // int test6() __attribute__((alias("test7")));
- //
- // Remove it and replace uses of it with the alias.
- GA->takeName(Entry);
-
- Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA,
- Entry->getType()));
- Entry->eraseFromParent();
- } else {
- GA->setName(MangledName);
- }
-
- // Set attributes which are particular to an alias; this is a
- // specialization of the attributes which may be set on a global
- // variable/function.
- if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() ||
- D->isWeakImported()) {
- GA->setLinkage(llvm::Function::WeakAnyLinkage);
- }
-
- if (const auto *VD = dyn_cast<VarDecl>(D))
- if (VD->getTLSKind())
- setTLSMode(GA, *VD);
-
- SetCommonAttributes(GD, GA);
-}
-
-void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) {
- const auto *D = cast<ValueDecl>(GD.getDecl());
- const IFuncAttr *IFA = D->getAttr<IFuncAttr>();
- assert(IFA && "Not an ifunc?");
-
- StringRef MangledName = getMangledName(GD);
-
- if (IFA->getResolver() == MangledName) {
- Diags.Report(IFA->getLocation(), diag::err_cyclic_alias) << 1;
- return;
- }
-
- // Report an error if some definition overrides ifunc.
- llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- if (Entry && !Entry->isDeclaration()) {
- GlobalDecl OtherGD;
- if (lookupRepresentativeDecl(MangledName, OtherGD) &&
- DiagnosedConflictingDefinitions.insert(GD).second) {
- Diags.Report(D->getLocation(), diag::err_duplicate_mangled_name)
- << MangledName;
- Diags.Report(OtherGD.getDecl()->getLocation(),
- diag::note_previous_definition);
- }
- return;
- }
-
- Aliases.push_back(GD);
-
- llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
- llvm::Constant *Resolver =
- GetOrCreateLLVMFunction(IFA->getResolver(), DeclTy, GD,
- /*ForVTable=*/false);
- llvm::GlobalIFunc *GIF =
- llvm::GlobalIFunc::create(DeclTy, 0, llvm::Function::ExternalLinkage,
- "", Resolver, &getModule());
- if (Entry) {
- if (GIF->getResolver() == Entry) {
- Diags.Report(IFA->getLocation(), diag::err_cyclic_alias) << 1;
- return;
- }
- assert(Entry->isDeclaration());
-
- // If there is a declaration in the module, then we had an extern followed
- // by the ifunc, as in:
- // extern int test();
- // ...
- // int test() __attribute__((ifunc("resolver")));
- //
- // Remove it and replace uses of it with the ifunc.
- GIF->takeName(Entry);
-
- Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GIF,
- Entry->getType()));
- Entry->eraseFromParent();
- } else
- GIF->setName(MangledName);
-
- SetCommonAttributes(GD, GIF);
-}
-
-llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,
- ArrayRef<llvm::Type*> Tys) {
- return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID,
- Tys);
-}
-
-static llvm::StringMapEntry<llvm::GlobalVariable *> &
-GetConstantCFStringEntry(llvm::StringMap<llvm::GlobalVariable *> &Map,
- const StringLiteral *Literal, bool TargetIsLSB,
- bool &IsUTF16, unsigned &StringLength) {
- StringRef String = Literal->getString();
- unsigned NumBytes = String.size();
-
- // Check for simple case.
- if (!Literal->containsNonAsciiOrNull()) {
- StringLength = NumBytes;
- return *Map.insert(std::make_pair(String, nullptr)).first;
- }
-
- // Otherwise, convert the UTF8 literals into a string of shorts.
- IsUTF16 = true;
-
- SmallVector<llvm::UTF16, 128> ToBuf(NumBytes + 1); // +1 for ending nulls.
- const llvm::UTF8 *FromPtr = (const llvm::UTF8 *)String.data();
- llvm::UTF16 *ToPtr = &ToBuf[0];
-
- (void)llvm::ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, &ToPtr,
- ToPtr + NumBytes, llvm::strictConversion);
-
- // ConvertUTF8toUTF16 returns the length in ToPtr.
- StringLength = ToPtr - &ToBuf[0];
-
- // Add an explicit null.
- *ToPtr = 0;
- return *Map.insert(std::make_pair(
- StringRef(reinterpret_cast<const char *>(ToBuf.data()),
- (StringLength + 1) * 2),
- nullptr)).first;
-}
-
-ConstantAddress
-CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
- unsigned StringLength = 0;
- bool isUTF16 = false;
- llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
- GetConstantCFStringEntry(CFConstantStringMap, Literal,
- getDataLayout().isLittleEndian(), isUTF16,
- StringLength);
-
- if (auto *C = Entry.second)
- return ConstantAddress(C, CharUnits::fromQuantity(C->getAlignment()));
-
- llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty);
- llvm::Constant *Zeros[] = { Zero, Zero };
-
- const ASTContext &Context = getContext();
- const llvm::Triple &Triple = getTriple();
-
- const auto CFRuntime = getLangOpts().CFRuntime;
- const bool IsSwiftABI =
- static_cast<unsigned>(CFRuntime) >=
- static_cast<unsigned>(LangOptions::CoreFoundationABI::Swift);
- const bool IsSwift4_1 = CFRuntime == LangOptions::CoreFoundationABI::Swift4_1;
-
- // If we don't already have it, get __CFConstantStringClassReference.
- if (!CFConstantStringClassRef) {
- const char *CFConstantStringClassName = "__CFConstantStringClassReference";
- llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
- Ty = llvm::ArrayType::get(Ty, 0);
-
- switch (CFRuntime) {
- default: break;
- case LangOptions::CoreFoundationABI::Swift: LLVM_FALLTHROUGH;
- case LangOptions::CoreFoundationABI::Swift5_0:
- CFConstantStringClassName =
- Triple.isOSDarwin() ? "$s15SwiftFoundation19_NSCFConstantStringCN"
- : "$s10Foundation19_NSCFConstantStringCN";
- Ty = IntPtrTy;
- break;
- case LangOptions::CoreFoundationABI::Swift4_2:
- CFConstantStringClassName =
- Triple.isOSDarwin() ? "$S15SwiftFoundation19_NSCFConstantStringCN"
- : "$S10Foundation19_NSCFConstantStringCN";
- Ty = IntPtrTy;
- break;
- case LangOptions::CoreFoundationABI::Swift4_1:
- CFConstantStringClassName =
- Triple.isOSDarwin() ? "__T015SwiftFoundation19_NSCFConstantStringCN"
- : "__T010Foundation19_NSCFConstantStringCN";
- Ty = IntPtrTy;
- break;
- }
-
- llvm::Constant *C = CreateRuntimeVariable(Ty, CFConstantStringClassName);
-
- if (Triple.isOSBinFormatELF() || Triple.isOSBinFormatCOFF()) {
- llvm::GlobalValue *GV = nullptr;
-
- if ((GV = dyn_cast<llvm::GlobalValue>(C))) {
- IdentifierInfo &II = Context.Idents.get(GV->getName());
- TranslationUnitDecl *TUDecl = Context.getTranslationUnitDecl();
- DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
-
- const VarDecl *VD = nullptr;
- for (const auto &Result : DC->lookup(&II))
- if ((VD = dyn_cast<VarDecl>(Result)))
- break;
-
- if (Triple.isOSBinFormatELF()) {
- if (!VD)
- GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- } else {
- GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- if (!VD || !VD->hasAttr<DLLExportAttr>())
- GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- else
- GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- }
-
- setDSOLocal(GV);
- }
- }
-
- // Decay array -> ptr
- CFConstantStringClassRef =
- IsSwiftABI ? llvm::ConstantExpr::getPtrToInt(C, Ty)
- : llvm::ConstantExpr::getGetElementPtr(Ty, C, Zeros);
- }
-
- QualType CFTy = Context.getCFConstantStringType();
-
- auto *STy = cast<llvm::StructType>(getTypes().ConvertType(CFTy));
-
- ConstantInitBuilder Builder(*this);
- auto Fields = Builder.beginStruct(STy);
-
- // Class pointer.
- Fields.add(cast<llvm::ConstantExpr>(CFConstantStringClassRef));
-
- // Flags.
- if (IsSwiftABI) {
- Fields.addInt(IntPtrTy, IsSwift4_1 ? 0x05 : 0x01);
- Fields.addInt(Int64Ty, isUTF16 ? 0x07d0 : 0x07c8);
- } else {
- Fields.addInt(IntTy, isUTF16 ? 0x07d0 : 0x07C8);
- }
-
- // String pointer.
- llvm::Constant *C = nullptr;
- if (isUTF16) {
- auto Arr = llvm::makeArrayRef(
- reinterpret_cast<uint16_t *>(const_cast<char *>(Entry.first().data())),
- Entry.first().size() / 2);
- C = llvm::ConstantDataArray::get(VMContext, Arr);
- } else {
- C = llvm::ConstantDataArray::getString(VMContext, Entry.first());
- }
-
- // Note: -fwritable-strings doesn't make the backing store strings of
- // CFStrings writable. (See <rdar://problem/10657500>)
- auto *GV =
- new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, C, ".str");
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- // Don't enforce the target's minimum global alignment, since the only use
- // of the string is via this class initializer.
- CharUnits Align = isUTF16 ? Context.getTypeAlignInChars(Context.ShortTy)
- : Context.getTypeAlignInChars(Context.CharTy);
- GV->setAlignment(Align.getQuantity());
-
- // FIXME: We set the section explicitly to avoid a bug in ld64 224.1.
- // Without it LLVM can merge the string with a non unnamed_addr one during
- // LTO. Doing that changes the section it ends in, which surprises ld64.
- if (Triple.isOSBinFormatMachO())
- GV->setSection(isUTF16 ? "__TEXT,__ustring"
- : "__TEXT,__cstring,cstring_literals");
- // Make sure the literal ends up in .rodata to allow for safe ICF and for
- // the static linker to adjust permissions to read-only later on.
- else if (Triple.isOSBinFormatELF())
- GV->setSection(".rodata");
-
- // String.
- llvm::Constant *Str =
- llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros);
-
- if (isUTF16)
- // Cast the UTF16 string to the correct type.
- Str = llvm::ConstantExpr::getBitCast(Str, Int8PtrTy);
- Fields.add(Str);
-
- // String length.
- llvm::IntegerType *LengthTy =
- llvm::IntegerType::get(getModule().getContext(),
- Context.getTargetInfo().getLongWidth());
- if (IsSwiftABI) {
- if (CFRuntime == LangOptions::CoreFoundationABI::Swift4_1 ||
- CFRuntime == LangOptions::CoreFoundationABI::Swift4_2)
- LengthTy = Int32Ty;
- else
- LengthTy = IntPtrTy;
- }
- Fields.addInt(LengthTy, StringLength);
-
- CharUnits Alignment = getPointerAlign();
-
- // The struct.
- GV = Fields.finishAndCreateGlobal("_unnamed_cfstring_", Alignment,
- /*isConstant=*/false,
- llvm::GlobalVariable::PrivateLinkage);
- switch (Triple.getObjectFormat()) {
- case llvm::Triple::UnknownObjectFormat:
- llvm_unreachable("unknown file format");
- case llvm::Triple::COFF:
- case llvm::Triple::ELF:
- case llvm::Triple::Wasm:
- GV->setSection("cfstring");
- break;
- case llvm::Triple::MachO:
- GV->setSection("__DATA,__cfstring");
- break;
- }
- Entry.second = GV;
-
- return ConstantAddress(GV, Alignment);
-}
-
-bool CodeGenModule::getExpressionLocationsEnabled() const {
- return !CodeGenOpts.EmitCodeView || CodeGenOpts.DebugColumnInfo;
-}
-
-QualType CodeGenModule::getObjCFastEnumerationStateType() {
- if (ObjCFastEnumerationStateType.isNull()) {
- RecordDecl *D = Context.buildImplicitRecord("__objcFastEnumerationState");
- D->startDefinition();
-
- QualType FieldTypes[] = {
- Context.UnsignedLongTy,
- Context.getPointerType(Context.getObjCIdType()),
- Context.getPointerType(Context.UnsignedLongTy),
- Context.getConstantArrayType(Context.UnsignedLongTy,
- llvm::APInt(32, 5), ArrayType::Normal, 0)
- };
-
- for (size_t i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(Context,
- D,
- SourceLocation(),
- SourceLocation(), nullptr,
- FieldTypes[i], /*TInfo=*/nullptr,
- /*BitWidth=*/nullptr,
- /*Mutable=*/false,
- ICIS_NoInit);
- Field->setAccess(AS_public);
- D->addDecl(Field);
- }
-
- D->completeDefinition();
- ObjCFastEnumerationStateType = Context.getTagDeclType(D);
- }
-
- return ObjCFastEnumerationStateType;
-}
-
-llvm::Constant *
-CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) {
- assert(!E->getType()->isPointerType() && "Strings are always arrays");
-
- // Don't emit it as the address of the string, emit the string data itself
- // as an inline array.
- if (E->getCharByteWidth() == 1) {
- SmallString<64> Str(E->getString());
-
- // Resize the string to the right size, which is indicated by its type.
- const ConstantArrayType *CAT = Context.getAsConstantArrayType(E->getType());
- Str.resize(CAT->getSize().getZExtValue());
- return llvm::ConstantDataArray::getString(VMContext, Str, false);
- }
-
- auto *AType = cast<llvm::ArrayType>(getTypes().ConvertType(E->getType()));
- llvm::Type *ElemTy = AType->getElementType();
- unsigned NumElements = AType->getNumElements();
-
- // Wide strings have either 2-byte or 4-byte elements.
- if (ElemTy->getPrimitiveSizeInBits() == 16) {
- SmallVector<uint16_t, 32> Elements;
- Elements.reserve(NumElements);
-
- for(unsigned i = 0, e = E->getLength(); i != e; ++i)
- Elements.push_back(E->getCodeUnit(i));
- Elements.resize(NumElements);
- return llvm::ConstantDataArray::get(VMContext, Elements);
- }
-
- assert(ElemTy->getPrimitiveSizeInBits() == 32);
- SmallVector<uint32_t, 32> Elements;
- Elements.reserve(NumElements);
-
- for(unsigned i = 0, e = E->getLength(); i != e; ++i)
- Elements.push_back(E->getCodeUnit(i));
- Elements.resize(NumElements);
- return llvm::ConstantDataArray::get(VMContext, Elements);
-}
-
-static llvm::GlobalVariable *
-GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
- CodeGenModule &CGM, StringRef GlobalName,
- CharUnits Alignment) {
- unsigned AddrSpace = CGM.getContext().getTargetAddressSpace(
- CGM.getStringLiteralAddressSpace());
-
- llvm::Module &M = CGM.getModule();
- // Create a global variable for this string
- auto *GV = new llvm::GlobalVariable(
- M, C->getType(), !CGM.getLangOpts().WritableStrings, LT, C, GlobalName,
- nullptr, llvm::GlobalVariable::NotThreadLocal, AddrSpace);
- GV->setAlignment(Alignment.getQuantity());
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- if (GV->isWeakForLinker()) {
- assert(CGM.supportsCOMDAT() && "Only COFF uses weak string literals");
- GV->setComdat(M.getOrInsertComdat(GV->getName()));
- }
- CGM.setDSOLocal(GV);
-
- return GV;
-}
-
-/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
-/// constant array for the given string literal.
-ConstantAddress
-CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
- StringRef Name) {
- CharUnits Alignment = getContext().getAlignOfGlobalVarInChars(S->getType());
-
- llvm::Constant *C = GetConstantArrayFromStringLiteral(S);
- llvm::GlobalVariable **Entry = nullptr;
- if (!LangOpts.WritableStrings) {
- Entry = &ConstantStringMap[C];
- if (auto GV = *Entry) {
- if (Alignment.getQuantity() > GV->getAlignment())
- GV->setAlignment(Alignment.getQuantity());
- return ConstantAddress(GV, Alignment);
- }
- }
-
- SmallString<256> MangledNameBuffer;
- StringRef GlobalVariableName;
- llvm::GlobalValue::LinkageTypes LT;
-
- // Mangle the string literal if that's how the ABI merges duplicate strings.
- // Don't do it if they are writable, since we don't want writes in one TU to
- // affect strings in another.
- if (getCXXABI().getMangleContext().shouldMangleStringLiteral(S) &&
- !LangOpts.WritableStrings) {
- llvm::raw_svector_ostream Out(MangledNameBuffer);
- getCXXABI().getMangleContext().mangleStringLiteral(S, Out);
- LT = llvm::GlobalValue::LinkOnceODRLinkage;
- GlobalVariableName = MangledNameBuffer;
- } else {
- LT = llvm::GlobalValue::PrivateLinkage;
- GlobalVariableName = Name;
- }
-
- auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment);
- if (Entry)
- *Entry = GV;
-
- SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>",
- QualType());
-
- return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
- Alignment);
-}
-
-/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
-/// array for the given ObjCEncodeExpr node.
-ConstantAddress
-CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
- std::string Str;
- getContext().getObjCEncodingForType(E->getEncodedType(), Str);
-
- return GetAddrOfConstantCString(Str);
-}
-
-/// GetAddrOfConstantCString - Returns a pointer to a character array containing
-/// the literal and a terminating '\0' character.
-/// The result has pointer to array type.
-ConstantAddress CodeGenModule::GetAddrOfConstantCString(
- const std::string &Str, const char *GlobalName) {
- StringRef StrWithNull(Str.c_str(), Str.size() + 1);
- CharUnits Alignment =
- getContext().getAlignOfGlobalVarInChars(getContext().CharTy);
-
- llvm::Constant *C =
- llvm::ConstantDataArray::getString(getLLVMContext(), StrWithNull, false);
-
- // Don't share any string literals if strings aren't constant.
- llvm::GlobalVariable **Entry = nullptr;
- if (!LangOpts.WritableStrings) {
- Entry = &ConstantStringMap[C];
- if (auto GV = *Entry) {
- if (Alignment.getQuantity() > GV->getAlignment())
- GV->setAlignment(Alignment.getQuantity());
- return ConstantAddress(GV, Alignment);
- }
- }
-
- // Get the default prefix if a name wasn't specified.
- if (!GlobalName)
- GlobalName = ".str";
- // Create a global variable for this.
- auto GV = GenerateStringLiteral(C, llvm::GlobalValue::PrivateLinkage, *this,
- GlobalName, Alignment);
- if (Entry)
- *Entry = GV;
-
- return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
- Alignment);
-}
-
-ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
- const MaterializeTemporaryExpr *E, const Expr *Init) {
- assert((E->getStorageDuration() == SD_Static ||
- E->getStorageDuration() == SD_Thread) && "not a global temporary");
- const auto *VD = cast<VarDecl>(E->getExtendingDecl());
-
- // If we're not materializing a subobject of the temporary, keep the
- // cv-qualifiers from the type of the MaterializeTemporaryExpr.
- QualType MaterializedType = Init->getType();
- if (Init == E->GetTemporaryExpr())
- MaterializedType = E->getType();
-
- CharUnits Align = getContext().getTypeAlignInChars(MaterializedType);
-
- if (llvm::Constant *Slot = MaterializedGlobalTemporaryMap[E])
- return ConstantAddress(Slot, Align);
-
- // FIXME: If an externally-visible declaration extends multiple temporaries,
- // we need to give each temporary the same name in every translation unit (and
- // we also need to make the temporaries externally-visible).
- SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- getCXXABI().getMangleContext().mangleReferenceTemporary(
- VD, E->getManglingNumber(), Out);
-
- APValue *Value = nullptr;
- if (E->getStorageDuration() == SD_Static) {
- // We might have a cached constant initializer for this temporary. Note
- // that this might have a different value from the value computed by
- // evaluating the initializer if the surrounding constant expression
- // modifies the temporary.
- Value = getContext().getMaterializedTemporaryValue(E, false);
- if (Value && Value->isUninit())
- Value = nullptr;
- }
-
- // Try evaluating it now, it might have a constant initializer.
- Expr::EvalResult EvalResult;
- if (!Value && Init->EvaluateAsRValue(EvalResult, getContext()) &&
- !EvalResult.hasSideEffects())
- Value = &EvalResult.Val;
-
- LangAS AddrSpace =
- VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace();
-
- Optional<ConstantEmitter> emitter;
- llvm::Constant *InitialValue = nullptr;
- bool Constant = false;
- llvm::Type *Type;
- if (Value) {
- // The temporary has a constant initializer, use it.
- emitter.emplace(*this);
- InitialValue = emitter->emitForInitializer(*Value, AddrSpace,
- MaterializedType);
- Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value);
- Type = InitialValue->getType();
- } else {
- // No initializer, the initialization will be provided when we
- // initialize the declaration which performed lifetime extension.
- Type = getTypes().ConvertTypeForMem(MaterializedType);
- }
-
- // Create a global variable for this lifetime-extended temporary.
- llvm::GlobalValue::LinkageTypes Linkage =
- getLLVMLinkageVarDefinition(VD, Constant);
- if (Linkage == llvm::GlobalVariable::ExternalLinkage) {
- const VarDecl *InitVD;
- if (VD->isStaticDataMember() && VD->getAnyInitializer(InitVD) &&
- isa<CXXRecordDecl>(InitVD->getLexicalDeclContext())) {
- // Temporaries defined inside a class get linkonce_odr linkage because the
- // class can be defined in multiple translation units.
- Linkage = llvm::GlobalVariable::LinkOnceODRLinkage;
- } else {
- // There is no need for this temporary to have external linkage if the
- // VarDecl has external linkage.
- Linkage = llvm::GlobalVariable::InternalLinkage;
- }
- }
- auto TargetAS = getContext().getTargetAddressSpace(AddrSpace);
- auto *GV = new llvm::GlobalVariable(
- getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
- /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
- if (emitter) emitter->finalize(GV);
- setGVProperties(GV, VD);
- GV->setAlignment(Align.getQuantity());
- if (supportsCOMDAT() && GV->isWeakForLinker())
- GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
- if (VD->getTLSKind())
- setTLSMode(GV, *VD);
- llvm::Constant *CV = GV;
- if (AddrSpace != LangAS::Default)
- CV = getTargetCodeGenInfo().performAddrSpaceCast(
- *this, GV, AddrSpace, LangAS::Default,
- Type->getPointerTo(
- getContext().getTargetAddressSpace(LangAS::Default)));
- MaterializedGlobalTemporaryMap[E] = CV;
- return ConstantAddress(CV, Align);
-}
-
-/// EmitObjCPropertyImplementations - Emit information for synthesized
-/// properties for an implementation.
-void CodeGenModule::EmitObjCPropertyImplementations(const
- ObjCImplementationDecl *D) {
- for (const auto *PID : D->property_impls()) {
- // Dynamic is just for type-checking.
- if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
- ObjCPropertyDecl *PD = PID->getPropertyDecl();
-
- // Determine which methods need to be implemented, some may have
- // been overridden. Note that ::isPropertyAccessor is not the method
- // we want, that just indicates if the decl came from a
- // property. What we want to know is if the method is defined in
- // this implementation.
- if (!D->getInstanceMethod(PD->getGetterName()))
- CodeGenFunction(*this).GenerateObjCGetter(
- const_cast<ObjCImplementationDecl *>(D), PID);
- if (!PD->isReadOnly() &&
- !D->getInstanceMethod(PD->getSetterName()))
- CodeGenFunction(*this).GenerateObjCSetter(
- const_cast<ObjCImplementationDecl *>(D), PID);
- }
- }
-}
-
-static bool needsDestructMethod(ObjCImplementationDecl *impl) {
- const ObjCInterfaceDecl *iface = impl->getClassInterface();
- for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
- ivar; ivar = ivar->getNextIvar())
- if (ivar->getType().isDestructedType())
- return true;
-
- return false;
-}
-
-static bool AllTrivialInitializers(CodeGenModule &CGM,
- ObjCImplementationDecl *D) {
- CodeGenFunction CGF(CGM);
- for (ObjCImplementationDecl::init_iterator B = D->init_begin(),
- E = D->init_end(); B != E; ++B) {
- CXXCtorInitializer *CtorInitExp = *B;
- Expr *Init = CtorInitExp->getInit();
- if (!CGF.isTrivialInitializer(Init))
- return false;
- }
- return true;
-}
-
-/// EmitObjCIvarInitializations - Emit information for ivar initialization
-/// for an implementation.
-void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
- // We might need a .cxx_destruct even if we don't have any ivar initializers.
- if (needsDestructMethod(D)) {
- IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
- Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
- ObjCMethodDecl *DTORMethod =
- ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
- cxxSelector, getContext().VoidTy, nullptr, D,
- /*isInstance=*/true, /*isVariadic=*/false,
- /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false, ObjCMethodDecl::Required);
- D->addInstanceMethod(DTORMethod);
- CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
- D->setHasDestructors(true);
- }
-
- // If the implementation doesn't have any ivar initializers, we don't need
- // a .cxx_construct.
- if (D->getNumIvarInitializers() == 0 ||
- AllTrivialInitializers(*this, D))
- return;
-
- IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
- Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
- // The constructor returns 'self'.
- ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
- D->getLocation(),
- D->getLocation(),
- cxxSelector,
- getContext().getObjCIdType(),
- nullptr, D, /*isInstance=*/true,
- /*isVariadic=*/false,
- /*isPropertyAccessor=*/true,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false,
- ObjCMethodDecl::Required);
- D->addInstanceMethod(CTORMethod);
- CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
- D->setHasNonZeroConstructors(true);
-}
-
-// EmitLinkageSpec - Emit all declarations in a linkage spec.
-void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
- if (LSD->getLanguage() != LinkageSpecDecl::lang_c &&
- LSD->getLanguage() != LinkageSpecDecl::lang_cxx) {
- ErrorUnsupported(LSD, "linkage spec");
- return;
- }
-
- EmitDeclContext(LSD);
-}
-
-void CodeGenModule::EmitDeclContext(const DeclContext *DC) {
- for (auto *I : DC->decls()) {
- // Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope
- // are themselves considered "top-level", so EmitTopLevelDecl on an
- // ObjCImplDecl does not recursively visit them. We need to do that in
- // case they're nested inside another construct (LinkageSpecDecl /
- // ExportDecl) that does stop them from being considered "top-level".
- if (auto *OID = dyn_cast<ObjCImplDecl>(I)) {
- for (auto *M : OID->methods())
- EmitTopLevelDecl(M);
- }
-
- EmitTopLevelDecl(I);
- }
-}
-
-/// EmitTopLevelDecl - Emit code for a single top level declaration.
-void CodeGenModule::EmitTopLevelDecl(Decl *D) {
- // Ignore dependent declarations.
- if (D->isTemplated())
- return;
-
- switch (D->getKind()) {
- case Decl::CXXConversion:
- case Decl::CXXMethod:
- case Decl::Function:
- EmitGlobal(cast<FunctionDecl>(D));
- // Always provide some coverage mapping
- // even for the functions that aren't emitted.
- AddDeferredUnusedCoverageMapping(D);
- break;
-
- case Decl::CXXDeductionGuide:
- // Function-like, but does not result in code emission.
- break;
-
- case Decl::Var:
- case Decl::Decomposition:
- case Decl::VarTemplateSpecialization:
- EmitGlobal(cast<VarDecl>(D));
- if (auto *DD = dyn_cast<DecompositionDecl>(D))
- for (auto *B : DD->bindings())
- if (auto *HD = B->getHoldingVar())
- EmitGlobal(HD);
- break;
-
- // Indirect fields from global anonymous structs and unions can be
- // ignored; only the actual variable requires IR gen support.
- case Decl::IndirectField:
- break;
-
- // C++ Decls
- case Decl::Namespace:
- EmitDeclContext(cast<NamespaceDecl>(D));
- break;
- case Decl::ClassTemplateSpecialization: {
- const auto *Spec = cast<ClassTemplateSpecializationDecl>(D);
- if (DebugInfo &&
- Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition &&
- Spec->hasDefinition())
- DebugInfo->completeTemplateDefinition(*Spec);
- } LLVM_FALLTHROUGH;
- case Decl::CXXRecord:
- if (DebugInfo) {
- if (auto *ES = D->getASTContext().getExternalSource())
- if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
- DebugInfo->completeUnusedClass(cast<CXXRecordDecl>(*D));
- }
- // Emit any static data members, they may be definitions.
- for (auto *I : cast<CXXRecordDecl>(D)->decls())
- if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
- EmitTopLevelDecl(I);
- break;
- // No code generation needed.
- case Decl::UsingShadow:
- case Decl::ClassTemplate:
- case Decl::VarTemplate:
- case Decl::VarTemplatePartialSpecialization:
- case Decl::FunctionTemplate:
- case Decl::TypeAliasTemplate:
- case Decl::Block:
- case Decl::Empty:
- case Decl::Binding:
- break;
- case Decl::Using: // using X; [C++]
- if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->EmitUsingDecl(cast<UsingDecl>(*D));
- return;
- case Decl::NamespaceAlias:
- if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->EmitNamespaceAlias(cast<NamespaceAliasDecl>(*D));
- return;
- case Decl::UsingDirective: // using namespace X; [C++]
- if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->EmitUsingDirective(cast<UsingDirectiveDecl>(*D));
- return;
- case Decl::CXXConstructor:
- getCXXABI().EmitCXXConstructors(cast<CXXConstructorDecl>(D));
- break;
- case Decl::CXXDestructor:
- getCXXABI().EmitCXXDestructors(cast<CXXDestructorDecl>(D));
- break;
-
- case Decl::StaticAssert:
- // Nothing to do.
- break;
-
- // Objective-C Decls
-
- // Forward declarations, no (immediate) code generation.
- case Decl::ObjCInterface:
- case Decl::ObjCCategory:
- break;
-
- case Decl::ObjCProtocol: {
- auto *Proto = cast<ObjCProtocolDecl>(D);
- if (Proto->isThisDeclarationADefinition())
- ObjCRuntime->GenerateProtocol(Proto);
- break;
- }
-
- case Decl::ObjCCategoryImpl:
- // Categories have properties but don't support synthesize so we
- // can ignore them here.
- ObjCRuntime->GenerateCategory(cast<ObjCCategoryImplDecl>(D));
- break;
-
- case Decl::ObjCImplementation: {
- auto *OMD = cast<ObjCImplementationDecl>(D);
- EmitObjCPropertyImplementations(OMD);
- EmitObjCIvarInitializations(OMD);
- ObjCRuntime->GenerateClass(OMD);
- // Emit global variable debug information.
- if (CGDebugInfo *DI = getModuleDebugInfo())
- if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo)
- DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType(
- OMD->getClassInterface()), OMD->getLocation());
- break;
- }
- case Decl::ObjCMethod: {
- auto *OMD = cast<ObjCMethodDecl>(D);
- // If this is not a prototype, emit the body.
- if (OMD->getBody())
- CodeGenFunction(*this).GenerateObjCMethod(OMD);
- break;
- }
- case Decl::ObjCCompatibleAlias:
- ObjCRuntime->RegisterAlias(cast<ObjCCompatibleAliasDecl>(D));
- break;
-
- case Decl::PragmaComment: {
- const auto *PCD = cast<PragmaCommentDecl>(D);
- switch (PCD->getCommentKind()) {
- case PCK_Unknown:
- llvm_unreachable("unexpected pragma comment kind");
- case PCK_Linker:
- AppendLinkerOptions(PCD->getArg());
- break;
- case PCK_Lib:
- if (getTarget().getTriple().isOSBinFormatELF() &&
- !getTarget().getTriple().isPS4())
- AddELFLibDirective(PCD->getArg());
- else
- AddDependentLib(PCD->getArg());
- break;
- case PCK_Compiler:
- case PCK_ExeStr:
- case PCK_User:
- break; // We ignore all of these.
- }
- break;
- }
-
- case Decl::PragmaDetectMismatch: {
- const auto *PDMD = cast<PragmaDetectMismatchDecl>(D);
- AddDetectMismatch(PDMD->getName(), PDMD->getValue());
- break;
- }
-
- case Decl::LinkageSpec:
- EmitLinkageSpec(cast<LinkageSpecDecl>(D));
- break;
-
- case Decl::FileScopeAsm: {
- // File-scope asm is ignored during device-side CUDA compilation.
- if (LangOpts.CUDA && LangOpts.CUDAIsDevice)
- break;
- // File-scope asm is ignored during device-side OpenMP compilation.
- if (LangOpts.OpenMPIsDevice)
- break;
- auto *AD = cast<FileScopeAsmDecl>(D);
- getModule().appendModuleInlineAsm(AD->getAsmString()->getString());
- break;
- }
-
- case Decl::Import: {
- auto *Import = cast<ImportDecl>(D);
-
- // If we've already imported this module, we're done.
- if (!ImportedModules.insert(Import->getImportedModule()))
- break;
-
- // Emit debug information for direct imports.
- if (!Import->getImportedOwningModule()) {
- if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->EmitImportDecl(*Import);
- }
-
- // Find all of the submodules and emit the module initializers.
- llvm::SmallPtrSet<clang::Module *, 16> Visited;
- SmallVector<clang::Module *, 16> Stack;
- Visited.insert(Import->getImportedModule());
- Stack.push_back(Import->getImportedModule());
-
- while (!Stack.empty()) {
- clang::Module *Mod = Stack.pop_back_val();
- if (!EmittedModuleInitializers.insert(Mod).second)
- continue;
-
- for (auto *D : Context.getModuleInitializers(Mod))
- EmitTopLevelDecl(D);
-
- // Visit the submodules of this module.
- for (clang::Module::submodule_iterator Sub = Mod->submodule_begin(),
- SubEnd = Mod->submodule_end();
- Sub != SubEnd; ++Sub) {
- // Skip explicit children; they need to be explicitly imported to emit
- // the initializers.
- if ((*Sub)->IsExplicit)
- continue;
-
- if (Visited.insert(*Sub).second)
- Stack.push_back(*Sub);
- }
- }
- break;
- }
-
- case Decl::Export:
- EmitDeclContext(cast<ExportDecl>(D));
- break;
-
- case Decl::OMPThreadPrivate:
- EmitOMPThreadPrivateDecl(cast<OMPThreadPrivateDecl>(D));
- break;
-
- case Decl::OMPDeclareReduction:
- EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(D));
- break;
-
- case Decl::OMPRequires:
- EmitOMPRequiresDecl(cast<OMPRequiresDecl>(D));
- break;
-
- default:
- // Make sure we handled everything we should, every other kind is a
- // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
- // function. Need to recode Decl::Kind to do that easily.
- assert(isa<TypeDecl>(D) && "Unsupported decl kind");
- break;
- }
-}
-
-void CodeGenModule::AddDeferredUnusedCoverageMapping(Decl *D) {
- // Do we need to generate coverage mapping?
- if (!CodeGenOpts.CoverageMapping)
- return;
- switch (D->getKind()) {
- case Decl::CXXConversion:
- case Decl::CXXMethod:
- case Decl::Function:
- case Decl::ObjCMethod:
- case Decl::CXXConstructor:
- case Decl::CXXDestructor: {
- if (!cast<FunctionDecl>(D)->doesThisDeclarationHaveABody())
- return;
- SourceManager &SM = getContext().getSourceManager();
- if (LimitedCoverage && SM.getMainFileID() != SM.getFileID(D->getBeginLoc()))
- return;
- auto I = DeferredEmptyCoverageMappingDecls.find(D);
- if (I == DeferredEmptyCoverageMappingDecls.end())
- DeferredEmptyCoverageMappingDecls[D] = true;
- break;
- }
- default:
- break;
- };
-}
-
-void CodeGenModule::ClearUnusedCoverageMapping(const Decl *D) {
- // Do we need to generate coverage mapping?
- if (!CodeGenOpts.CoverageMapping)
- return;
- if (const auto *Fn = dyn_cast<FunctionDecl>(D)) {
- if (Fn->isTemplateInstantiation())
- ClearUnusedCoverageMapping(Fn->getTemplateInstantiationPattern());
- }
- auto I = DeferredEmptyCoverageMappingDecls.find(D);
- if (I == DeferredEmptyCoverageMappingDecls.end())
- DeferredEmptyCoverageMappingDecls[D] = false;
- else
- I->second = false;
-}
-
-void CodeGenModule::EmitDeferredUnusedCoverageMappings() {
- // We call takeVector() here to avoid use-after-free.
- // FIXME: DeferredEmptyCoverageMappingDecls is getting mutated because
- // we deserialize function bodies to emit coverage info for them, and that
- // deserializes more declarations. How should we handle that case?
- for (const auto &Entry : DeferredEmptyCoverageMappingDecls.takeVector()) {
- if (!Entry.second)
- continue;
- const Decl *D = Entry.first;
- switch (D->getKind()) {
- case Decl::CXXConversion:
- case Decl::CXXMethod:
- case Decl::Function:
- case Decl::ObjCMethod: {
- CodeGenPGO PGO(*this);
- GlobalDecl GD(cast<FunctionDecl>(D));
- PGO.emitEmptyCounterMapping(D, getMangledName(GD),
- getFunctionLinkage(GD));
- break;
- }
- case Decl::CXXConstructor: {
- CodeGenPGO PGO(*this);
- GlobalDecl GD(cast<CXXConstructorDecl>(D), Ctor_Base);
- PGO.emitEmptyCounterMapping(D, getMangledName(GD),
- getFunctionLinkage(GD));
- break;
- }
- case Decl::CXXDestructor: {
- CodeGenPGO PGO(*this);
- GlobalDecl GD(cast<CXXDestructorDecl>(D), Dtor_Base);
- PGO.emitEmptyCounterMapping(D, getMangledName(GD),
- getFunctionLinkage(GD));
- break;
- }
- default:
- break;
- };
- }
-}
-
-/// Turns the given pointer into a constant.
-static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context,
- const void *Ptr) {
- uintptr_t PtrInt = reinterpret_cast<uintptr_t>(Ptr);
- llvm::Type *i64 = llvm::Type::getInt64Ty(Context);
- return llvm::ConstantInt::get(i64, PtrInt);
-}
-
-static void EmitGlobalDeclMetadata(CodeGenModule &CGM,
- llvm::NamedMDNode *&GlobalMetadata,
- GlobalDecl D,
- llvm::GlobalValue *Addr) {
- if (!GlobalMetadata)
- GlobalMetadata =
- CGM.getModule().getOrInsertNamedMetadata("clang.global.decl.ptrs");
-
- // TODO: should we report variant information for ctors/dtors?
- llvm::Metadata *Ops[] = {llvm::ConstantAsMetadata::get(Addr),
- llvm::ConstantAsMetadata::get(GetPointerConstant(
- CGM.getLLVMContext(), D.getDecl()))};
- GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops));
-}
-
-/// For each function which is declared within an extern "C" region and marked
-/// as 'used', but has internal linkage, create an alias from the unmangled
-/// name to the mangled name if possible. People expect to be able to refer
-/// to such functions with an unmangled name from inline assembly within the
-/// same translation unit.
-void CodeGenModule::EmitStaticExternCAliases() {
- if (!getTargetCodeGenInfo().shouldEmitStaticExternCAliases())
- return;
- for (auto &I : StaticExternCValues) {
- IdentifierInfo *Name = I.first;
- llvm::GlobalValue *Val = I.second;
- if (Val && !getModule().getNamedValue(Name->getName()))
- addUsedGlobal(llvm::GlobalAlias::create(Name->getName(), Val));
- }
-}
-
-bool CodeGenModule::lookupRepresentativeDecl(StringRef MangledName,
- GlobalDecl &Result) const {
- auto Res = Manglings.find(MangledName);
- if (Res == Manglings.end())
- return false;
- Result = Res->getValue();
- return true;
-}
-
-/// Emits metadata nodes associating all the global values in the
-/// current module with the Decls they came from. This is useful for
-/// projects using IR gen as a subroutine.
-///
-/// Since there's currently no way to associate an MDNode directly
-/// with an llvm::GlobalValue, we create a global named metadata
-/// with the name 'clang.global.decl.ptrs'.
-void CodeGenModule::EmitDeclMetadata() {
- llvm::NamedMDNode *GlobalMetadata = nullptr;
-
- for (auto &I : MangledDeclNames) {
- llvm::GlobalValue *Addr = getModule().getNamedValue(I.second);
- // Some mangled names don't necessarily have an associated GlobalValue
- // in this module, e.g. if we mangled it for DebugInfo.
- if (Addr)
- EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr);
- }
-}
-
-/// Emits metadata nodes for all the local variables in the current
-/// function.
-void CodeGenFunction::EmitDeclMetadata() {
- if (LocalDeclMap.empty()) return;
-
- llvm::LLVMContext &Context = getLLVMContext();
-
- // Find the unique metadata ID for this name.
- unsigned DeclPtrKind = Context.getMDKindID("clang.decl.ptr");
-
- llvm::NamedMDNode *GlobalMetadata = nullptr;
-
- for (auto &I : LocalDeclMap) {
- const Decl *D = I.first;
- llvm::Value *Addr = I.second.getPointer();
- if (auto *Alloca = dyn_cast<llvm::AllocaInst>(Addr)) {
- llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D);
- Alloca->setMetadata(
- DeclPtrKind, llvm::MDNode::get(
- Context, llvm::ValueAsMetadata::getConstant(DAddr)));
- } else if (auto *GV = dyn_cast<llvm::GlobalValue>(Addr)) {
- GlobalDecl GD = GlobalDecl(cast<VarDecl>(D));
- EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV);
- }
- }
-}
-
-void CodeGenModule::EmitVersionIdentMetadata() {
- llvm::NamedMDNode *IdentMetadata =
- TheModule.getOrInsertNamedMetadata("llvm.ident");
- std::string Version = getClangFullVersion();
- llvm::LLVMContext &Ctx = TheModule.getContext();
-
- llvm::Metadata *IdentNode[] = {llvm::MDString::get(Ctx, Version)};
- IdentMetadata->addOperand(llvm::MDNode::get(Ctx, IdentNode));
-}
-
-void CodeGenModule::EmitCommandLineMetadata() {
- llvm::NamedMDNode *CommandLineMetadata =
- TheModule.getOrInsertNamedMetadata("llvm.commandline");
- std::string CommandLine = getCodeGenOpts().RecordCommandLine;
- llvm::LLVMContext &Ctx = TheModule.getContext();
-
- llvm::Metadata *CommandLineNode[] = {llvm::MDString::get(Ctx, CommandLine)};
- CommandLineMetadata->addOperand(llvm::MDNode::get(Ctx, CommandLineNode));
-}
-
-void CodeGenModule::EmitTargetMetadata() {
- // Warning, new MangledDeclNames may be appended within this loop.
- // We rely on MapVector insertions adding new elements to the end
- // of the container.
- // FIXME: Move this loop into the one target that needs it, and only
- // loop over those declarations for which we couldn't emit the target
- // metadata when we emitted the declaration.
- for (unsigned I = 0; I != MangledDeclNames.size(); ++I) {
- auto Val = *(MangledDeclNames.begin() + I);
- const Decl *D = Val.first.getDecl()->getMostRecentDecl();
- llvm::GlobalValue *GV = GetGlobalValue(Val.second);
- getTargetCodeGenInfo().emitTargetMD(D, GV, *this);
- }
-}
-
-void CodeGenModule::EmitCoverageFile() {
- if (getCodeGenOpts().CoverageDataFile.empty() &&
- getCodeGenOpts().CoverageNotesFile.empty())
- return;
-
- llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu");
- if (!CUNode)
- return;
-
- llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov");
- llvm::LLVMContext &Ctx = TheModule.getContext();
- auto *CoverageDataFile =
- llvm::MDString::get(Ctx, getCodeGenOpts().CoverageDataFile);
- auto *CoverageNotesFile =
- llvm::MDString::get(Ctx, getCodeGenOpts().CoverageNotesFile);
- for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) {
- llvm::MDNode *CU = CUNode->getOperand(i);
- llvm::Metadata *Elts[] = {CoverageNotesFile, CoverageDataFile, CU};
- GCov->addOperand(llvm::MDNode::get(Ctx, Elts));
- }
-}
-
-llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid) {
- // Sema has checked that all uuid strings are of the form
- // "12345678-1234-1234-1234-1234567890ab".
- assert(Uuid.size() == 36);
- for (unsigned i = 0; i < 36; ++i) {
- if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuid[i] == '-');
- else assert(isHexDigit(Uuid[i]));
- }
-
- // The starts of all bytes of Field3 in Uuid. Field 3 is "1234-1234567890ab".
- const unsigned Field3ValueOffsets[8] = { 19, 21, 24, 26, 28, 30, 32, 34 };
-
- llvm::Constant *Field3[8];
- for (unsigned Idx = 0; Idx < 8; ++Idx)
- Field3[Idx] = llvm::ConstantInt::get(
- Int8Ty, Uuid.substr(Field3ValueOffsets[Idx], 2), 16);
-
- llvm::Constant *Fields[4] = {
- llvm::ConstantInt::get(Int32Ty, Uuid.substr(0, 8), 16),
- llvm::ConstantInt::get(Int16Ty, Uuid.substr(9, 4), 16),
- llvm::ConstantInt::get(Int16Ty, Uuid.substr(14, 4), 16),
- llvm::ConstantArray::get(llvm::ArrayType::get(Int8Ty, 8), Field3)
- };
-
- return llvm::ConstantStruct::getAnon(Fields);
-}
-
-llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
- bool ForEH) {
- // Return a bogus pointer if RTTI is disabled, unless it's for EH.
- // FIXME: should we even be calling this method if RTTI is disabled
- // and it's not for EH?
- if ((!ForEH && !getLangOpts().RTTI) || getLangOpts().CUDAIsDevice)
- return llvm::Constant::getNullValue(Int8PtrTy);
-
- if (ForEH && Ty->isObjCObjectPointerType() &&
- LangOpts.ObjCRuntime.isGNUFamily())
- return ObjCRuntime->GetEHType(Ty);
-
- return getCXXABI().getAddrOfRTTIDescriptor(Ty);
-}
-
-void CodeGenModule::EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
- // Do not emit threadprivates in simd-only mode.
- if (LangOpts.OpenMP && LangOpts.OpenMPSimd)
- return;
- for (auto RefExpr : D->varlists()) {
- auto *VD = cast<VarDecl>(cast<DeclRefExpr>(RefExpr)->getDecl());
- bool PerformInit =
- VD->getAnyInitializer() &&
- !VD->getAnyInitializer()->isConstantInitializer(getContext(),
- /*ForRef=*/false);
-
- Address Addr(GetAddrOfGlobalVar(VD), getContext().getDeclAlign(VD));
- if (auto InitFunction = getOpenMPRuntime().emitThreadPrivateVarDefinition(
- VD, Addr, RefExpr->getBeginLoc(), PerformInit))
- CXXGlobalInits.push_back(InitFunction);
- }
-}
-
-llvm::Metadata *
-CodeGenModule::CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
- StringRef Suffix) {
- llvm::Metadata *&InternalId = Map[T.getCanonicalType()];
- if (InternalId)
- return InternalId;
-
- if (isExternallyVisible(T->getLinkage())) {
- std::string OutName;
- llvm::raw_string_ostream Out(OutName);
- getCXXABI().getMangleContext().mangleTypeName(T, Out);
- Out << Suffix;
-
- InternalId = llvm::MDString::get(getLLVMContext(), Out.str());
- } else {
- InternalId = llvm::MDNode::getDistinct(getLLVMContext(),
- llvm::ArrayRef<llvm::Metadata *>());
- }
-
- return InternalId;
-}
-
-llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) {
- return CreateMetadataIdentifierImpl(T, MetadataIdMap, "");
-}
-
-llvm::Metadata *
-CodeGenModule::CreateMetadataIdentifierForVirtualMemPtrType(QualType T) {
- return CreateMetadataIdentifierImpl(T, VirtualMetadataIdMap, ".virtual");
-}
-
-// Generalize pointer types to a void pointer with the qualifiers of the
-// originally pointed-to type, e.g. 'const char *' and 'char * const *'
-// generalize to 'const void *' while 'char *' and 'const char **' generalize to
-// 'void *'.
-static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) {
- if (!Ty->isPointerType())
- return Ty;
-
- return Ctx.getPointerType(
- QualType(Ctx.VoidTy).withCVRQualifiers(
- Ty->getPointeeType().getCVRQualifiers()));
-}
-
-// Apply type generalization to a FunctionType's return and argument types
-static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty) {
- if (auto *FnType = Ty->getAs<FunctionProtoType>()) {
- SmallVector<QualType, 8> GeneralizedParams;
- for (auto &Param : FnType->param_types())
- GeneralizedParams.push_back(GeneralizeType(Ctx, Param));
-
- return Ctx.getFunctionType(
- GeneralizeType(Ctx, FnType->getReturnType()),
- GeneralizedParams, FnType->getExtProtoInfo());
- }
-
- if (auto *FnType = Ty->getAs<FunctionNoProtoType>())
- return Ctx.getFunctionNoProtoType(
- GeneralizeType(Ctx, FnType->getReturnType()));
-
- llvm_unreachable("Encountered unknown FunctionType");
-}
-
-llvm::Metadata *CodeGenModule::CreateMetadataIdentifierGeneralized(QualType T) {
- return CreateMetadataIdentifierImpl(GeneralizeFunctionType(getContext(), T),
- GeneralizedMetadataIdMap, ".generalized");
-}
-
-/// Returns whether this module needs the "all-vtables" type identifier.
-bool CodeGenModule::NeedAllVtablesTypeId() const {
- // Returns true if at least one of vtable-based CFI checkers is enabled and
- // is not in the trapping mode.
- return ((LangOpts.Sanitize.has(SanitizerKind::CFIVCall) &&
- !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIVCall)) ||
- (LangOpts.Sanitize.has(SanitizerKind::CFINVCall) &&
- !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFINVCall)) ||
- (LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) &&
- !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIDerivedCast)) ||
- (LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast) &&
- !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIUnrelatedCast)));
-}
-
-void CodeGenModule::AddVTableTypeMetadata(llvm::GlobalVariable *VTable,
- CharUnits Offset,
- const CXXRecordDecl *RD) {
- llvm::Metadata *MD =
- CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
- VTable->addTypeMetadata(Offset.getQuantity(), MD);
-
- if (CodeGenOpts.SanitizeCfiCrossDso)
- if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
- VTable->addTypeMetadata(Offset.getQuantity(),
- llvm::ConstantAsMetadata::get(CrossDsoTypeId));
-
- if (NeedAllVtablesTypeId()) {
- llvm::Metadata *MD = llvm::MDString::get(getLLVMContext(), "all-vtables");
- VTable->addTypeMetadata(Offset.getQuantity(), MD);
- }
-}
-
-TargetAttr::ParsedTargetAttr CodeGenModule::filterFunctionTargetAttrs(const TargetAttr *TD) {
- assert(TD != nullptr);
- TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
-
- ParsedAttr.Features.erase(
- llvm::remove_if(ParsedAttr.Features,
- [&](const std::string &Feat) {
- return !Target.isValidFeatureName(
- StringRef{Feat}.substr(1));
- }),
- ParsedAttr.Features.end());
- return ParsedAttr;
-}
-
-
-// Fills in the supplied string map with the set of target features for the
-// passed in function.
-void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
- GlobalDecl GD) {
- StringRef TargetCPU = Target.getTargetOpts().CPU;
- const FunctionDecl *FD = GD.getDecl()->getAsFunction();
- if (const auto *TD = FD->getAttr<TargetAttr>()) {
- TargetAttr::ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD);
-
- // Make a copy of the features as passed on the command line into the
- // beginning of the additional features from the function to override.
- ParsedAttr.Features.insert(ParsedAttr.Features.begin(),
- Target.getTargetOpts().FeaturesAsWritten.begin(),
- Target.getTargetOpts().FeaturesAsWritten.end());
-
- if (ParsedAttr.Architecture != "" &&
- Target.isValidCPUName(ParsedAttr.Architecture))
- TargetCPU = ParsedAttr.Architecture;
-
- // Now populate the feature map, first with the TargetCPU which is either
- // the default or a new one from the target attribute string. Then we'll use
- // the passed in features (FeaturesAsWritten) along with the new ones from
- // the attribute.
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
- ParsedAttr.Features);
- } else if (const auto *SD = FD->getAttr<CPUSpecificAttr>()) {
- llvm::SmallVector<StringRef, 32> FeaturesTmp;
- Target.getCPUSpecificCPUDispatchFeatures(
- SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp);
- std::vector<std::string> Features(FeaturesTmp.begin(), FeaturesTmp.end());
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, Features);
- } else {
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
- Target.getTargetOpts().Features);
- }
-}
-
-llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
- if (!SanStats)
- SanStats = llvm::make_unique<llvm::SanitizerStatReport>(&getModule());
-
- return *SanStats;
-}
-llvm::Value *
-CodeGenModule::createOpenCLIntToSamplerConversion(const Expr *E,
- CodeGenFunction &CGF) {
- llvm::Constant *C = ConstantEmitter(CGF).emitAbstract(E, E->getType());
- auto SamplerT = getOpenCLRuntime().getSamplerType(E->getType().getTypePtr());
- auto FTy = llvm::FunctionType::get(SamplerT, {C->getType()}, false);
- return CGF.Builder.CreateCall(CreateRuntimeFunction(FTy,
- "__translate_sampler_initializer"),
- {C});
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.h
deleted file mode 100644
index 75679d11c13..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenModule.h
+++ /dev/null
@@ -1,1470 +0,0 @@
-//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the internal per-translation-unit state used for llvm translation.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H
-#define LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H
-
-#include "CGVTables.h"
-#include "CodeGenTypeCache.h"
-#include "CodeGenTypes.h"
-#include "SanitizerMetadata.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclOpenMP.h"
-#include "clang/AST/GlobalDecl.h"
-#include "clang/AST/Mangle.h"
-#include "clang/Basic/ABI.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/Module.h"
-#include "clang/Basic/SanitizerBlacklist.h"
-#include "clang/Basic/XRayLists.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/ValueHandle.h"
-#include "llvm/Transforms/Utils/SanitizerStats.h"
-
-namespace llvm {
-class Module;
-class Constant;
-class ConstantInt;
-class Function;
-class GlobalValue;
-class DataLayout;
-class FunctionType;
-class LLVMContext;
-class IndexedInstrProfReader;
-}
-
-namespace clang {
-class ASTContext;
-class AtomicType;
-class FunctionDecl;
-class IdentifierInfo;
-class ObjCMethodDecl;
-class ObjCImplementationDecl;
-class ObjCCategoryImplDecl;
-class ObjCProtocolDecl;
-class ObjCEncodeExpr;
-class BlockExpr;
-class CharUnits;
-class Decl;
-class Expr;
-class Stmt;
-class InitListExpr;
-class StringLiteral;
-class NamedDecl;
-class ValueDecl;
-class VarDecl;
-class LangOptions;
-class CodeGenOptions;
-class HeaderSearchOptions;
-class PreprocessorOptions;
-class DiagnosticsEngine;
-class AnnotateAttr;
-class CXXDestructorDecl;
-class Module;
-class CoverageSourceInfo;
-
-namespace CodeGen {
-
-class CallArgList;
-class CodeGenFunction;
-class CodeGenTBAA;
-class CGCXXABI;
-class CGDebugInfo;
-class CGObjCRuntime;
-class CGOpenCLRuntime;
-class CGOpenMPRuntime;
-class CGCUDARuntime;
-class BlockFieldFlags;
-class FunctionArgList;
-class CoverageMappingModuleGen;
-class TargetCodeGenInfo;
-
-enum ForDefinition_t : bool {
- NotForDefinition = false,
- ForDefinition = true
-};
-
-struct OrderGlobalInits {
- unsigned int priority;
- unsigned int lex_order;
- OrderGlobalInits(unsigned int p, unsigned int l)
- : priority(p), lex_order(l) {}
-
- bool operator==(const OrderGlobalInits &RHS) const {
- return priority == RHS.priority && lex_order == RHS.lex_order;
- }
-
- bool operator<(const OrderGlobalInits &RHS) const {
- return std::tie(priority, lex_order) <
- std::tie(RHS.priority, RHS.lex_order);
- }
-};
-
-struct ObjCEntrypoints {
- ObjCEntrypoints() { memset(this, 0, sizeof(*this)); }
-
- /// void objc_alloc(id);
- llvm::Constant *objc_alloc;
-
- /// void objc_allocWithZone(id);
- llvm::Constant *objc_allocWithZone;
-
- /// void objc_autoreleasePoolPop(void*);
- llvm::Constant *objc_autoreleasePoolPop;
-
- /// void objc_autoreleasePoolPop(void*);
- /// Note this method is used when we are using exception handling
- llvm::Constant *objc_autoreleasePoolPopInvoke;
-
- /// void *objc_autoreleasePoolPush(void);
- llvm::Constant *objc_autoreleasePoolPush;
-
- /// id objc_autorelease(id);
- llvm::Constant *objc_autorelease;
-
- /// id objc_autorelease(id);
- /// Note this is the runtime method not the intrinsic.
- llvm::Constant *objc_autoreleaseRuntimeFunction;
-
- /// id objc_autoreleaseReturnValue(id);
- llvm::Constant *objc_autoreleaseReturnValue;
-
- /// void objc_copyWeak(id *dest, id *src);
- llvm::Constant *objc_copyWeak;
-
- /// void objc_destroyWeak(id*);
- llvm::Constant *objc_destroyWeak;
-
- /// id objc_initWeak(id*, id);
- llvm::Constant *objc_initWeak;
-
- /// id objc_loadWeak(id*);
- llvm::Constant *objc_loadWeak;
-
- /// id objc_loadWeakRetained(id*);
- llvm::Constant *objc_loadWeakRetained;
-
- /// void objc_moveWeak(id *dest, id *src);
- llvm::Constant *objc_moveWeak;
-
- /// id objc_retain(id);
- llvm::Constant *objc_retain;
-
- /// id objc_retain(id);
- /// Note this is the runtime method not the intrinsic.
- llvm::Constant *objc_retainRuntimeFunction;
-
- /// id objc_retainAutorelease(id);
- llvm::Constant *objc_retainAutorelease;
-
- /// id objc_retainAutoreleaseReturnValue(id);
- llvm::Constant *objc_retainAutoreleaseReturnValue;
-
- /// id objc_retainAutoreleasedReturnValue(id);
- llvm::Constant *objc_retainAutoreleasedReturnValue;
-
- /// id objc_retainBlock(id);
- llvm::Constant *objc_retainBlock;
-
- /// void objc_release(id);
- llvm::Constant *objc_release;
-
- /// void objc_release(id);
- /// Note this is the runtime method not the intrinsic.
- llvm::Constant *objc_releaseRuntimeFunction;
-
- /// void objc_storeStrong(id*, id);
- llvm::Constant *objc_storeStrong;
-
- /// id objc_storeWeak(id*, id);
- llvm::Constant *objc_storeWeak;
-
- /// id objc_unsafeClaimAutoreleasedReturnValue(id);
- llvm::Constant *objc_unsafeClaimAutoreleasedReturnValue;
-
- /// A void(void) inline asm to use to mark that the return value of
- /// a call will be immediately retain.
- llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
-
- /// void clang.arc.use(...);
- llvm::Constant *clang_arc_use;
-};
-
-/// This class records statistics on instrumentation based profiling.
-class InstrProfStats {
- uint32_t VisitedInMainFile;
- uint32_t MissingInMainFile;
- uint32_t Visited;
- uint32_t Missing;
- uint32_t Mismatched;
-
-public:
- InstrProfStats()
- : VisitedInMainFile(0), MissingInMainFile(0), Visited(0), Missing(0),
- Mismatched(0) {}
- /// Record that we've visited a function and whether or not that function was
- /// in the main source file.
- void addVisited(bool MainFile) {
- if (MainFile)
- ++VisitedInMainFile;
- ++Visited;
- }
- /// Record that a function we've visited has no profile data.
- void addMissing(bool MainFile) {
- if (MainFile)
- ++MissingInMainFile;
- ++Missing;
- }
- /// Record that a function we've visited has mismatched profile data.
- void addMismatched(bool MainFile) { ++Mismatched; }
- /// Whether or not the stats we've gathered indicate any potential problems.
- bool hasDiagnostics() { return Missing || Mismatched; }
- /// Report potential problems we've found to \c Diags.
- void reportDiagnostics(DiagnosticsEngine &Diags, StringRef MainFile);
-};
-
-/// A pair of helper functions for a __block variable.
-class BlockByrefHelpers : public llvm::FoldingSetNode {
- // MSVC requires this type to be complete in order to process this
- // header.
-public:
- llvm::Constant *CopyHelper;
- llvm::Constant *DisposeHelper;
-
- /// The alignment of the field. This is important because
- /// different offsets to the field within the byref struct need to
- /// have different helper functions.
- CharUnits Alignment;
-
- BlockByrefHelpers(CharUnits alignment) : Alignment(alignment) {}
- BlockByrefHelpers(const BlockByrefHelpers &) = default;
- virtual ~BlockByrefHelpers();
-
- void Profile(llvm::FoldingSetNodeID &id) const {
- id.AddInteger(Alignment.getQuantity());
- profileImpl(id);
- }
- virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0;
-
- virtual bool needsCopy() const { return true; }
- virtual void emitCopy(CodeGenFunction &CGF, Address dest, Address src) = 0;
-
- virtual bool needsDispose() const { return true; }
- virtual void emitDispose(CodeGenFunction &CGF, Address field) = 0;
-};
-
-/// This class organizes the cross-function state that is used while generating
-/// LLVM code.
-class CodeGenModule : public CodeGenTypeCache {
- CodeGenModule(const CodeGenModule &) = delete;
- void operator=(const CodeGenModule &) = delete;
-
-public:
- struct Structor {
- Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {}
- Structor(int Priority, llvm::Constant *Initializer,
- llvm::Constant *AssociatedData)
- : Priority(Priority), Initializer(Initializer),
- AssociatedData(AssociatedData) {}
- int Priority;
- llvm::Constant *Initializer;
- llvm::Constant *AssociatedData;
- };
-
- typedef std::vector<Structor> CtorList;
-
-private:
- ASTContext &Context;
- const LangOptions &LangOpts;
- const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
- const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
- const CodeGenOptions &CodeGenOpts;
- llvm::Module &TheModule;
- DiagnosticsEngine &Diags;
- const TargetInfo &Target;
- std::unique_ptr<CGCXXABI> ABI;
- llvm::LLVMContext &VMContext;
-
- std::unique_ptr<CodeGenTBAA> TBAA;
-
- mutable std::unique_ptr<TargetCodeGenInfo> TheTargetCodeGenInfo;
-
- // This should not be moved earlier, since its initialization depends on some
- // of the previous reference members being already initialized and also checks
- // if TheTargetCodeGenInfo is NULL
- CodeGenTypes Types;
-
- /// Holds information about C++ vtables.
- CodeGenVTables VTables;
-
- std::unique_ptr<CGObjCRuntime> ObjCRuntime;
- std::unique_ptr<CGOpenCLRuntime> OpenCLRuntime;
- std::unique_ptr<CGOpenMPRuntime> OpenMPRuntime;
- std::unique_ptr<CGCUDARuntime> CUDARuntime;
- std::unique_ptr<CGDebugInfo> DebugInfo;
- std::unique_ptr<ObjCEntrypoints> ObjCData;
- llvm::MDNode *NoObjCARCExceptionsMetadata = nullptr;
- std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
- InstrProfStats PGOStats;
- std::unique_ptr<llvm::SanitizerStatReport> SanStats;
-
- // A set of references that have only been seen via a weakref so far. This is
- // used to remove the weak of the reference if we ever see a direct reference
- // or a definition.
- llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences;
-
- /// This contains all the decls which have definitions but/ which are deferred
- /// for emission and therefore should only be output if they are actually
- /// used. If a decl is in this, then it is known to have not been referenced
- /// yet.
- std::map<StringRef, GlobalDecl> DeferredDecls;
-
- /// This is a list of deferred decls which we have seen that *are* actually
- /// referenced. These get code generated when the module is done.
- std::vector<GlobalDecl> DeferredDeclsToEmit;
- void addDeferredDeclToEmit(GlobalDecl GD) {
- DeferredDeclsToEmit.emplace_back(GD);
- }
-
- /// List of alias we have emitted. Used to make sure that what they point to
- /// is defined once we get to the end of the of the translation unit.
- std::vector<GlobalDecl> Aliases;
-
- /// List of multiversion functions that have to be emitted. Used to make sure
- /// we properly emit the iFunc.
- std::vector<GlobalDecl> MultiVersionFuncs;
-
- typedef llvm::StringMap<llvm::TrackingVH<llvm::Constant> > ReplacementsTy;
- ReplacementsTy Replacements;
-
- /// List of global values to be replaced with something else. Used when we
- /// want to replace a GlobalValue but can't identify it by its mangled name
- /// anymore (because the name is already taken).
- llvm::SmallVector<std::pair<llvm::GlobalValue *, llvm::Constant *>, 8>
- GlobalValReplacements;
-
- /// Set of global decls for which we already diagnosed mangled name conflict.
- /// Required to not issue a warning (on a mangling conflict) multiple times
- /// for the same decl.
- llvm::DenseSet<GlobalDecl> DiagnosedConflictingDefinitions;
-
- /// A queue of (optional) vtables to consider emitting.
- std::vector<const CXXRecordDecl*> DeferredVTables;
-
- /// A queue of (optional) vtables that may be emitted opportunistically.
- std::vector<const CXXRecordDecl *> OpportunisticVTables;
-
- /// List of global values which are required to be present in the object file;
- /// bitcast to i8*. This is used for forcing visibility of symbols which may
- /// otherwise be optimized out.
- std::vector<llvm::WeakTrackingVH> LLVMUsed;
- std::vector<llvm::WeakTrackingVH> LLVMCompilerUsed;
-
- /// Store the list of global constructors and their respective priorities to
- /// be emitted when the translation unit is complete.
- CtorList GlobalCtors;
-
- /// Store the list of global destructors and their respective priorities to be
- /// emitted when the translation unit is complete.
- CtorList GlobalDtors;
-
- /// An ordered map of canonical GlobalDecls to their mangled names.
- llvm::MapVector<GlobalDecl, StringRef> MangledDeclNames;
- llvm::StringMap<GlobalDecl, llvm::BumpPtrAllocator> Manglings;
-
- // An ordered map of canonical GlobalDecls paired with the cpu-index for
- // cpu-specific name manglings.
- llvm::MapVector<std::pair<GlobalDecl, unsigned>, StringRef>
- CPUSpecificMangledDeclNames;
- llvm::StringMap<std::pair<GlobalDecl, unsigned>, llvm::BumpPtrAllocator>
- CPUSpecificManglings;
-
- /// Global annotations.
- std::vector<llvm::Constant*> Annotations;
-
- /// Map used to get unique annotation strings.
- llvm::StringMap<llvm::Constant*> AnnotationStrings;
-
- llvm::StringMap<llvm::GlobalVariable *> CFConstantStringMap;
-
- llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> ConstantStringMap;
- llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
- llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
- llvm::DenseMap<const Expr*, llvm::Constant *> MaterializedGlobalTemporaryMap;
-
- llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
- llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
-
- /// Map used to get unique type descriptor constants for sanitizers.
- llvm::DenseMap<QualType, llvm::Constant *> TypeDescriptorMap;
-
- /// Map used to track internal linkage functions declared within
- /// extern "C" regions.
- typedef llvm::MapVector<IdentifierInfo *,
- llvm::GlobalValue *> StaticExternCMap;
- StaticExternCMap StaticExternCValues;
-
- /// thread_local variables defined or used in this TU.
- std::vector<const VarDecl *> CXXThreadLocals;
-
- /// thread_local variables with initializers that need to run
- /// before any thread_local variable in this TU is odr-used.
- std::vector<llvm::Function *> CXXThreadLocalInits;
- std::vector<const VarDecl *> CXXThreadLocalInitVars;
-
- /// Global variables with initializers that need to run before main.
- std::vector<llvm::Function *> CXXGlobalInits;
-
- /// When a C++ decl with an initializer is deferred, null is
- /// appended to CXXGlobalInits, and the index of that null is placed
- /// here so that the initializer will be performed in the correct
- /// order. Once the decl is emitted, the index is replaced with ~0U to ensure
- /// that we don't re-emit the initializer.
- llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition;
-
- typedef std::pair<OrderGlobalInits, llvm::Function*> GlobalInitData;
-
- struct GlobalInitPriorityCmp {
- bool operator()(const GlobalInitData &LHS,
- const GlobalInitData &RHS) const {
- return LHS.first.priority < RHS.first.priority;
- }
- };
-
- /// Global variables with initializers whose order of initialization is set by
- /// init_priority attribute.
- SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
-
- /// Global destructor functions and arguments that need to run on termination.
- std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>> CXXGlobalDtors;
-
- /// The complete set of modules that has been imported.
- llvm::SetVector<clang::Module *> ImportedModules;
-
- /// The set of modules for which the module initializers
- /// have been emitted.
- llvm::SmallPtrSet<clang::Module *, 16> EmittedModuleInitializers;
-
- /// A vector of metadata strings.
- SmallVector<llvm::MDNode *, 16> LinkerOptionsMetadata;
-
- /// @name Cache for Objective-C runtime types
- /// @{
-
- /// Cached reference to the class for constant strings. This value has type
- /// int * but is actually an Obj-C class pointer.
- llvm::WeakTrackingVH CFConstantStringClassRef;
-
- /// The type used to describe the state of a fast enumeration in
- /// Objective-C's for..in loop.
- QualType ObjCFastEnumerationStateType;
-
- /// @}
-
- /// Lazily create the Objective-C runtime
- void createObjCRuntime();
-
- void createOpenCLRuntime();
- void createOpenMPRuntime();
- void createCUDARuntime();
-
- bool isTriviallyRecursive(const FunctionDecl *F);
- bool shouldEmitFunction(GlobalDecl GD);
- bool shouldOpportunisticallyEmitVTables();
- /// Map used to be sure we don't emit the same CompoundLiteral twice.
- llvm::DenseMap<const CompoundLiteralExpr *, llvm::GlobalVariable *>
- EmittedCompoundLiterals;
-
- /// Map of the global blocks we've emitted, so that we don't have to re-emit
- /// them if the constexpr evaluator gets aggressive.
- llvm::DenseMap<const BlockExpr *, llvm::Constant *> EmittedGlobalBlocks;
-
- /// @name Cache for Blocks Runtime Globals
- /// @{
-
- llvm::Constant *NSConcreteGlobalBlock = nullptr;
- llvm::Constant *NSConcreteStackBlock = nullptr;
-
- llvm::Constant *BlockObjectAssign = nullptr;
- llvm::Constant *BlockObjectDispose = nullptr;
-
- llvm::Type *BlockDescriptorType = nullptr;
- llvm::Type *GenericBlockLiteralType = nullptr;
-
- struct {
- int GlobalUniqueCount;
- } Block;
-
- /// void @llvm.lifetime.start(i64 %size, i8* nocapture <ptr>)
- llvm::Constant *LifetimeStartFn = nullptr;
-
- /// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>)
- llvm::Constant *LifetimeEndFn = nullptr;
-
- GlobalDecl initializedGlobalDecl;
-
- std::unique_ptr<SanitizerMetadata> SanitizerMD;
-
- /// @}
-
- llvm::MapVector<const Decl *, bool> DeferredEmptyCoverageMappingDecls;
-
- std::unique_ptr<CoverageMappingModuleGen> CoverageMapping;
-
- /// Mapping from canonical types to their metadata identifiers. We need to
- /// maintain this mapping because identifiers may be formed from distinct
- /// MDNodes.
- typedef llvm::DenseMap<QualType, llvm::Metadata *> MetadataTypeMap;
- MetadataTypeMap MetadataIdMap;
- MetadataTypeMap VirtualMetadataIdMap;
- MetadataTypeMap GeneralizedMetadataIdMap;
-
-public:
- CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
- const PreprocessorOptions &ppopts,
- const CodeGenOptions &CodeGenOpts, llvm::Module &M,
- DiagnosticsEngine &Diags,
- CoverageSourceInfo *CoverageInfo = nullptr);
-
- ~CodeGenModule();
-
- void clear();
-
- /// Finalize LLVM code generation.
- void Release();
-
- /// Return true if we should emit location information for expressions.
- bool getExpressionLocationsEnabled() const;
-
- /// Return a reference to the configured Objective-C runtime.
- CGObjCRuntime &getObjCRuntime() {
- if (!ObjCRuntime) createObjCRuntime();
- return *ObjCRuntime;
- }
-
- /// Return true iff an Objective-C runtime has been configured.
- bool hasObjCRuntime() { return !!ObjCRuntime; }
-
- /// Return a reference to the configured OpenCL runtime.
- CGOpenCLRuntime &getOpenCLRuntime() {
- assert(OpenCLRuntime != nullptr);
- return *OpenCLRuntime;
- }
-
- /// Return a reference to the configured OpenMP runtime.
- CGOpenMPRuntime &getOpenMPRuntime() {
- assert(OpenMPRuntime != nullptr);
- return *OpenMPRuntime;
- }
-
- /// Return a reference to the configured CUDA runtime.
- CGCUDARuntime &getCUDARuntime() {
- assert(CUDARuntime != nullptr);
- return *CUDARuntime;
- }
-
- ObjCEntrypoints &getObjCEntrypoints() const {
- assert(ObjCData != nullptr);
- return *ObjCData;
- }
-
- // Version checking function, used to implement ObjC's @available:
- // i32 @__isOSVersionAtLeast(i32, i32, i32)
- llvm::Constant *IsOSVersionAtLeastFn = nullptr;
-
- InstrProfStats &getPGOStats() { return PGOStats; }
- llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
-
- CoverageMappingModuleGen *getCoverageMapping() const {
- return CoverageMapping.get();
- }
-
- llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) {
- return StaticLocalDeclMap[D];
- }
- void setStaticLocalDeclAddress(const VarDecl *D,
- llvm::Constant *C) {
- StaticLocalDeclMap[D] = C;
- }
-
- llvm::Constant *
- getOrCreateStaticVarDecl(const VarDecl &D,
- llvm::GlobalValue::LinkageTypes Linkage);
-
- llvm::GlobalVariable *getStaticLocalDeclGuardAddress(const VarDecl *D) {
- return StaticLocalDeclGuardMap[D];
- }
- void setStaticLocalDeclGuardAddress(const VarDecl *D,
- llvm::GlobalVariable *C) {
- StaticLocalDeclGuardMap[D] = C;
- }
-
- bool lookupRepresentativeDecl(StringRef MangledName,
- GlobalDecl &Result) const;
-
- llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) {
- return AtomicSetterHelperFnMap[Ty];
- }
- void setAtomicSetterHelperFnMap(QualType Ty,
- llvm::Constant *Fn) {
- AtomicSetterHelperFnMap[Ty] = Fn;
- }
-
- llvm::Constant *getAtomicGetterHelperFnMap(QualType Ty) {
- return AtomicGetterHelperFnMap[Ty];
- }
- void setAtomicGetterHelperFnMap(QualType Ty,
- llvm::Constant *Fn) {
- AtomicGetterHelperFnMap[Ty] = Fn;
- }
-
- llvm::Constant *getTypeDescriptorFromMap(QualType Ty) {
- return TypeDescriptorMap[Ty];
- }
- void setTypeDescriptorInMap(QualType Ty, llvm::Constant *C) {
- TypeDescriptorMap[Ty] = C;
- }
-
- CGDebugInfo *getModuleDebugInfo() { return DebugInfo.get(); }
-
- llvm::MDNode *getNoObjCARCExceptionsMetadata() {
- if (!NoObjCARCExceptionsMetadata)
- NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), None);
- return NoObjCARCExceptionsMetadata;
- }
-
- ASTContext &getContext() const { return Context; }
- const LangOptions &getLangOpts() const { return LangOpts; }
- const HeaderSearchOptions &getHeaderSearchOpts()
- const { return HeaderSearchOpts; }
- const PreprocessorOptions &getPreprocessorOpts()
- const { return PreprocessorOpts; }
- const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
- llvm::Module &getModule() const { return TheModule; }
- DiagnosticsEngine &getDiags() const { return Diags; }
- const llvm::DataLayout &getDataLayout() const {
- return TheModule.getDataLayout();
- }
- const TargetInfo &getTarget() const { return Target; }
- const llvm::Triple &getTriple() const { return Target.getTriple(); }
- bool supportsCOMDAT() const;
- void maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO);
-
- CGCXXABI &getCXXABI() const { return *ABI; }
- llvm::LLVMContext &getLLVMContext() { return VMContext; }
-
- bool shouldUseTBAA() const { return TBAA != nullptr; }
-
- const TargetCodeGenInfo &getTargetCodeGenInfo();
-
- CodeGenTypes &getTypes() { return Types; }
-
- CodeGenVTables &getVTables() { return VTables; }
-
- ItaniumVTableContext &getItaniumVTableContext() {
- return VTables.getItaniumVTableContext();
- }
-
- MicrosoftVTableContext &getMicrosoftVTableContext() {
- return VTables.getMicrosoftVTableContext();
- }
-
- CtorList &getGlobalCtors() { return GlobalCtors; }
- CtorList &getGlobalDtors() { return GlobalDtors; }
-
- /// getTBAATypeInfo - Get metadata used to describe accesses to objects of
- /// the given type.
- llvm::MDNode *getTBAATypeInfo(QualType QTy);
-
- /// getTBAAAccessInfo - Get TBAA information that describes an access to
- /// an object of the given type.
- TBAAAccessInfo getTBAAAccessInfo(QualType AccessType);
-
- /// getTBAAVTablePtrAccessInfo - Get the TBAA information that describes an
- /// access to a virtual table pointer.
- TBAAAccessInfo getTBAAVTablePtrAccessInfo(llvm::Type *VTablePtrType);
-
- llvm::MDNode *getTBAAStructInfo(QualType QTy);
-
- /// getTBAABaseTypeInfo - Get metadata that describes the given base access
- /// type. Return null if the type is not suitable for use in TBAA access tags.
- llvm::MDNode *getTBAABaseTypeInfo(QualType QTy);
-
- /// getTBAAAccessTagInfo - Get TBAA tag for a given memory access.
- llvm::MDNode *getTBAAAccessTagInfo(TBAAAccessInfo Info);
-
- /// mergeTBAAInfoForCast - Get merged TBAA information for the purposes of
- /// type casts.
- TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
- TBAAAccessInfo TargetInfo);
-
- /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the
- /// purposes of conditional operator.
- TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
- TBAAAccessInfo InfoB);
-
- /// mergeTBAAInfoForMemoryTransfer - Get merged TBAA information for the
- /// purposes of memory transfer calls.
- TBAAAccessInfo mergeTBAAInfoForMemoryTransfer(TBAAAccessInfo DestInfo,
- TBAAAccessInfo SrcInfo);
-
- /// getTBAAInfoForSubobject - Get TBAA information for an access with a given
- /// base lvalue.
- TBAAAccessInfo getTBAAInfoForSubobject(LValue Base, QualType AccessType) {
- if (Base.getTBAAInfo().isMayAlias())
- return TBAAAccessInfo::getMayAliasInfo();
- return getTBAAAccessInfo(AccessType);
- }
-
- bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
-
- bool isPaddedAtomicType(QualType type);
- bool isPaddedAtomicType(const AtomicType *type);
-
- /// DecorateInstructionWithTBAA - Decorate the instruction with a TBAA tag.
- void DecorateInstructionWithTBAA(llvm::Instruction *Inst,
- TBAAAccessInfo TBAAInfo);
-
- /// Adds !invariant.barrier !tag to instruction
- void DecorateInstructionWithInvariantGroup(llvm::Instruction *I,
- const CXXRecordDecl *RD);
-
- /// Emit the given number of characters as a value of type size_t.
- llvm::ConstantInt *getSize(CharUnits numChars);
-
- /// Set the visibility for the given LLVM GlobalValue.
- void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const;
-
- void setGlobalVisibilityAndLocal(llvm::GlobalValue *GV,
- const NamedDecl *D) const;
-
- void setDSOLocal(llvm::GlobalValue *GV) const;
-
- void setDLLImportDLLExport(llvm::GlobalValue *GV, GlobalDecl D) const;
- void setDLLImportDLLExport(llvm::GlobalValue *GV, const NamedDecl *D) const;
- /// Set visibility, dllimport/dllexport and dso_local.
- /// This must be called after dllimport/dllexport is set.
- void setGVProperties(llvm::GlobalValue *GV, GlobalDecl GD) const;
- void setGVProperties(llvm::GlobalValue *GV, const NamedDecl *D) const;
-
- /// Set the TLS mode for the given LLVM GlobalValue for the thread-local
- /// variable declaration D.
- void setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const;
-
- static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) {
- switch (V) {
- case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility;
- case HiddenVisibility: return llvm::GlobalValue::HiddenVisibility;
- case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility;
- }
- llvm_unreachable("unknown visibility!");
- }
-
- llvm::Constant *GetAddrOfGlobal(GlobalDecl GD,
- ForDefinition_t IsForDefinition
- = NotForDefinition);
-
- /// Will return a global variable of the given type. If a variable with a
- /// different type already exists then a new variable with the right type
- /// will be created and all uses of the old variable will be replaced with a
- /// bitcast to the new variable.
- llvm::GlobalVariable *
- CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty,
- llvm::GlobalValue::LinkageTypes Linkage,
- unsigned Alignment);
-
- llvm::Function *
- CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, const Twine &name,
- const CGFunctionInfo &FI,
- SourceLocation Loc = SourceLocation(),
- bool TLS = false);
-
- /// Return the AST address space of the underlying global variable for D, as
- /// determined by its declaration. Normally this is the same as the address
- /// space of D's type, but in CUDA, address spaces are associated with
- /// declarations, not types. If D is nullptr, return the default address
- /// space for global variable.
- ///
- /// For languages without explicit address spaces, if D has default address
- /// space, target-specific global or constant address space may be returned.
- LangAS GetGlobalVarAddressSpace(const VarDecl *D);
-
- /// Return the llvm::Constant for the address of the given global variable.
- /// If Ty is non-null and if the global doesn't exist, then it will be created
- /// with the specified type instead of whatever the normal requested type
- /// would be. If IsForDefinition is true, it is guaranteed that an actual
- /// global with type Ty will be returned, not conversion of a variable with
- /// the same mangled name but some other type.
- llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
- llvm::Type *Ty = nullptr,
- ForDefinition_t IsForDefinition
- = NotForDefinition);
-
- /// Return the AST address space of string literal, which is used to emit
- /// the string literal as global variable in LLVM IR.
- /// Note: This is not necessarily the address space of the string literal
- /// in AST. For address space agnostic language, e.g. C++, string literal
- /// in AST is always in default address space.
- LangAS getStringLiteralAddressSpace() const;
-
- /// Return the address of the given function. If Ty is non-null, then this
- /// function will use the specified type if it has to create it.
- llvm::Constant *GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty = nullptr,
- bool ForVTable = false,
- bool DontDefer = false,
- ForDefinition_t IsForDefinition
- = NotForDefinition);
-
- /// Get the address of the RTTI descriptor for the given type.
- llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
-
- /// Get the address of a uuid descriptor .
- ConstantAddress GetAddrOfUuidDescriptor(const CXXUuidofExpr* E);
-
- /// Get the address of the thunk for the given global decl.
- llvm::Constant *GetAddrOfThunk(StringRef Name, llvm::Type *FnTy,
- GlobalDecl GD);
-
- /// Get a reference to the target of VD.
- ConstantAddress GetWeakRefReference(const ValueDecl *VD);
-
- /// Returns the assumed alignment of an opaque pointer to the given class.
- CharUnits getClassPointerAlignment(const CXXRecordDecl *CD);
-
- /// Returns the assumed alignment of a virtual base of a class.
- CharUnits getVBaseAlignment(CharUnits DerivedAlign,
- const CXXRecordDecl *Derived,
- const CXXRecordDecl *VBase);
-
- /// Given a class pointer with an actual known alignment, and the
- /// expected alignment of an object at a dynamic offset w.r.t that
- /// pointer, return the alignment to assume at the offset.
- CharUnits getDynamicOffsetAlignment(CharUnits ActualAlign,
- const CXXRecordDecl *Class,
- CharUnits ExpectedTargetAlign);
-
- CharUnits
- computeNonVirtualBaseClassOffset(const CXXRecordDecl *DerivedClass,
- CastExpr::path_const_iterator Start,
- CastExpr::path_const_iterator End);
-
- /// Returns the offset from a derived class to a class. Returns null if the
- /// offset is 0.
- llvm::Constant *
- GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd);
-
- llvm::FoldingSet<BlockByrefHelpers> ByrefHelpersCache;
-
- /// Fetches the global unique block count.
- int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; }
-
- /// Fetches the type of a generic block descriptor.
- llvm::Type *getBlockDescriptorType();
-
- /// The type of a generic block literal.
- llvm::Type *getGenericBlockLiteralType();
-
- /// Gets the address of a block which requires no captures.
- llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, StringRef Name);
-
- /// Returns the address of a block which requires no caputres, or null if
- /// we've yet to emit the block for BE.
- llvm::Constant *getAddrOfGlobalBlockIfEmitted(const BlockExpr *BE) {
- return EmittedGlobalBlocks.lookup(BE);
- }
-
- /// Notes that BE's global block is available via Addr. Asserts that BE
- /// isn't already emitted.
- void setAddrOfGlobalBlock(const BlockExpr *BE, llvm::Constant *Addr);
-
- /// Return a pointer to a constant CFString object for the given string.
- ConstantAddress GetAddrOfConstantCFString(const StringLiteral *Literal);
-
- /// Return a pointer to a constant NSString object for the given string. Or a
- /// user defined String object as defined via
- /// -fconstant-string-class=class_name option.
- ConstantAddress GetAddrOfConstantString(const StringLiteral *Literal);
-
- /// Return a constant array for the given string.
- llvm::Constant *GetConstantArrayFromStringLiteral(const StringLiteral *E);
-
- /// Return a pointer to a constant array for the given string literal.
- ConstantAddress
- GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
- StringRef Name = ".str");
-
- /// Return a pointer to a constant array for the given ObjCEncodeExpr node.
- ConstantAddress
- GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *);
-
- /// Returns a pointer to a character array containing the literal and a
- /// terminating '\0' character. The result has pointer to array type.
- ///
- /// \param GlobalName If provided, the name to use for the global (if one is
- /// created).
- ConstantAddress
- GetAddrOfConstantCString(const std::string &Str,
- const char *GlobalName = nullptr);
-
- /// Returns a pointer to a constant global variable for the given file-scope
- /// compound literal expression.
- ConstantAddress GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E);
-
- /// If it's been emitted already, returns the GlobalVariable corresponding to
- /// a compound literal. Otherwise, returns null.
- llvm::GlobalVariable *
- getAddrOfConstantCompoundLiteralIfEmitted(const CompoundLiteralExpr *E);
-
- /// Notes that CLE's GlobalVariable is GV. Asserts that CLE isn't already
- /// emitted.
- void setAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *CLE,
- llvm::GlobalVariable *GV);
-
- /// Returns a pointer to a global variable representing a temporary
- /// with static or thread storage duration.
- ConstantAddress GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E,
- const Expr *Inner);
-
- /// Retrieve the record type that describes the state of an
- /// Objective-C fast enumeration loop (for..in).
- QualType getObjCFastEnumerationStateType();
-
- // Produce code for this constructor/destructor. This method doesn't try
- // to apply any ABI rules about which other constructors/destructors
- // are needed or if they are alias to each other.
- llvm::Function *codegenCXXStructor(const CXXMethodDecl *MD,
- StructorType Type);
-
- /// Return the address of the constructor/destructor of the given type.
- llvm::Constant *
- getAddrOfCXXStructor(const CXXMethodDecl *MD, StructorType Type,
- const CGFunctionInfo *FnInfo = nullptr,
- llvm::FunctionType *FnType = nullptr,
- bool DontDefer = false,
- ForDefinition_t IsForDefinition = NotForDefinition);
-
- /// Given a builtin id for a function like "__builtin_fabsf", return a
- /// Function* for "fabsf".
- llvm::Constant *getBuiltinLibFunction(const FunctionDecl *FD,
- unsigned BuiltinID);
-
- llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = None);
-
- /// Emit code for a single top level declaration.
- void EmitTopLevelDecl(Decl *D);
-
- /// Stored a deferred empty coverage mapping for an unused
- /// and thus uninstrumented top level declaration.
- void AddDeferredUnusedCoverageMapping(Decl *D);
-
- /// Remove the deferred empty coverage mapping as this
- /// declaration is actually instrumented.
- void ClearUnusedCoverageMapping(const Decl *D);
-
- /// Emit all the deferred coverage mappings
- /// for the uninstrumented functions.
- void EmitDeferredUnusedCoverageMappings();
-
- /// Tell the consumer that this variable has been instantiated.
- void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
-
- /// If the declaration has internal linkage but is inside an
- /// extern "C" linkage specification, prepare to emit an alias for it
- /// to the expected name.
- template<typename SomeDecl>
- void MaybeHandleStaticInExternC(const SomeDecl *D, llvm::GlobalValue *GV);
-
- /// Add a global to a list to be added to the llvm.used metadata.
- void addUsedGlobal(llvm::GlobalValue *GV);
-
- /// Add a global to a list to be added to the llvm.compiler.used metadata.
- void addCompilerUsedGlobal(llvm::GlobalValue *GV);
-
- /// Add a destructor and object to add to the C++ global destructor function.
- void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) {
- CXXGlobalDtors.emplace_back(DtorFn, Object);
- }
-
- /// Create a new runtime function with the specified type and name.
- llvm::Constant *
- CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name,
- llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
- bool Local = false);
-
- /// Create a new compiler builtin function with the specified type and name.
- llvm::Constant *
- CreateBuiltinFunction(llvm::FunctionType *Ty, StringRef Name,
- llvm::AttributeList ExtraAttrs = llvm::AttributeList());
- /// Create a new runtime global variable with the specified type and name.
- llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
- StringRef Name);
-
- ///@name Custom Blocks Runtime Interfaces
- ///@{
-
- llvm::Constant *getNSConcreteGlobalBlock();
- llvm::Constant *getNSConcreteStackBlock();
- llvm::Constant *getBlockObjectAssign();
- llvm::Constant *getBlockObjectDispose();
-
- ///@}
-
- llvm::Constant *getLLVMLifetimeStartFn();
- llvm::Constant *getLLVMLifetimeEndFn();
-
- // Make sure that this type is translated.
- void UpdateCompletedType(const TagDecl *TD);
-
- llvm::Constant *getMemberPointerConstant(const UnaryOperator *e);
-
- /// Emit type info if type of an expression is a variably modified
- /// type. Also emit proper debug info for cast types.
- void EmitExplicitCastExprType(const ExplicitCastExpr *E,
- CodeGenFunction *CGF = nullptr);
-
- /// Return the result of value-initializing the given type, i.e. a null
- /// expression of the given type. This is usually, but not always, an LLVM
- /// null constant.
- llvm::Constant *EmitNullConstant(QualType T);
-
- /// Return a null constant appropriate for zero-initializing a base class with
- /// the given type. This is usually, but not always, an LLVM null constant.
- llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record);
-
- /// Emit a general error that something can't be done.
- void Error(SourceLocation loc, StringRef error);
-
- /// Print out an error that codegen doesn't support the specified stmt yet.
- void ErrorUnsupported(const Stmt *S, const char *Type);
-
- /// Print out an error that codegen doesn't support the specified decl yet.
- void ErrorUnsupported(const Decl *D, const char *Type);
-
- /// Set the attributes on the LLVM function for the given decl and function
- /// info. This applies attributes necessary for handling the ABI as well as
- /// user specified attributes like section.
- void SetInternalFunctionAttributes(GlobalDecl GD, llvm::Function *F,
- const CGFunctionInfo &FI);
-
- /// Set the LLVM function attributes (sext, zext, etc).
- void SetLLVMFunctionAttributes(GlobalDecl GD, const CGFunctionInfo &Info,
- llvm::Function *F);
-
- /// Set the LLVM function attributes which only apply to a function
- /// definition.
- void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
-
- /// Return true iff the given type uses 'sret' when used as a return type.
- bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
-
- /// Return true iff the given type uses an argument slot when 'sret' is used
- /// as a return type.
- bool ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI);
-
- /// Return true iff the given type uses 'fpret' when used as a return type.
- bool ReturnTypeUsesFPRet(QualType ResultType);
-
- /// Return true iff the given type uses 'fp2ret' when used as a return type.
- bool ReturnTypeUsesFP2Ret(QualType ResultType);
-
- /// Get the LLVM attributes and calling convention to use for a particular
- /// function type.
- ///
- /// \param Name - The function name.
- /// \param Info - The function type information.
- /// \param CalleeInfo - The callee information these attributes are being
- /// constructed for. If valid, the attributes applied to this decl may
- /// contribute to the function attributes and calling convention.
- /// \param Attrs [out] - On return, the attribute list to use.
- /// \param CallingConv [out] - On return, the LLVM calling convention to use.
- void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info,
- CGCalleeInfo CalleeInfo,
- llvm::AttributeList &Attrs, unsigned &CallingConv,
- bool AttrOnCallSite);
-
- /// Adds attributes to F according to our CodeGenOptions and LangOptions, as
- /// though we had emitted it ourselves. We remove any attributes on F that
- /// conflict with the attributes we add here.
- ///
- /// This is useful for adding attrs to bitcode modules that you want to link
- /// with but don't control, such as CUDA's libdevice. When linking with such
- /// a bitcode library, you might want to set e.g. its functions'
- /// "unsafe-fp-math" attribute to match the attr of the functions you're
- /// codegen'ing. Otherwise, LLVM will interpret the bitcode module's lack of
- /// unsafe-fp-math attrs as tantamount to unsafe-fp-math=false, and then LLVM
- /// will propagate unsafe-fp-math=false up to every transitive caller of a
- /// function in the bitcode library!
- ///
- /// With the exception of fast-math attrs, this will only make the attributes
- /// on the function more conservative. But it's unsafe to call this on a
- /// function which relies on particular fast-math attributes for correctness.
- /// It's up to you to ensure that this is safe.
- void AddDefaultFnAttrs(llvm::Function &F);
-
- /// Parses the target attributes passed in, and returns only the ones that are
- /// valid feature names.
- TargetAttr::ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD);
-
- // Fills in the supplied string map with the set of target features for the
- // passed in function.
- void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, GlobalDecl GD);
-
- StringRef getMangledName(GlobalDecl GD);
- StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
-
- void EmitTentativeDefinition(const VarDecl *D);
-
- void EmitVTable(CXXRecordDecl *Class);
-
- void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
-
- /// Appends Opts to the "llvm.linker.options" metadata value.
- void AppendLinkerOptions(StringRef Opts);
-
- /// Appends a detect mismatch command to the linker options.
- void AddDetectMismatch(StringRef Name, StringRef Value);
-
- /// Appends a dependent lib to the "llvm.linker.options" metadata
- /// value.
- void AddDependentLib(StringRef Lib);
-
- void AddELFLibDirective(StringRef Lib);
-
- llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
-
- void setFunctionLinkage(GlobalDecl GD, llvm::Function *F) {
- F->setLinkage(getFunctionLinkage(GD));
- }
-
- /// Return the appropriate linkage for the vtable, VTT, and type information
- /// of the given class.
- llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD);
-
- /// Return the store size, in character units, of the given LLVM type.
- CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const;
-
- /// Returns LLVM linkage for a declarator.
- llvm::GlobalValue::LinkageTypes
- getLLVMLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage,
- bool IsConstantVariable);
-
- /// Returns LLVM linkage for a declarator.
- llvm::GlobalValue::LinkageTypes
- getLLVMLinkageVarDefinition(const VarDecl *VD, bool IsConstant);
-
- /// Emit all the global annotations.
- void EmitGlobalAnnotations();
-
- /// Emit an annotation string.
- llvm::Constant *EmitAnnotationString(StringRef Str);
-
- /// Emit the annotation's translation unit.
- llvm::Constant *EmitAnnotationUnit(SourceLocation Loc);
-
- /// Emit the annotation line number.
- llvm::Constant *EmitAnnotationLineNo(SourceLocation L);
-
- /// Generate the llvm::ConstantStruct which contains the annotation
- /// information for a given GlobalValue. The annotation struct is
- /// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the
- /// GlobalValue being annotated. The second field is the constant string
- /// created from the AnnotateAttr's annotation. The third field is a constant
- /// string containing the name of the translation unit. The fourth field is
- /// the line number in the file of the annotated value declaration.
- llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
- const AnnotateAttr *AA,
- SourceLocation L);
-
- /// Add global annotations that are set on D, for the global GV. Those
- /// annotations are emitted during finalization of the LLVM code.
- void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
-
- bool isInSanitizerBlacklist(SanitizerMask Kind, llvm::Function *Fn,
- SourceLocation Loc) const;
-
- bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc,
- QualType Ty,
- StringRef Category = StringRef()) const;
-
- /// Imbue XRay attributes to a function, applying the always/never attribute
- /// lists in the process. Returns true if we did imbue attributes this way,
- /// false otherwise.
- bool imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
- StringRef Category = StringRef()) const;
-
- SanitizerMetadata *getSanitizerMetadata() {
- return SanitizerMD.get();
- }
-
- void addDeferredVTable(const CXXRecordDecl *RD) {
- DeferredVTables.push_back(RD);
- }
-
- /// Emit code for a single global function or var decl. Forward declarations
- /// are emitted lazily.
- void EmitGlobal(GlobalDecl D);
-
- bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
-
- llvm::GlobalValue *GetGlobalValue(StringRef Ref);
-
- /// Set attributes which are common to any form of a global definition (alias,
- /// Objective-C method, function, global variable).
- ///
- /// NOTE: This should only be called for definitions.
- void SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV);
-
- void addReplacement(StringRef Name, llvm::Constant *C);
-
- void addGlobalValReplacement(llvm::GlobalValue *GV, llvm::Constant *C);
-
- /// Emit a code for threadprivate directive.
- /// \param D Threadprivate declaration.
- void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
-
- /// Emit a code for declare reduction construct.
- void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D,
- CodeGenFunction *CGF = nullptr);
-
- /// Emit a code for requires directive.
- /// \param D Requires declaration
- void EmitOMPRequiresDecl(const OMPRequiresDecl *D);
-
- /// Returns whether the given record has hidden LTO visibility and therefore
- /// may participate in (single-module) CFI and whole-program vtable
- /// optimization.
- bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);
-
- /// Emit type metadata for the given vtable using the given layout.
- void EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
- const VTableLayout &VTLayout);
-
- /// Generate a cross-DSO type identifier for MD.
- llvm::ConstantInt *CreateCrossDsoCfiTypeId(llvm::Metadata *MD);
-
- /// Create a metadata identifier for the given type. This may either be an
- /// MDString (for external identifiers) or a distinct unnamed MDNode (for
- /// internal identifiers).
- llvm::Metadata *CreateMetadataIdentifierForType(QualType T);
-
- /// Create a metadata identifier that is intended to be used to check virtual
- /// calls via a member function pointer.
- llvm::Metadata *CreateMetadataIdentifierForVirtualMemPtrType(QualType T);
-
- /// Create a metadata identifier for the generalization of the given type.
- /// This may either be an MDString (for external identifiers) or a distinct
- /// unnamed MDNode (for internal identifiers).
- llvm::Metadata *CreateMetadataIdentifierGeneralized(QualType T);
-
- /// Create and attach type metadata to the given function.
- void CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
- llvm::Function *F);
-
- /// Returns whether this module needs the "all-vtables" type identifier.
- bool NeedAllVtablesTypeId() const;
-
- /// Create and attach type metadata for the given vtable.
- void AddVTableTypeMetadata(llvm::GlobalVariable *VTable, CharUnits Offset,
- const CXXRecordDecl *RD);
-
- /// Return a vector of most-base classes for RD. This is used to implement
- /// control flow integrity checks for member function pointers.
- ///
- /// A most-base class of a class C is defined as a recursive base class of C,
- /// including C itself, that does not have any bases.
- std::vector<const CXXRecordDecl *>
- getMostBaseClasses(const CXXRecordDecl *RD);
-
- /// Get the declaration of std::terminate for the platform.
- llvm::Constant *getTerminateFn();
-
- llvm::SanitizerStatReport &getSanStats();
-
- llvm::Value *
- createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction &CGF);
-
- /// Get target specific null pointer.
- /// \param T is the LLVM type of the null pointer.
- /// \param QT is the clang QualType of the null pointer.
- llvm::Constant *getNullPointer(llvm::PointerType *T, QualType QT);
-
-private:
- llvm::Constant *GetOrCreateLLVMFunction(
- StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable,
- bool DontDefer = false, bool IsThunk = false,
- llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
- ForDefinition_t IsForDefinition = NotForDefinition);
-
- llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD,
- llvm::Type *DeclTy,
- const FunctionDecl *FD);
- void UpdateMultiVersionNames(GlobalDecl GD, const FunctionDecl *FD);
-
- llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
- llvm::PointerType *PTy,
- const VarDecl *D,
- ForDefinition_t IsForDefinition
- = NotForDefinition);
-
- bool GetCPUAndFeaturesAttributes(GlobalDecl GD,
- llvm::AttrBuilder &AttrBuilder);
- void setNonAliasAttributes(GlobalDecl GD, llvm::GlobalObject *GO);
-
- /// Set function attributes for a function declaration.
- void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
- bool IsIncompleteFunction, bool IsThunk);
-
- void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr);
-
- void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
- void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
-
- void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false);
- void EmitAliasDefinition(GlobalDecl GD);
- void emitIFuncDefinition(GlobalDecl GD);
- void emitCPUDispatchDefinition(GlobalDecl GD);
- void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
- void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
-
- // C++ related functions.
-
- void EmitDeclContext(const DeclContext *DC);
- void EmitLinkageSpec(const LinkageSpecDecl *D);
-
- /// Emit the function that initializes C++ thread_local variables.
- void EmitCXXThreadLocalInitFunc();
-
- /// Emit the function that initializes C++ globals.
- void EmitCXXGlobalInitFunc();
-
- /// Emit the function that destroys C++ globals.
- void EmitCXXGlobalDtorFunc();
-
- /// Emit the function that initializes the specified global (if PerformInit is
- /// true) and registers its destructor.
- void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
- llvm::GlobalVariable *Addr,
- bool PerformInit);
-
- void EmitPointerToInitFunc(const VarDecl *VD, llvm::GlobalVariable *Addr,
- llvm::Function *InitFunc, InitSegAttr *ISA);
-
- // FIXME: Hardcoding priority here is gross.
- void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535,
- llvm::Constant *AssociatedData = nullptr);
- void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535);
-
- /// EmitCtorList - Generates a global array of functions and priorities using
- /// the given list and name. This array will have appending linkage and is
- /// suitable for use as a LLVM constructor or destructor array. Clears Fns.
- void EmitCtorList(CtorList &Fns, const char *GlobalName);
-
- /// Emit any needed decls for which code generation was deferred.
- void EmitDeferred();
-
- /// Try to emit external vtables as available_externally if they have emitted
- /// all inlined virtual functions. It runs after EmitDeferred() and therefore
- /// is not allowed to create new references to things that need to be emitted
- /// lazily.
- void EmitVTablesOpportunistically();
-
- /// Call replaceAllUsesWith on all pairs in Replacements.
- void applyReplacements();
-
- /// Call replaceAllUsesWith on all pairs in GlobalValReplacements.
- void applyGlobalValReplacements();
-
- void checkAliases();
-
- std::map<int, llvm::TinyPtrVector<llvm::Function *>> DtorsUsingAtExit;
-
- /// Register functions annotated with __attribute__((destructor)) using
- /// __cxa_atexit, if it is available, or atexit otherwise.
- void registerGlobalDtorsWithAtExit();
-
- void emitMultiVersionFunctions();
-
- /// Emit any vtables which we deferred and still have a use for.
- void EmitDeferredVTables();
-
- /// Emit a dummy function that reference a CoreFoundation symbol when
- /// @available is used on Darwin.
- void emitAtAvailableLinkGuard();
-
- /// Emit the llvm.used and llvm.compiler.used metadata.
- void emitLLVMUsed();
-
- /// Emit the link options introduced by imported modules.
- void EmitModuleLinkOptions();
-
- /// Emit aliases for internal-linkage declarations inside "C" language
- /// linkage specifications, giving them the "expected" name where possible.
- void EmitStaticExternCAliases();
-
- void EmitDeclMetadata();
-
- /// Emit the Clang version as llvm.ident metadata.
- void EmitVersionIdentMetadata();
-
- /// Emit the Clang commandline as llvm.commandline metadata.
- void EmitCommandLineMetadata();
-
- /// Emits target specific Metadata for global declarations.
- void EmitTargetMetadata();
-
- /// Emits OpenCL specific Metadata e.g. OpenCL version.
- void EmitOpenCLMetadata();
-
- /// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and
- /// .gcda files in a way that persists in .bc files.
- void EmitCoverageFile();
-
- /// Emits the initializer for a uuidof string.
- llvm::Constant *EmitUuidofInitializer(StringRef uuidstr);
-
- /// Determine whether the definition must be emitted; if this returns \c
- /// false, the definition can be emitted lazily if it's used.
- bool MustBeEmitted(const ValueDecl *D);
-
- /// Determine whether the definition can be emitted eagerly, or should be
- /// delayed until the end of the translation unit. This is relevant for
- /// definitions whose linkage can change, e.g. implicit function instantions
- /// which may later be explicitly instantiated.
- bool MayBeEmittedEagerly(const ValueDecl *D);
-
- /// Check whether we can use a "simpler", more core exceptions personality
- /// function.
- void SimplifyPersonality();
-
- /// Helper function for ConstructAttributeList and AddDefaultFnAttrs.
- /// Constructs an AttrList for a function with the given properties.
- void ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
- bool AttrOnCallSite,
- llvm::AttrBuilder &FuncAttrs);
-
- llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
- StringRef Suffix);
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp
deleted file mode 100644
index 776060743a6..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp
+++ /dev/null
@@ -1,1059 +0,0 @@
-//===--- CodeGenPGO.cpp - PGO Instrumentation for LLVM CodeGen --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Instrumentation-based profile-guided optimization
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenPGO.h"
-#include "CodeGenFunction.h"
-#include "CoverageMappingGen.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/StmtVisitor.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MD5.h"
-
-static llvm::cl::opt<bool>
- EnableValueProfiling("enable-value-profiling", llvm::cl::ZeroOrMore,
- llvm::cl::desc("Enable value profiling"),
- llvm::cl::Hidden, llvm::cl::init(false));
-
-using namespace clang;
-using namespace CodeGen;
-
-void CodeGenPGO::setFuncName(StringRef Name,
- llvm::GlobalValue::LinkageTypes Linkage) {
- llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
- FuncName = llvm::getPGOFuncName(
- Name, Linkage, CGM.getCodeGenOpts().MainFileName,
- PGOReader ? PGOReader->getVersion() : llvm::IndexedInstrProf::Version);
-
- // If we're generating a profile, create a variable for the name.
- if (CGM.getCodeGenOpts().hasProfileClangInstr())
- FuncNameVar = llvm::createPGOFuncNameVar(CGM.getModule(), Linkage, FuncName);
-}
-
-void CodeGenPGO::setFuncName(llvm::Function *Fn) {
- setFuncName(Fn->getName(), Fn->getLinkage());
- // Create PGOFuncName meta data.
- llvm::createPGOFuncNameMetadata(*Fn, FuncName);
-}
-
-/// The version of the PGO hash algorithm.
-enum PGOHashVersion : unsigned {
- PGO_HASH_V1,
- PGO_HASH_V2,
-
- // Keep this set to the latest hash version.
- PGO_HASH_LATEST = PGO_HASH_V2
-};
-
-namespace {
-/// Stable hasher for PGO region counters.
-///
-/// PGOHash produces a stable hash of a given function's control flow.
-///
-/// Changing the output of this hash will invalidate all previously generated
-/// profiles -- i.e., don't do it.
-///
-/// \note When this hash does eventually change (years?), we still need to
-/// support old hashes. We'll need to pull in the version number from the
-/// profile data format and use the matching hash function.
-class PGOHash {
- uint64_t Working;
- unsigned Count;
- PGOHashVersion HashVersion;
- llvm::MD5 MD5;
-
- static const int NumBitsPerType = 6;
- static const unsigned NumTypesPerWord = sizeof(uint64_t) * 8 / NumBitsPerType;
- static const unsigned TooBig = 1u << NumBitsPerType;
-
-public:
- /// Hash values for AST nodes.
- ///
- /// Distinct values for AST nodes that have region counters attached.
- ///
- /// These values must be stable. All new members must be added at the end,
- /// and no members should be removed. Changing the enumeration value for an
- /// AST node will affect the hash of every function that contains that node.
- enum HashType : unsigned char {
- None = 0,
- LabelStmt = 1,
- WhileStmt,
- DoStmt,
- ForStmt,
- CXXForRangeStmt,
- ObjCForCollectionStmt,
- SwitchStmt,
- CaseStmt,
- DefaultStmt,
- IfStmt,
- CXXTryStmt,
- CXXCatchStmt,
- ConditionalOperator,
- BinaryOperatorLAnd,
- BinaryOperatorLOr,
- BinaryConditionalOperator,
- // The preceding values are available with PGO_HASH_V1.
-
- EndOfScope,
- IfThenBranch,
- IfElseBranch,
- GotoStmt,
- IndirectGotoStmt,
- BreakStmt,
- ContinueStmt,
- ReturnStmt,
- ThrowExpr,
- UnaryOperatorLNot,
- BinaryOperatorLT,
- BinaryOperatorGT,
- BinaryOperatorLE,
- BinaryOperatorGE,
- BinaryOperatorEQ,
- BinaryOperatorNE,
- // The preceding values are available with PGO_HASH_V2.
-
- // Keep this last. It's for the static assert that follows.
- LastHashType
- };
- static_assert(LastHashType <= TooBig, "Too many types in HashType");
-
- PGOHash(PGOHashVersion HashVersion)
- : Working(0), Count(0), HashVersion(HashVersion), MD5() {}
- void combine(HashType Type);
- uint64_t finalize();
- PGOHashVersion getHashVersion() const { return HashVersion; }
-};
-const int PGOHash::NumBitsPerType;
-const unsigned PGOHash::NumTypesPerWord;
-const unsigned PGOHash::TooBig;
-
-/// Get the PGO hash version used in the given indexed profile.
-static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader,
- CodeGenModule &CGM) {
- if (PGOReader->getVersion() <= 4)
- return PGO_HASH_V1;
- return PGO_HASH_V2;
-}
-
-/// A RecursiveASTVisitor that fills a map of statements to PGO counters.
-struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
- using Base = RecursiveASTVisitor<MapRegionCounters>;
-
- /// The next counter value to assign.
- unsigned NextCounter;
- /// The function hash.
- PGOHash Hash;
- /// The map of statements to counters.
- llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
-
- MapRegionCounters(PGOHashVersion HashVersion,
- llvm::DenseMap<const Stmt *, unsigned> &CounterMap)
- : NextCounter(0), Hash(HashVersion), CounterMap(CounterMap) {}
-
- // Blocks and lambdas are handled as separate functions, so we need not
- // traverse them in the parent context.
- bool TraverseBlockExpr(BlockExpr *BE) { return true; }
- bool TraverseLambdaExpr(LambdaExpr *LE) {
- // Traverse the captures, but not the body.
- for (const auto &C : zip(LE->captures(), LE->capture_inits()))
- TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
- return true;
- }
- bool TraverseCapturedStmt(CapturedStmt *CS) { return true; }
-
- bool VisitDecl(const Decl *D) {
- switch (D->getKind()) {
- default:
- break;
- case Decl::Function:
- case Decl::CXXMethod:
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::ObjCMethod:
- case Decl::Block:
- case Decl::Captured:
- CounterMap[D->getBody()] = NextCounter++;
- break;
- }
- return true;
- }
-
- /// If \p S gets a fresh counter, update the counter mappings. Return the
- /// V1 hash of \p S.
- PGOHash::HashType updateCounterMappings(Stmt *S) {
- auto Type = getHashType(PGO_HASH_V1, S);
- if (Type != PGOHash::None)
- CounterMap[S] = NextCounter++;
- return Type;
- }
-
- /// Include \p S in the function hash.
- bool VisitStmt(Stmt *S) {
- auto Type = updateCounterMappings(S);
- if (Hash.getHashVersion() != PGO_HASH_V1)
- Type = getHashType(Hash.getHashVersion(), S);
- if (Type != PGOHash::None)
- Hash.combine(Type);
- return true;
- }
-
- bool TraverseIfStmt(IfStmt *If) {
- // If we used the V1 hash, use the default traversal.
- if (Hash.getHashVersion() == PGO_HASH_V1)
- return Base::TraverseIfStmt(If);
-
- // Otherwise, keep track of which branch we're in while traversing.
- VisitStmt(If);
- for (Stmt *CS : If->children()) {
- if (!CS)
- continue;
- if (CS == If->getThen())
- Hash.combine(PGOHash::IfThenBranch);
- else if (CS == If->getElse())
- Hash.combine(PGOHash::IfElseBranch);
- TraverseStmt(CS);
- }
- Hash.combine(PGOHash::EndOfScope);
- return true;
- }
-
-// If the statement type \p N is nestable, and its nesting impacts profile
-// stability, define a custom traversal which tracks the end of the statement
-// in the hash (provided we're not using the V1 hash).
-#define DEFINE_NESTABLE_TRAVERSAL(N) \
- bool Traverse##N(N *S) { \
- Base::Traverse##N(S); \
- if (Hash.getHashVersion() != PGO_HASH_V1) \
- Hash.combine(PGOHash::EndOfScope); \
- return true; \
- }
-
- DEFINE_NESTABLE_TRAVERSAL(WhileStmt)
- DEFINE_NESTABLE_TRAVERSAL(DoStmt)
- DEFINE_NESTABLE_TRAVERSAL(ForStmt)
- DEFINE_NESTABLE_TRAVERSAL(CXXForRangeStmt)
- DEFINE_NESTABLE_TRAVERSAL(ObjCForCollectionStmt)
- DEFINE_NESTABLE_TRAVERSAL(CXXTryStmt)
- DEFINE_NESTABLE_TRAVERSAL(CXXCatchStmt)
-
- /// Get version \p HashVersion of the PGO hash for \p S.
- PGOHash::HashType getHashType(PGOHashVersion HashVersion, const Stmt *S) {
- switch (S->getStmtClass()) {
- default:
- break;
- case Stmt::LabelStmtClass:
- return PGOHash::LabelStmt;
- case Stmt::WhileStmtClass:
- return PGOHash::WhileStmt;
- case Stmt::DoStmtClass:
- return PGOHash::DoStmt;
- case Stmt::ForStmtClass:
- return PGOHash::ForStmt;
- case Stmt::CXXForRangeStmtClass:
- return PGOHash::CXXForRangeStmt;
- case Stmt::ObjCForCollectionStmtClass:
- return PGOHash::ObjCForCollectionStmt;
- case Stmt::SwitchStmtClass:
- return PGOHash::SwitchStmt;
- case Stmt::CaseStmtClass:
- return PGOHash::CaseStmt;
- case Stmt::DefaultStmtClass:
- return PGOHash::DefaultStmt;
- case Stmt::IfStmtClass:
- return PGOHash::IfStmt;
- case Stmt::CXXTryStmtClass:
- return PGOHash::CXXTryStmt;
- case Stmt::CXXCatchStmtClass:
- return PGOHash::CXXCatchStmt;
- case Stmt::ConditionalOperatorClass:
- return PGOHash::ConditionalOperator;
- case Stmt::BinaryConditionalOperatorClass:
- return PGOHash::BinaryConditionalOperator;
- case Stmt::BinaryOperatorClass: {
- const BinaryOperator *BO = cast<BinaryOperator>(S);
- if (BO->getOpcode() == BO_LAnd)
- return PGOHash::BinaryOperatorLAnd;
- if (BO->getOpcode() == BO_LOr)
- return PGOHash::BinaryOperatorLOr;
- if (HashVersion == PGO_HASH_V2) {
- switch (BO->getOpcode()) {
- default:
- break;
- case BO_LT:
- return PGOHash::BinaryOperatorLT;
- case BO_GT:
- return PGOHash::BinaryOperatorGT;
- case BO_LE:
- return PGOHash::BinaryOperatorLE;
- case BO_GE:
- return PGOHash::BinaryOperatorGE;
- case BO_EQ:
- return PGOHash::BinaryOperatorEQ;
- case BO_NE:
- return PGOHash::BinaryOperatorNE;
- }
- }
- break;
- }
- }
-
- if (HashVersion == PGO_HASH_V2) {
- switch (S->getStmtClass()) {
- default:
- break;
- case Stmt::GotoStmtClass:
- return PGOHash::GotoStmt;
- case Stmt::IndirectGotoStmtClass:
- return PGOHash::IndirectGotoStmt;
- case Stmt::BreakStmtClass:
- return PGOHash::BreakStmt;
- case Stmt::ContinueStmtClass:
- return PGOHash::ContinueStmt;
- case Stmt::ReturnStmtClass:
- return PGOHash::ReturnStmt;
- case Stmt::CXXThrowExprClass:
- return PGOHash::ThrowExpr;
- case Stmt::UnaryOperatorClass: {
- const UnaryOperator *UO = cast<UnaryOperator>(S);
- if (UO->getOpcode() == UO_LNot)
- return PGOHash::UnaryOperatorLNot;
- break;
- }
- }
- }
-
- return PGOHash::None;
- }
-};
-
-/// A StmtVisitor that propagates the raw counts through the AST and
-/// records the count at statements where the value may change.
-struct ComputeRegionCounts : public ConstStmtVisitor<ComputeRegionCounts> {
- /// PGO state.
- CodeGenPGO &PGO;
-
- /// A flag that is set when the current count should be recorded on the
- /// next statement, such as at the exit of a loop.
- bool RecordNextStmtCount;
-
- /// The count at the current location in the traversal.
- uint64_t CurrentCount;
-
- /// The map of statements to count values.
- llvm::DenseMap<const Stmt *, uint64_t> &CountMap;
-
- /// BreakContinueStack - Keep counts of breaks and continues inside loops.
- struct BreakContinue {
- uint64_t BreakCount;
- uint64_t ContinueCount;
- BreakContinue() : BreakCount(0), ContinueCount(0) {}
- };
- SmallVector<BreakContinue, 8> BreakContinueStack;
-
- ComputeRegionCounts(llvm::DenseMap<const Stmt *, uint64_t> &CountMap,
- CodeGenPGO &PGO)
- : PGO(PGO), RecordNextStmtCount(false), CountMap(CountMap) {}
-
- void RecordStmtCount(const Stmt *S) {
- if (RecordNextStmtCount) {
- CountMap[S] = CurrentCount;
- RecordNextStmtCount = false;
- }
- }
-
- /// Set and return the current count.
- uint64_t setCount(uint64_t Count) {
- CurrentCount = Count;
- return Count;
- }
-
- void VisitStmt(const Stmt *S) {
- RecordStmtCount(S);
- for (const Stmt *Child : S->children())
- if (Child)
- this->Visit(Child);
- }
-
- void VisitFunctionDecl(const FunctionDecl *D) {
- // Counter tracks entry to the function body.
- uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody()));
- CountMap[D->getBody()] = BodyCount;
- Visit(D->getBody());
- }
-
- // Skip lambda expressions. We visit these as FunctionDecls when we're
- // generating them and aren't interested in the body when generating a
- // parent context.
- void VisitLambdaExpr(const LambdaExpr *LE) {}
-
- void VisitCapturedDecl(const CapturedDecl *D) {
- // Counter tracks entry to the capture body.
- uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody()));
- CountMap[D->getBody()] = BodyCount;
- Visit(D->getBody());
- }
-
- void VisitObjCMethodDecl(const ObjCMethodDecl *D) {
- // Counter tracks entry to the method body.
- uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody()));
- CountMap[D->getBody()] = BodyCount;
- Visit(D->getBody());
- }
-
- void VisitBlockDecl(const BlockDecl *D) {
- // Counter tracks entry to the block body.
- uint64_t BodyCount = setCount(PGO.getRegionCount(D->getBody()));
- CountMap[D->getBody()] = BodyCount;
- Visit(D->getBody());
- }
-
- void VisitReturnStmt(const ReturnStmt *S) {
- RecordStmtCount(S);
- if (S->getRetValue())
- Visit(S->getRetValue());
- CurrentCount = 0;
- RecordNextStmtCount = true;
- }
-
- void VisitCXXThrowExpr(const CXXThrowExpr *E) {
- RecordStmtCount(E);
- if (E->getSubExpr())
- Visit(E->getSubExpr());
- CurrentCount = 0;
- RecordNextStmtCount = true;
- }
-
- void VisitGotoStmt(const GotoStmt *S) {
- RecordStmtCount(S);
- CurrentCount = 0;
- RecordNextStmtCount = true;
- }
-
- void VisitLabelStmt(const LabelStmt *S) {
- RecordNextStmtCount = false;
- // Counter tracks the block following the label.
- uint64_t BlockCount = setCount(PGO.getRegionCount(S));
- CountMap[S] = BlockCount;
- Visit(S->getSubStmt());
- }
-
- void VisitBreakStmt(const BreakStmt *S) {
- RecordStmtCount(S);
- assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
- BreakContinueStack.back().BreakCount += CurrentCount;
- CurrentCount = 0;
- RecordNextStmtCount = true;
- }
-
- void VisitContinueStmt(const ContinueStmt *S) {
- RecordStmtCount(S);
- assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
- BreakContinueStack.back().ContinueCount += CurrentCount;
- CurrentCount = 0;
- RecordNextStmtCount = true;
- }
-
- void VisitWhileStmt(const WhileStmt *S) {
- RecordStmtCount(S);
- uint64_t ParentCount = CurrentCount;
-
- BreakContinueStack.push_back(BreakContinue());
- // Visit the body region first so the break/continue adjustments can be
- // included when visiting the condition.
- uint64_t BodyCount = setCount(PGO.getRegionCount(S));
- CountMap[S->getBody()] = CurrentCount;
- Visit(S->getBody());
- uint64_t BackedgeCount = CurrentCount;
-
- // ...then go back and propagate counts through the condition. The count
- // at the start of the condition is the sum of the incoming edges,
- // the backedge from the end of the loop body, and the edges from
- // continue statements.
- BreakContinue BC = BreakContinueStack.pop_back_val();
- uint64_t CondCount =
- setCount(ParentCount + BackedgeCount + BC.ContinueCount);
- CountMap[S->getCond()] = CondCount;
- Visit(S->getCond());
- setCount(BC.BreakCount + CondCount - BodyCount);
- RecordNextStmtCount = true;
- }
-
- void VisitDoStmt(const DoStmt *S) {
- RecordStmtCount(S);
- uint64_t LoopCount = PGO.getRegionCount(S);
-
- BreakContinueStack.push_back(BreakContinue());
- // The count doesn't include the fallthrough from the parent scope. Add it.
- uint64_t BodyCount = setCount(LoopCount + CurrentCount);
- CountMap[S->getBody()] = BodyCount;
- Visit(S->getBody());
- uint64_t BackedgeCount = CurrentCount;
-
- BreakContinue BC = BreakContinueStack.pop_back_val();
- // The count at the start of the condition is equal to the count at the
- // end of the body, plus any continues.
- uint64_t CondCount = setCount(BackedgeCount + BC.ContinueCount);
- CountMap[S->getCond()] = CondCount;
- Visit(S->getCond());
- setCount(BC.BreakCount + CondCount - LoopCount);
- RecordNextStmtCount = true;
- }
-
- void VisitForStmt(const ForStmt *S) {
- RecordStmtCount(S);
- if (S->getInit())
- Visit(S->getInit());
-
- uint64_t ParentCount = CurrentCount;
-
- BreakContinueStack.push_back(BreakContinue());
- // Visit the body region first. (This is basically the same as a while
- // loop; see further comments in VisitWhileStmt.)
- uint64_t BodyCount = setCount(PGO.getRegionCount(S));
- CountMap[S->getBody()] = BodyCount;
- Visit(S->getBody());
- uint64_t BackedgeCount = CurrentCount;
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- // The increment is essentially part of the body but it needs to include
- // the count for all the continue statements.
- if (S->getInc()) {
- uint64_t IncCount = setCount(BackedgeCount + BC.ContinueCount);
- CountMap[S->getInc()] = IncCount;
- Visit(S->getInc());
- }
-
- // ...then go back and propagate counts through the condition.
- uint64_t CondCount =
- setCount(ParentCount + BackedgeCount + BC.ContinueCount);
- if (S->getCond()) {
- CountMap[S->getCond()] = CondCount;
- Visit(S->getCond());
- }
- setCount(BC.BreakCount + CondCount - BodyCount);
- RecordNextStmtCount = true;
- }
-
- void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
- RecordStmtCount(S);
- if (S->getInit())
- Visit(S->getInit());
- Visit(S->getLoopVarStmt());
- Visit(S->getRangeStmt());
- Visit(S->getBeginStmt());
- Visit(S->getEndStmt());
-
- uint64_t ParentCount = CurrentCount;
- BreakContinueStack.push_back(BreakContinue());
- // Visit the body region first. (This is basically the same as a while
- // loop; see further comments in VisitWhileStmt.)
- uint64_t BodyCount = setCount(PGO.getRegionCount(S));
- CountMap[S->getBody()] = BodyCount;
- Visit(S->getBody());
- uint64_t BackedgeCount = CurrentCount;
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- // The increment is essentially part of the body but it needs to include
- // the count for all the continue statements.
- uint64_t IncCount = setCount(BackedgeCount + BC.ContinueCount);
- CountMap[S->getInc()] = IncCount;
- Visit(S->getInc());
-
- // ...then go back and propagate counts through the condition.
- uint64_t CondCount =
- setCount(ParentCount + BackedgeCount + BC.ContinueCount);
- CountMap[S->getCond()] = CondCount;
- Visit(S->getCond());
- setCount(BC.BreakCount + CondCount - BodyCount);
- RecordNextStmtCount = true;
- }
-
- void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
- RecordStmtCount(S);
- Visit(S->getElement());
- uint64_t ParentCount = CurrentCount;
- BreakContinueStack.push_back(BreakContinue());
- // Counter tracks the body of the loop.
- uint64_t BodyCount = setCount(PGO.getRegionCount(S));
- CountMap[S->getBody()] = BodyCount;
- Visit(S->getBody());
- uint64_t BackedgeCount = CurrentCount;
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- setCount(BC.BreakCount + ParentCount + BackedgeCount + BC.ContinueCount -
- BodyCount);
- RecordNextStmtCount = true;
- }
-
- void VisitSwitchStmt(const SwitchStmt *S) {
- RecordStmtCount(S);
- if (S->getInit())
- Visit(S->getInit());
- Visit(S->getCond());
- CurrentCount = 0;
- BreakContinueStack.push_back(BreakContinue());
- Visit(S->getBody());
- // If the switch is inside a loop, add the continue counts.
- BreakContinue BC = BreakContinueStack.pop_back_val();
- if (!BreakContinueStack.empty())
- BreakContinueStack.back().ContinueCount += BC.ContinueCount;
- // Counter tracks the exit block of the switch.
- setCount(PGO.getRegionCount(S));
- RecordNextStmtCount = true;
- }
-
- void VisitSwitchCase(const SwitchCase *S) {
- RecordNextStmtCount = false;
- // Counter for this particular case. This counts only jumps from the
- // switch header and does not include fallthrough from the case before
- // this one.
- uint64_t CaseCount = PGO.getRegionCount(S);
- setCount(CurrentCount + CaseCount);
- // We need the count without fallthrough in the mapping, so it's more useful
- // for branch probabilities.
- CountMap[S] = CaseCount;
- RecordNextStmtCount = true;
- Visit(S->getSubStmt());
- }
-
- void VisitIfStmt(const IfStmt *S) {
- RecordStmtCount(S);
- uint64_t ParentCount = CurrentCount;
- if (S->getInit())
- Visit(S->getInit());
- Visit(S->getCond());
-
- // Counter tracks the "then" part of an if statement. The count for
- // the "else" part, if it exists, will be calculated from this counter.
- uint64_t ThenCount = setCount(PGO.getRegionCount(S));
- CountMap[S->getThen()] = ThenCount;
- Visit(S->getThen());
- uint64_t OutCount = CurrentCount;
-
- uint64_t ElseCount = ParentCount - ThenCount;
- if (S->getElse()) {
- setCount(ElseCount);
- CountMap[S->getElse()] = ElseCount;
- Visit(S->getElse());
- OutCount += CurrentCount;
- } else
- OutCount += ElseCount;
- setCount(OutCount);
- RecordNextStmtCount = true;
- }
-
- void VisitCXXTryStmt(const CXXTryStmt *S) {
- RecordStmtCount(S);
- Visit(S->getTryBlock());
- for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
- Visit(S->getHandler(I));
- // Counter tracks the continuation block of the try statement.
- setCount(PGO.getRegionCount(S));
- RecordNextStmtCount = true;
- }
-
- void VisitCXXCatchStmt(const CXXCatchStmt *S) {
- RecordNextStmtCount = false;
- // Counter tracks the catch statement's handler block.
- uint64_t CatchCount = setCount(PGO.getRegionCount(S));
- CountMap[S] = CatchCount;
- Visit(S->getHandlerBlock());
- }
-
- void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
- RecordStmtCount(E);
- uint64_t ParentCount = CurrentCount;
- Visit(E->getCond());
-
- // Counter tracks the "true" part of a conditional operator. The
- // count in the "false" part will be calculated from this counter.
- uint64_t TrueCount = setCount(PGO.getRegionCount(E));
- CountMap[E->getTrueExpr()] = TrueCount;
- Visit(E->getTrueExpr());
- uint64_t OutCount = CurrentCount;
-
- uint64_t FalseCount = setCount(ParentCount - TrueCount);
- CountMap[E->getFalseExpr()] = FalseCount;
- Visit(E->getFalseExpr());
- OutCount += CurrentCount;
-
- setCount(OutCount);
- RecordNextStmtCount = true;
- }
-
- void VisitBinLAnd(const BinaryOperator *E) {
- RecordStmtCount(E);
- uint64_t ParentCount = CurrentCount;
- Visit(E->getLHS());
- // Counter tracks the right hand side of a logical and operator.
- uint64_t RHSCount = setCount(PGO.getRegionCount(E));
- CountMap[E->getRHS()] = RHSCount;
- Visit(E->getRHS());
- setCount(ParentCount + RHSCount - CurrentCount);
- RecordNextStmtCount = true;
- }
-
- void VisitBinLOr(const BinaryOperator *E) {
- RecordStmtCount(E);
- uint64_t ParentCount = CurrentCount;
- Visit(E->getLHS());
- // Counter tracks the right hand side of a logical or operator.
- uint64_t RHSCount = setCount(PGO.getRegionCount(E));
- CountMap[E->getRHS()] = RHSCount;
- Visit(E->getRHS());
- setCount(ParentCount + RHSCount - CurrentCount);
- RecordNextStmtCount = true;
- }
-};
-} // end anonymous namespace
-
-void PGOHash::combine(HashType Type) {
- // Check that we never combine 0 and only have six bits.
- assert(Type && "Hash is invalid: unexpected type 0");
- assert(unsigned(Type) < TooBig && "Hash is invalid: too many types");
-
- // Pass through MD5 if enough work has built up.
- if (Count && Count % NumTypesPerWord == 0) {
- using namespace llvm::support;
- uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working);
- MD5.update(llvm::makeArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));
- Working = 0;
- }
-
- // Accumulate the current type.
- ++Count;
- Working = Working << NumBitsPerType | Type;
-}
-
-uint64_t PGOHash::finalize() {
- // Use Working as the hash directly if we never used MD5.
- if (Count <= NumTypesPerWord)
- // No need to byte swap here, since none of the math was endian-dependent.
- // This number will be byte-swapped as required on endianness transitions,
- // so we will see the same value on the other side.
- return Working;
-
- // Check for remaining work in Working.
- if (Working)
- MD5.update(Working);
-
- // Finalize the MD5 and return the hash.
- llvm::MD5::MD5Result Result;
- MD5.final(Result);
- using namespace llvm::support;
- return Result.low();
-}
-
-void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
- const Decl *D = GD.getDecl();
- if (!D->hasBody())
- return;
-
- bool InstrumentRegions = CGM.getCodeGenOpts().hasProfileClangInstr();
- llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
- if (!InstrumentRegions && !PGOReader)
- return;
- if (D->isImplicit())
- return;
- // Constructors and destructors may be represented by several functions in IR.
- // If so, instrument only base variant, others are implemented by delegation
- // to the base one, it would be counted twice otherwise.
- if (CGM.getTarget().getCXXABI().hasConstructorVariants()) {
- if (isa<CXXDestructorDecl>(D) && GD.getDtorType() != Dtor_Base)
- return;
-
- if (const auto *CCD = dyn_cast<CXXConstructorDecl>(D))
- if (GD.getCtorType() != Ctor_Base &&
- CodeGenFunction::IsConstructorDelegationValid(CCD))
- return;
- }
- CGM.ClearUnusedCoverageMapping(D);
- setFuncName(Fn);
-
- mapRegionCounters(D);
- if (CGM.getCodeGenOpts().CoverageMapping)
- emitCounterRegionMapping(D);
- if (PGOReader) {
- SourceManager &SM = CGM.getContext().getSourceManager();
- loadRegionCounts(PGOReader, SM.isInMainFile(D->getLocation()));
- computeRegionCounts(D);
- applyFunctionAttributes(PGOReader, Fn);
- }
-}
-
-void CodeGenPGO::mapRegionCounters(const Decl *D) {
- // Use the latest hash version when inserting instrumentation, but use the
- // version in the indexed profile if we're reading PGO data.
- PGOHashVersion HashVersion = PGO_HASH_LATEST;
- if (auto *PGOReader = CGM.getPGOReader())
- HashVersion = getPGOHashVersion(PGOReader, CGM);
-
- RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
- MapRegionCounters Walker(HashVersion, *RegionCounterMap);
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));
- else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
- Walker.TraverseDecl(const_cast<ObjCMethodDecl *>(MD));
- else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D))
- Walker.TraverseDecl(const_cast<BlockDecl *>(BD));
- else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D))
- Walker.TraverseDecl(const_cast<CapturedDecl *>(CD));
- assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");
- NumRegionCounters = Walker.NextCounter;
- FunctionHash = Walker.Hash.finalize();
-}
-
-bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) {
- if (!D->getBody())
- return true;
-
- // Don't map the functions in system headers.
- const auto &SM = CGM.getContext().getSourceManager();
- auto Loc = D->getBody()->getBeginLoc();
- return SM.isInSystemHeader(Loc);
-}
-
-void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {
- if (skipRegionMappingForDecl(D))
- return;
-
- std::string CoverageMapping;
- llvm::raw_string_ostream OS(CoverageMapping);
- CoverageMappingGen MappingGen(*CGM.getCoverageMapping(),
- CGM.getContext().getSourceManager(),
- CGM.getLangOpts(), RegionCounterMap.get());
- MappingGen.emitCounterMapping(D, OS);
- OS.flush();
-
- if (CoverageMapping.empty())
- return;
-
- CGM.getCoverageMapping()->addFunctionMappingRecord(
- FuncNameVar, FuncName, FunctionHash, CoverageMapping);
-}
-
-void
-CodeGenPGO::emitEmptyCounterMapping(const Decl *D, StringRef Name,
- llvm::GlobalValue::LinkageTypes Linkage) {
- if (skipRegionMappingForDecl(D))
- return;
-
- std::string CoverageMapping;
- llvm::raw_string_ostream OS(CoverageMapping);
- CoverageMappingGen MappingGen(*CGM.getCoverageMapping(),
- CGM.getContext().getSourceManager(),
- CGM.getLangOpts());
- MappingGen.emitEmptyMapping(D, OS);
- OS.flush();
-
- if (CoverageMapping.empty())
- return;
-
- setFuncName(Name, Linkage);
- CGM.getCoverageMapping()->addFunctionMappingRecord(
- FuncNameVar, FuncName, FunctionHash, CoverageMapping, false);
-}
-
-void CodeGenPGO::computeRegionCounts(const Decl *D) {
- StmtCountMap.reset(new llvm::DenseMap<const Stmt *, uint64_t>);
- ComputeRegionCounts Walker(*StmtCountMap, *this);
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- Walker.VisitFunctionDecl(FD);
- else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
- Walker.VisitObjCMethodDecl(MD);
- else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D))
- Walker.VisitBlockDecl(BD);
- else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D))
- Walker.VisitCapturedDecl(const_cast<CapturedDecl *>(CD));
-}
-
-void
-CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
- llvm::Function *Fn) {
- if (!haveRegionCounts())
- return;
-
- uint64_t FunctionCount = getRegionCount(nullptr);
- Fn->setEntryCount(FunctionCount);
-}
-
-void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
- llvm::Value *StepV) {
- if (!CGM.getCodeGenOpts().hasProfileClangInstr() || !RegionCounterMap)
- return;
- if (!Builder.GetInsertBlock())
- return;
-
- unsigned Counter = (*RegionCounterMap)[S];
- auto *I8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
-
- llvm::Value *Args[] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
- Builder.getInt64(FunctionHash),
- Builder.getInt32(NumRegionCounters),
- Builder.getInt32(Counter), StepV};
- if (!StepV)
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment),
- makeArrayRef(Args, 4));
- else
- Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step),
- makeArrayRef(Args));
-}
-
-// This method either inserts a call to the profile run-time during
-// instrumentation or puts profile data into metadata for PGO use.
-void CodeGenPGO::valueProfile(CGBuilderTy &Builder, uint32_t ValueKind,
- llvm::Instruction *ValueSite, llvm::Value *ValuePtr) {
-
- if (!EnableValueProfiling)
- return;
-
- if (!ValuePtr || !ValueSite || !Builder.GetInsertBlock())
- return;
-
- if (isa<llvm::Constant>(ValuePtr))
- return;
-
- bool InstrumentValueSites = CGM.getCodeGenOpts().hasProfileClangInstr();
- if (InstrumentValueSites && RegionCounterMap) {
- auto BuilderInsertPoint = Builder.saveIP();
- Builder.SetInsertPoint(ValueSite);
- llvm::Value *Args[5] = {
- llvm::ConstantExpr::getBitCast(FuncNameVar, Builder.getInt8PtrTy()),
- Builder.getInt64(FunctionHash),
- Builder.CreatePtrToInt(ValuePtr, Builder.getInt64Ty()),
- Builder.getInt32(ValueKind),
- Builder.getInt32(NumValueSites[ValueKind]++)
- };
- Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::instrprof_value_profile), Args);
- Builder.restoreIP(BuilderInsertPoint);
- return;
- }
-
- llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
- if (PGOReader && haveRegionCounts()) {
- // We record the top most called three functions at each call site.
- // Profile metadata contains "VP" string identifying this metadata
- // as value profiling data, then a uint32_t value for the value profiling
- // kind, a uint64_t value for the total number of times the call is
- // executed, followed by the function hash and execution count (uint64_t)
- // pairs for each function.
- if (NumValueSites[ValueKind] >= ProfRecord->getNumValueSites(ValueKind))
- return;
-
- llvm::annotateValueSite(CGM.getModule(), *ValueSite, *ProfRecord,
- (llvm::InstrProfValueKind)ValueKind,
- NumValueSites[ValueKind]);
-
- NumValueSites[ValueKind]++;
- }
-}
-
-void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
- bool IsInMainFile) {
- CGM.getPGOStats().addVisited(IsInMainFile);
- RegionCounts.clear();
- llvm::Expected<llvm::InstrProfRecord> RecordExpected =
- PGOReader->getInstrProfRecord(FuncName, FunctionHash);
- if (auto E = RecordExpected.takeError()) {
- auto IPE = llvm::InstrProfError::take(std::move(E));
- if (IPE == llvm::instrprof_error::unknown_function)
- CGM.getPGOStats().addMissing(IsInMainFile);
- else if (IPE == llvm::instrprof_error::hash_mismatch)
- CGM.getPGOStats().addMismatched(IsInMainFile);
- else if (IPE == llvm::instrprof_error::malformed)
- // TODO: Consider a more specific warning for this case.
- CGM.getPGOStats().addMismatched(IsInMainFile);
- return;
- }
- ProfRecord =
- llvm::make_unique<llvm::InstrProfRecord>(std::move(RecordExpected.get()));
- RegionCounts = ProfRecord->Counts;
-}
-
-/// Calculate what to divide by to scale weights.
-///
-/// Given the maximum weight, calculate a divisor that will scale all the
-/// weights to strictly less than UINT32_MAX.
-static uint64_t calculateWeightScale(uint64_t MaxWeight) {
- return MaxWeight < UINT32_MAX ? 1 : MaxWeight / UINT32_MAX + 1;
-}
-
-/// Scale an individual branch weight (and add 1).
-///
-/// Scale a 64-bit weight down to 32-bits using \c Scale.
-///
-/// According to Laplace's Rule of Succession, it is better to compute the
-/// weight based on the count plus 1, so universally add 1 to the value.
-///
-/// \pre \c Scale was calculated by \a calculateWeightScale() with a weight no
-/// greater than \c Weight.
-static uint32_t scaleBranchWeight(uint64_t Weight, uint64_t Scale) {
- assert(Scale && "scale by 0?");
- uint64_t Scaled = Weight / Scale + 1;
- assert(Scaled <= UINT32_MAX && "overflow 32-bits");
- return Scaled;
-}
-
-llvm::MDNode *CodeGenFunction::createProfileWeights(uint64_t TrueCount,
- uint64_t FalseCount) {
- // Check for empty weights.
- if (!TrueCount && !FalseCount)
- return nullptr;
-
- // Calculate how to scale down to 32-bits.
- uint64_t Scale = calculateWeightScale(std::max(TrueCount, FalseCount));
-
- llvm::MDBuilder MDHelper(CGM.getLLVMContext());
- return MDHelper.createBranchWeights(scaleBranchWeight(TrueCount, Scale),
- scaleBranchWeight(FalseCount, Scale));
-}
-
-llvm::MDNode *
-CodeGenFunction::createProfileWeights(ArrayRef<uint64_t> Weights) {
- // We need at least two elements to create meaningful weights.
- if (Weights.size() < 2)
- return nullptr;
-
- // Check for empty weights.
- uint64_t MaxWeight = *std::max_element(Weights.begin(), Weights.end());
- if (MaxWeight == 0)
- return nullptr;
-
- // Calculate how to scale down to 32-bits.
- uint64_t Scale = calculateWeightScale(MaxWeight);
-
- SmallVector<uint32_t, 16> ScaledWeights;
- ScaledWeights.reserve(Weights.size());
- for (uint64_t W : Weights)
- ScaledWeights.push_back(scaleBranchWeight(W, Scale));
-
- llvm::MDBuilder MDHelper(CGM.getLLVMContext());
- return MDHelper.createBranchWeights(ScaledWeights);
-}
-
-llvm::MDNode *CodeGenFunction::createProfileWeightsForLoop(const Stmt *Cond,
- uint64_t LoopCount) {
- if (!PGO.haveRegionCounts())
- return nullptr;
- Optional<uint64_t> CondCount = PGO.getStmtCount(Cond);
- assert(CondCount.hasValue() && "missing expected loop condition count");
- if (*CondCount == 0)
- return nullptr;
- return createProfileWeights(LoopCount,
- std::max(*CondCount, LoopCount) - LoopCount);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h
deleted file mode 100644
index 120ab651a4a..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h
+++ /dev/null
@@ -1,120 +0,0 @@
-//===--- CodeGenPGO.h - PGO Instrumentation for LLVM CodeGen ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Instrumentation-based profile-guided optimization
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENPGO_H
-#define LLVM_CLANG_LIB_CODEGEN_CODEGENPGO_H
-
-#include "CGBuilder.h"
-#include "CodeGenModule.h"
-#include "CodeGenTypes.h"
-#include "llvm/ProfileData/InstrProfReader.h"
-#include <array>
-#include <memory>
-
-namespace clang {
-namespace CodeGen {
-
-/// Per-function PGO state.
-class CodeGenPGO {
-private:
- CodeGenModule &CGM;
- std::string FuncName;
- llvm::GlobalVariable *FuncNameVar;
-
- std::array <unsigned, llvm::IPVK_Last + 1> NumValueSites;
- unsigned NumRegionCounters;
- uint64_t FunctionHash;
- std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCounterMap;
- std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap;
- std::unique_ptr<llvm::InstrProfRecord> ProfRecord;
- std::vector<uint64_t> RegionCounts;
- uint64_t CurrentRegionCount;
-
-public:
- CodeGenPGO(CodeGenModule &CGM)
- : CGM(CGM), NumValueSites({{0}}), NumRegionCounters(0), FunctionHash(0),
- CurrentRegionCount(0) {}
-
- /// Whether or not we have PGO region data for the current function. This is
- /// false both when we have no data at all and when our data has been
- /// discarded.
- bool haveRegionCounts() const { return !RegionCounts.empty(); }
-
- /// Return the counter value of the current region.
- uint64_t getCurrentRegionCount() const { return CurrentRegionCount; }
-
- /// Set the counter value for the current region. This is used to keep track
- /// of changes to the most recent counter from control flow and non-local
- /// exits.
- void setCurrentRegionCount(uint64_t Count) { CurrentRegionCount = Count; }
-
- /// Check if an execution count is known for a given statement. If so, return
- /// true and put the value in Count; else return false.
- Optional<uint64_t> getStmtCount(const Stmt *S) {
- if (!StmtCountMap)
- return None;
- auto I = StmtCountMap->find(S);
- if (I == StmtCountMap->end())
- return None;
- return I->second;
- }
-
- /// If the execution count for the current statement is known, record that
- /// as the current count.
- void setCurrentStmt(const Stmt *S) {
- if (auto Count = getStmtCount(S))
- setCurrentRegionCount(*Count);
- }
-
- /// Assign counters to regions and configure them for PGO of a given
- /// function. Does nothing if instrumentation is not enabled and either
- /// generates global variables or associates PGO data with each of the
- /// counters depending on whether we are generating or using instrumentation.
- void assignRegionCounters(GlobalDecl GD, llvm::Function *Fn);
- /// Emit a coverage mapping range with a counter zero
- /// for an unused declaration.
- void emitEmptyCounterMapping(const Decl *D, StringRef FuncName,
- llvm::GlobalValue::LinkageTypes Linkage);
- // Insert instrumentation or attach profile metadata at value sites
- void valueProfile(CGBuilderTy &Builder, uint32_t ValueKind,
- llvm::Instruction *ValueSite, llvm::Value *ValuePtr);
-private:
- void setFuncName(llvm::Function *Fn);
- void setFuncName(StringRef Name, llvm::GlobalValue::LinkageTypes Linkage);
- void mapRegionCounters(const Decl *D);
- void computeRegionCounts(const Decl *D);
- void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
- llvm::Function *Fn);
- void loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
- bool IsInMainFile);
- bool skipRegionMappingForDecl(const Decl *D);
- void emitCounterRegionMapping(const Decl *D);
-
-public:
- void emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
- llvm::Value *StepV);
-
- /// Return the region count for the counter at the given index.
- uint64_t getRegionCount(const Stmt *S) {
- if (!RegionCounterMap)
- return 0;
- if (!haveRegionCounts())
- return 0;
- return RegionCounts[(*RegionCounterMap)[S]];
- }
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp
deleted file mode 100644
index 27d39716d22..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-//===--- CodeGenTypes.cpp - TBAA information for LLVM CodeGen -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the code that manages TBAA information and defines the TBAA policy
-// for the optimizer to use. Relevant standards text includes:
-//
-// C99 6.5p7
-// C++ [basic.lval] (p10 in n3126, p15 in some earlier versions)
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenTBAA.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/Mangle.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Metadata.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Type.h"
-using namespace clang;
-using namespace CodeGen;
-
-CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::Module &M,
- const CodeGenOptions &CGO,
- const LangOptions &Features, MangleContext &MContext)
- : Context(Ctx), Module(M), CodeGenOpts(CGO),
- Features(Features), MContext(MContext), MDHelper(M.getContext()),
- Root(nullptr), Char(nullptr)
-{}
-
-CodeGenTBAA::~CodeGenTBAA() {
-}
-
-llvm::MDNode *CodeGenTBAA::getRoot() {
- // Define the root of the tree. This identifies the tree, so that
- // if our LLVM IR is linked with LLVM IR from a different front-end
- // (or a different version of this front-end), their TBAA trees will
- // remain distinct, and the optimizer will treat them conservatively.
- if (!Root) {
- if (Features.CPlusPlus)
- Root = MDHelper.createTBAARoot("Simple C++ TBAA");
- else
- Root = MDHelper.createTBAARoot("Simple C/C++ TBAA");
- }
-
- return Root;
-}
-
-llvm::MDNode *CodeGenTBAA::createScalarTypeNode(StringRef Name,
- llvm::MDNode *Parent,
- uint64_t Size) {
- if (CodeGenOpts.NewStructPathTBAA) {
- llvm::Metadata *Id = MDHelper.createString(Name);
- return MDHelper.createTBAATypeNode(Parent, Size, Id);
- }
- return MDHelper.createTBAAScalarTypeNode(Name, Parent);
-}
-
-llvm::MDNode *CodeGenTBAA::getChar() {
- // Define the root of the tree for user-accessible memory. C and C++
- // give special powers to char and certain similar types. However,
- // these special powers only cover user-accessible memory, and doesn't
- // include things like vtables.
- if (!Char)
- Char = createScalarTypeNode("omnipotent char", getRoot(), /* Size= */ 1);
-
- return Char;
-}
-
-static bool TypeHasMayAlias(QualType QTy) {
- // Tagged types have declarations, and therefore may have attributes.
- if (const TagType *TTy = dyn_cast<TagType>(QTy))
- return TTy->getDecl()->hasAttr<MayAliasAttr>();
-
- // Typedef types have declarations, and therefore may have attributes.
- if (const TypedefType *TTy = dyn_cast<TypedefType>(QTy)) {
- if (TTy->getDecl()->hasAttr<MayAliasAttr>())
- return true;
- // Also, their underlying types may have relevant attributes.
- return TypeHasMayAlias(TTy->desugar());
- }
-
- return false;
-}
-
-/// Check if the given type is a valid base type to be used in access tags.
-static bool isValidBaseType(QualType QTy) {
- if (QTy->isReferenceType())
- return false;
- if (const RecordType *TTy = QTy->getAs<RecordType>()) {
- const RecordDecl *RD = TTy->getDecl()->getDefinition();
- // Incomplete types are not valid base access types.
- if (!RD)
- return false;
- if (RD->hasFlexibleArrayMember())
- return false;
- // RD can be struct, union, class, interface or enum.
- // For now, we only handle struct and class.
- if (RD->isStruct() || RD->isClass())
- return true;
- }
- return false;
-}
-
-llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
- uint64_t Size = Context.getTypeSizeInChars(Ty).getQuantity();
-
- // Handle builtin types.
- if (const BuiltinType *BTy = dyn_cast<BuiltinType>(Ty)) {
- switch (BTy->getKind()) {
- // Character types are special and can alias anything.
- // In C++, this technically only includes "char" and "unsigned char",
- // and not "signed char". In C, it includes all three. For now,
- // the risk of exploiting this detail in C++ seems likely to outweigh
- // the benefit.
- case BuiltinType::Char_U:
- case BuiltinType::Char_S:
- case BuiltinType::UChar:
- case BuiltinType::SChar:
- return getChar();
-
- // Unsigned types can alias their corresponding signed types.
- case BuiltinType::UShort:
- return getTypeInfo(Context.ShortTy);
- case BuiltinType::UInt:
- return getTypeInfo(Context.IntTy);
- case BuiltinType::ULong:
- return getTypeInfo(Context.LongTy);
- case BuiltinType::ULongLong:
- return getTypeInfo(Context.LongLongTy);
- case BuiltinType::UInt128:
- return getTypeInfo(Context.Int128Ty);
-
- // Treat all other builtin types as distinct types. This includes
- // treating wchar_t, char16_t, and char32_t as distinct from their
- // "underlying types".
- default:
- return createScalarTypeNode(BTy->getName(Features), getChar(), Size);
- }
- }
-
- // C++1z [basic.lval]p10: "If a program attempts to access the stored value of
- // an object through a glvalue of other than one of the following types the
- // behavior is undefined: [...] a char, unsigned char, or std::byte type."
- if (Ty->isStdByteType())
- return getChar();
-
- // Handle pointers and references.
- // TODO: Implement C++'s type "similarity" and consider dis-"similar"
- // pointers distinct.
- if (Ty->isPointerType() || Ty->isReferenceType())
- return createScalarTypeNode("any pointer", getChar(), Size);
-
- // Accesses to arrays are accesses to objects of their element types.
- if (CodeGenOpts.NewStructPathTBAA && Ty->isArrayType())
- return getTypeInfo(cast<ArrayType>(Ty)->getElementType());
-
- // Enum types are distinct types. In C++ they have "underlying types",
- // however they aren't related for TBAA.
- if (const EnumType *ETy = dyn_cast<EnumType>(Ty)) {
- // In C++ mode, types have linkage, so we can rely on the ODR and
- // on their mangled names, if they're external.
- // TODO: Is there a way to get a program-wide unique name for a
- // decl with local linkage or no linkage?
- if (!Features.CPlusPlus || !ETy->getDecl()->isExternallyVisible())
- return getChar();
-
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- MContext.mangleTypeName(QualType(ETy, 0), Out);
- return createScalarTypeNode(OutName, getChar(), Size);
- }
-
- // For now, handle any other kind of type conservatively.
- return getChar();
-}
-
-llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
- // At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
- if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
- return nullptr;
-
- // If the type has the may_alias attribute (even on a typedef), it is
- // effectively in the general char alias class.
- if (TypeHasMayAlias(QTy))
- return getChar();
-
- // We need this function to not fall back to returning the "omnipotent char"
- // type node for aggregate and union types. Otherwise, any dereference of an
- // aggregate will result into the may-alias access descriptor, meaning all
- // subsequent accesses to direct and indirect members of that aggregate will
- // be considered may-alias too.
- // TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function.
- if (isValidBaseType(QTy))
- return getBaseTypeInfo(QTy);
-
- const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
- if (llvm::MDNode *N = MetadataCache[Ty])
- return N;
-
- // Note that the following helper call is allowed to add new nodes to the
- // cache, which invalidates all its previously obtained iterators. So we
- // first generate the node for the type and then add that node to the cache.
- llvm::MDNode *TypeNode = getTypeInfoHelper(Ty);
- return MetadataCache[Ty] = TypeNode;
-}
-
-TBAAAccessInfo CodeGenTBAA::getAccessInfo(QualType AccessType) {
- // Pointee values may have incomplete types, but they shall never be
- // dereferenced.
- if (AccessType->isIncompleteType())
- return TBAAAccessInfo::getIncompleteInfo();
-
- if (TypeHasMayAlias(AccessType))
- return TBAAAccessInfo::getMayAliasInfo();
-
- uint64_t Size = Context.getTypeSizeInChars(AccessType).getQuantity();
- return TBAAAccessInfo(getTypeInfo(AccessType), Size);
-}
-
-TBAAAccessInfo CodeGenTBAA::getVTablePtrAccessInfo(llvm::Type *VTablePtrType) {
- llvm::DataLayout DL(&Module);
- unsigned Size = DL.getPointerTypeSize(VTablePtrType);
- return TBAAAccessInfo(createScalarTypeNode("vtable pointer", getRoot(), Size),
- Size);
-}
-
-bool
-CodeGenTBAA::CollectFields(uint64_t BaseOffset,
- QualType QTy,
- SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &
- Fields,
- bool MayAlias) {
- /* Things not handled yet include: C++ base classes, bitfields, */
-
- if (const RecordType *TTy = QTy->getAs<RecordType>()) {
- const RecordDecl *RD = TTy->getDecl()->getDefinition();
- if (RD->hasFlexibleArrayMember())
- return false;
-
- // TODO: Handle C++ base classes.
- if (const CXXRecordDecl *Decl = dyn_cast<CXXRecordDecl>(RD))
- if (Decl->bases_begin() != Decl->bases_end())
- return false;
-
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- unsigned idx = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i, ++idx) {
- uint64_t Offset = BaseOffset +
- Layout.getFieldOffset(idx) / Context.getCharWidth();
- QualType FieldQTy = i->getType();
- if (!CollectFields(Offset, FieldQTy, Fields,
- MayAlias || TypeHasMayAlias(FieldQTy)))
- return false;
- }
- return true;
- }
-
- /* Otherwise, treat whatever it is as a field. */
- uint64_t Offset = BaseOffset;
- uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity();
- llvm::MDNode *TBAAType = MayAlias ? getChar() : getTypeInfo(QTy);
- llvm::MDNode *TBAATag = getAccessTagInfo(TBAAAccessInfo(TBAAType, Size));
- Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag));
- return true;
-}
-
-llvm::MDNode *
-CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
- const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
-
- if (llvm::MDNode *N = StructMetadataCache[Ty])
- return N;
-
- SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields;
- if (CollectFields(0, QTy, Fields, TypeHasMayAlias(QTy)))
- return MDHelper.createTBAAStructNode(Fields);
-
- // For now, handle any other kind of type conservatively.
- return StructMetadataCache[Ty] = nullptr;
-}
-
-llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
- if (auto *TTy = dyn_cast<RecordType>(Ty)) {
- const RecordDecl *RD = TTy->getDecl()->getDefinition();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields;
- for (FieldDecl *Field : RD->fields()) {
- QualType FieldQTy = Field->getType();
- llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) ?
- getBaseTypeInfo(FieldQTy) : getTypeInfo(FieldQTy);
- if (!TypeNode)
- return BaseTypeMetadataCache[Ty] = nullptr;
-
- uint64_t BitOffset = Layout.getFieldOffset(Field->getFieldIndex());
- uint64_t Offset = Context.toCharUnitsFromBits(BitOffset).getQuantity();
- uint64_t Size = Context.getTypeSizeInChars(FieldQTy).getQuantity();
- Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size,
- TypeNode));
- }
-
- SmallString<256> OutName;
- if (Features.CPlusPlus) {
- // Don't use the mangler for C code.
- llvm::raw_svector_ostream Out(OutName);
- MContext.mangleTypeName(QualType(Ty, 0), Out);
- } else {
- OutName = RD->getName();
- }
-
- if (CodeGenOpts.NewStructPathTBAA) {
- llvm::MDNode *Parent = getChar();
- uint64_t Size = Context.getTypeSizeInChars(Ty).getQuantity();
- llvm::Metadata *Id = MDHelper.createString(OutName);
- return MDHelper.createTBAATypeNode(Parent, Size, Id, Fields);
- }
-
- // Create the struct type node with a vector of pairs (offset, type).
- SmallVector<std::pair<llvm::MDNode*, uint64_t>, 4> OffsetsAndTypes;
- for (const auto &Field : Fields)
- OffsetsAndTypes.push_back(std::make_pair(Field.Type, Field.Offset));
- return MDHelper.createTBAAStructTypeNode(OutName, OffsetsAndTypes);
- }
-
- return nullptr;
-}
-
-llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) {
- if (!isValidBaseType(QTy))
- return nullptr;
-
- const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
- if (llvm::MDNode *N = BaseTypeMetadataCache[Ty])
- return N;
-
- // Note that the following helper call is allowed to add new nodes to the
- // cache, which invalidates all its previously obtained iterators. So we
- // first generate the node for the type and then add that node to the cache.
- llvm::MDNode *TypeNode = getBaseTypeInfoHelper(Ty);
- return BaseTypeMetadataCache[Ty] = TypeNode;
-}
-
-llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) {
- assert(!Info.isIncomplete() && "Access to an object of an incomplete type!");
-
- if (Info.isMayAlias())
- Info = TBAAAccessInfo(getChar(), Info.Size);
-
- if (!Info.AccessType)
- return nullptr;
-
- if (!CodeGenOpts.StructPathTBAA)
- Info = TBAAAccessInfo(Info.AccessType, Info.Size);
-
- llvm::MDNode *&N = AccessTagMetadataCache[Info];
- if (N)
- return N;
-
- if (!Info.BaseType) {
- Info.BaseType = Info.AccessType;
- assert(!Info.Offset && "Nonzero offset for an access with no base type!");
- }
- if (CodeGenOpts.NewStructPathTBAA) {
- return N = MDHelper.createTBAAAccessTag(Info.BaseType, Info.AccessType,
- Info.Offset, Info.Size);
- }
- return N = MDHelper.createTBAAStructTagNode(Info.BaseType, Info.AccessType,
- Info.Offset);
-}
-
-TBAAAccessInfo CodeGenTBAA::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
- TBAAAccessInfo TargetInfo) {
- if (SourceInfo.isMayAlias() || TargetInfo.isMayAlias())
- return TBAAAccessInfo::getMayAliasInfo();
- return TargetInfo;
-}
-
-TBAAAccessInfo
-CodeGenTBAA::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
- TBAAAccessInfo InfoB) {
- if (InfoA == InfoB)
- return InfoA;
-
- if (!InfoA || !InfoB)
- return TBAAAccessInfo();
-
- if (InfoA.isMayAlias() || InfoB.isMayAlias())
- return TBAAAccessInfo::getMayAliasInfo();
-
- // TODO: Implement the rest of the logic here. For example, two accesses
- // with same final access types result in an access to an object of that final
- // access type regardless of their base types.
- return TBAAAccessInfo::getMayAliasInfo();
-}
-
-TBAAAccessInfo
-CodeGenTBAA::mergeTBAAInfoForMemoryTransfer(TBAAAccessInfo DestInfo,
- TBAAAccessInfo SrcInfo) {
- if (DestInfo == SrcInfo)
- return DestInfo;
-
- if (!DestInfo || !SrcInfo)
- return TBAAAccessInfo();
-
- if (DestInfo.isMayAlias() || SrcInfo.isMayAlias())
- return TBAAAccessInfo::getMayAliasInfo();
-
- // TODO: Implement the rest of the logic here. For example, two accesses
- // with same final access types result in an access to an object of that final
- // access type regardless of their base types.
- return TBAAAccessInfo::getMayAliasInfo();
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h
deleted file mode 100644
index 86ba407c05c..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h
+++ /dev/null
@@ -1,258 +0,0 @@
-//===--- CodeGenTBAA.h - TBAA information for LLVM CodeGen ------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the code that manages TBAA information and defines the TBAA policy
-// for the optimizer to use.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTBAA_H
-#define LLVM_CLANG_LIB_CODEGEN_CODEGENTBAA_H
-
-#include "clang/AST/Type.h"
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/IR/Metadata.h"
-
-namespace clang {
- class ASTContext;
- class CodeGenOptions;
- class LangOptions;
- class MangleContext;
- class QualType;
- class Type;
-
-namespace CodeGen {
-class CGRecordLayout;
-
-// TBAAAccessKind - A kind of TBAA memory access descriptor.
-enum class TBAAAccessKind : unsigned {
- Ordinary,
- MayAlias,
- Incomplete,
-};
-
-// TBAAAccessInfo - Describes a memory access in terms of TBAA.
-struct TBAAAccessInfo {
- TBAAAccessInfo(TBAAAccessKind Kind, llvm::MDNode *BaseType,
- llvm::MDNode *AccessType, uint64_t Offset, uint64_t Size)
- : Kind(Kind), BaseType(BaseType), AccessType(AccessType),
- Offset(Offset), Size(Size)
- {}
-
- TBAAAccessInfo(llvm::MDNode *BaseType, llvm::MDNode *AccessType,
- uint64_t Offset, uint64_t Size)
- : TBAAAccessInfo(TBAAAccessKind::Ordinary, BaseType, AccessType,
- Offset, Size)
- {}
-
- explicit TBAAAccessInfo(llvm::MDNode *AccessType, uint64_t Size)
- : TBAAAccessInfo(/* BaseType= */ nullptr, AccessType, /* Offset= */ 0, Size)
- {}
-
- TBAAAccessInfo()
- : TBAAAccessInfo(/* AccessType= */ nullptr, /* Size= */ 0)
- {}
-
- static TBAAAccessInfo getMayAliasInfo() {
- return TBAAAccessInfo(TBAAAccessKind::MayAlias,
- /* BaseType= */ nullptr, /* AccessType= */ nullptr,
- /* Offset= */ 0, /* Size= */ 0);
- }
-
- bool isMayAlias() const { return Kind == TBAAAccessKind::MayAlias; }
-
- static TBAAAccessInfo getIncompleteInfo() {
- return TBAAAccessInfo(TBAAAccessKind::Incomplete,
- /* BaseType= */ nullptr, /* AccessType= */ nullptr,
- /* Offset= */ 0, /* Size= */ 0);
- }
-
- bool isIncomplete() const { return Kind == TBAAAccessKind::Incomplete; }
-
- bool operator==(const TBAAAccessInfo &Other) const {
- return Kind == Other.Kind &&
- BaseType == Other.BaseType &&
- AccessType == Other.AccessType &&
- Offset == Other.Offset &&
- Size == Other.Size;
- }
-
- bool operator!=(const TBAAAccessInfo &Other) const {
- return !(*this == Other);
- }
-
- explicit operator bool() const {
- return *this != TBAAAccessInfo();
- }
-
- /// Kind - The kind of the access descriptor.
- TBAAAccessKind Kind;
-
- /// BaseType - The base/leading access type. May be null if this access
- /// descriptor represents an access that is not considered to be an access
- /// to an aggregate or union member.
- llvm::MDNode *BaseType;
-
- /// AccessType - The final access type. May be null if there is no TBAA
- /// information available about this access.
- llvm::MDNode *AccessType;
-
- /// Offset - The byte offset of the final access within the base one. Must be
- /// zero if the base access type is not specified.
- uint64_t Offset;
-
- /// Size - The size of access, in bytes.
- uint64_t Size;
-};
-
-/// CodeGenTBAA - This class organizes the cross-module state that is used
-/// while lowering AST types to LLVM types.
-class CodeGenTBAA {
- ASTContext &Context;
- llvm::Module &Module;
- const CodeGenOptions &CodeGenOpts;
- const LangOptions &Features;
- MangleContext &MContext;
-
- // MDHelper - Helper for creating metadata.
- llvm::MDBuilder MDHelper;
-
- /// MetadataCache - This maps clang::Types to scalar llvm::MDNodes describing
- /// them.
- llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
- /// This maps clang::Types to a base access type in the type DAG.
- llvm::DenseMap<const Type *, llvm::MDNode *> BaseTypeMetadataCache;
- /// This maps TBAA access descriptors to tag nodes.
- llvm::DenseMap<TBAAAccessInfo, llvm::MDNode *> AccessTagMetadataCache;
-
- /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing
- /// them for struct assignments.
- llvm::DenseMap<const Type *, llvm::MDNode *> StructMetadataCache;
-
- llvm::MDNode *Root;
- llvm::MDNode *Char;
-
- /// getRoot - This is the mdnode for the root of the metadata type graph
- /// for this translation unit.
- llvm::MDNode *getRoot();
-
- /// getChar - This is the mdnode for "char", which is special, and any types
- /// considered to be equivalent to it.
- llvm::MDNode *getChar();
-
- /// CollectFields - Collect information about the fields of a type for
- /// !tbaa.struct metadata formation. Return false for an unsupported type.
- bool CollectFields(uint64_t BaseOffset,
- QualType Ty,
- SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &Fields,
- bool MayAlias);
-
- /// createScalarTypeNode - A wrapper function to create a metadata node
- /// describing a scalar type.
- llvm::MDNode *createScalarTypeNode(StringRef Name, llvm::MDNode *Parent,
- uint64_t Size);
-
- /// getTypeInfoHelper - An internal helper function to generate metadata used
- /// to describe accesses to objects of the given type.
- llvm::MDNode *getTypeInfoHelper(const Type *Ty);
-
- /// getBaseTypeInfoHelper - An internal helper function to generate metadata
- /// used to describe accesses to objects of the given base type.
- llvm::MDNode *getBaseTypeInfoHelper(const Type *Ty);
-
-public:
- CodeGenTBAA(ASTContext &Ctx, llvm::Module &M, const CodeGenOptions &CGO,
- const LangOptions &Features, MangleContext &MContext);
- ~CodeGenTBAA();
-
- /// getTypeInfo - Get metadata used to describe accesses to objects of the
- /// given type.
- llvm::MDNode *getTypeInfo(QualType QTy);
-
- /// getAccessInfo - Get TBAA information that describes an access to
- /// an object of the given type.
- TBAAAccessInfo getAccessInfo(QualType AccessType);
-
- /// getVTablePtrAccessInfo - Get the TBAA information that describes an
- /// access to a virtual table pointer.
- TBAAAccessInfo getVTablePtrAccessInfo(llvm::Type *VTablePtrType);
-
- /// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of
- /// the given type.
- llvm::MDNode *getTBAAStructInfo(QualType QTy);
-
- /// getBaseTypeInfo - Get metadata that describes the given base access type.
- /// Return null if the type is not suitable for use in TBAA access tags.
- llvm::MDNode *getBaseTypeInfo(QualType QTy);
-
- /// getAccessTagInfo - Get TBAA tag for a given memory access.
- llvm::MDNode *getAccessTagInfo(TBAAAccessInfo Info);
-
- /// mergeTBAAInfoForCast - Get merged TBAA information for the purpose of
- /// type casts.
- TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
- TBAAAccessInfo TargetInfo);
-
- /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the
- /// purpose of conditional operator.
- TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
- TBAAAccessInfo InfoB);
-
- /// mergeTBAAInfoForMemoryTransfer - Get merged TBAA information for the
- /// purpose of memory transfer calls.
- TBAAAccessInfo mergeTBAAInfoForMemoryTransfer(TBAAAccessInfo DestInfo,
- TBAAAccessInfo SrcInfo);
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-namespace llvm {
-
-template<> struct DenseMapInfo<clang::CodeGen::TBAAAccessInfo> {
- static clang::CodeGen::TBAAAccessInfo getEmptyKey() {
- unsigned UnsignedKey = DenseMapInfo<unsigned>::getEmptyKey();
- return clang::CodeGen::TBAAAccessInfo(
- static_cast<clang::CodeGen::TBAAAccessKind>(UnsignedKey),
- DenseMapInfo<MDNode *>::getEmptyKey(),
- DenseMapInfo<MDNode *>::getEmptyKey(),
- DenseMapInfo<uint64_t>::getEmptyKey(),
- DenseMapInfo<uint64_t>::getEmptyKey());
- }
-
- static clang::CodeGen::TBAAAccessInfo getTombstoneKey() {
- unsigned UnsignedKey = DenseMapInfo<unsigned>::getTombstoneKey();
- return clang::CodeGen::TBAAAccessInfo(
- static_cast<clang::CodeGen::TBAAAccessKind>(UnsignedKey),
- DenseMapInfo<MDNode *>::getTombstoneKey(),
- DenseMapInfo<MDNode *>::getTombstoneKey(),
- DenseMapInfo<uint64_t>::getTombstoneKey(),
- DenseMapInfo<uint64_t>::getTombstoneKey());
- }
-
- static unsigned getHashValue(const clang::CodeGen::TBAAAccessInfo &Val) {
- auto KindValue = static_cast<unsigned>(Val.Kind);
- return DenseMapInfo<unsigned>::getHashValue(KindValue) ^
- DenseMapInfo<MDNode *>::getHashValue(Val.BaseType) ^
- DenseMapInfo<MDNode *>::getHashValue(Val.AccessType) ^
- DenseMapInfo<uint64_t>::getHashValue(Val.Offset) ^
- DenseMapInfo<uint64_t>::getHashValue(Val.Size);
- }
-
- static bool isEqual(const clang::CodeGen::TBAAAccessInfo &LHS,
- const clang::CodeGen::TBAAAccessInfo &RHS) {
- return LHS == RHS;
- }
-};
-
-} // end namespace llvm
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h
deleted file mode 100644
index 901aed6c00b..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h
+++ /dev/null
@@ -1,122 +0,0 @@
-//===--- CodeGenTypeCache.h - Commonly used LLVM types and info -*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This structure provides a set of common types useful during IR emission.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPECACHE_H
-#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPECACHE_H
-
-#include "clang/AST/CharUnits.h"
-#include "clang/Basic/AddressSpaces.h"
-#include "llvm/IR/CallingConv.h"
-
-namespace llvm {
- class Type;
- class IntegerType;
- class PointerType;
-}
-
-namespace clang {
-namespace CodeGen {
-
-/// This structure provides a set of types that are commonly used
-/// during IR emission. It's initialized once in CodeGenModule's
-/// constructor and then copied around into new CodeGenFunctions.
-struct CodeGenTypeCache {
- /// void
- llvm::Type *VoidTy;
-
- /// i8, i16, i32, and i64
- llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty;
- /// float, double
- llvm::Type *HalfTy, *FloatTy, *DoubleTy;
-
- /// int
- llvm::IntegerType *IntTy;
-
- /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size.
- union {
- llvm::IntegerType *IntPtrTy;
- llvm::IntegerType *SizeTy;
- llvm::IntegerType *PtrDiffTy;
- };
-
- /// void* in address space 0
- union {
- llvm::PointerType *VoidPtrTy;
- llvm::PointerType *Int8PtrTy;
- };
-
- /// void** in address space 0
- union {
- llvm::PointerType *VoidPtrPtrTy;
- llvm::PointerType *Int8PtrPtrTy;
- };
-
- /// void* in alloca address space
- union {
- llvm::PointerType *AllocaVoidPtrTy;
- llvm::PointerType *AllocaInt8PtrTy;
- };
-
- /// The size and alignment of the builtin C type 'int'. This comes
- /// up enough in various ABI lowering tasks to be worth pre-computing.
- union {
- unsigned char IntSizeInBytes;
- unsigned char IntAlignInBytes;
- };
- CharUnits getIntSize() const {
- return CharUnits::fromQuantity(IntSizeInBytes);
- }
- CharUnits getIntAlign() const {
- return CharUnits::fromQuantity(IntAlignInBytes);
- }
-
- /// The width of a pointer into the generic address space.
- unsigned char PointerWidthInBits;
-
- /// The size and alignment of a pointer into the generic address space.
- union {
- unsigned char PointerAlignInBytes;
- unsigned char PointerSizeInBytes;
- };
-
- /// The size and alignment of size_t.
- union {
- unsigned char SizeSizeInBytes; // sizeof(size_t)
- unsigned char SizeAlignInBytes;
- };
-
- LangAS ASTAllocaAddressSpace;
-
- CharUnits getSizeSize() const {
- return CharUnits::fromQuantity(SizeSizeInBytes);
- }
- CharUnits getSizeAlign() const {
- return CharUnits::fromQuantity(SizeAlignInBytes);
- }
- CharUnits getPointerSize() const {
- return CharUnits::fromQuantity(PointerSizeInBytes);
- }
- CharUnits getPointerAlign() const {
- return CharUnits::fromQuantity(PointerAlignInBytes);
- }
-
- llvm::CallingConv::ID RuntimeCC;
- llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; }
-
- LangAS getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp
deleted file mode 100644
index 2acf1ac1618..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp
+++ /dev/null
@@ -1,812 +0,0 @@
-//===--- CodeGenTypes.cpp - Type translation for LLVM CodeGen -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the code that handles AST -> LLVM type lowering.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenTypes.h"
-#include "CGCXXABI.h"
-#include "CGCall.h"
-#include "CGOpenCLRuntime.h"
-#include "CGRecordLayout.h"
-#include "TargetInfo.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Module.h"
-using namespace clang;
-using namespace CodeGen;
-
-CodeGenTypes::CodeGenTypes(CodeGenModule &cgm)
- : CGM(cgm), Context(cgm.getContext()), TheModule(cgm.getModule()),
- Target(cgm.getTarget()), TheCXXABI(cgm.getCXXABI()),
- TheABIInfo(cgm.getTargetCodeGenInfo().getABIInfo()) {
- SkippedLayout = false;
-}
-
-CodeGenTypes::~CodeGenTypes() {
- llvm::DeleteContainerSeconds(CGRecordLayouts);
-
- for (llvm::FoldingSet<CGFunctionInfo>::iterator
- I = FunctionInfos.begin(), E = FunctionInfos.end(); I != E; )
- delete &*I++;
-}
-
-const CodeGenOptions &CodeGenTypes::getCodeGenOpts() const {
- return CGM.getCodeGenOpts();
-}
-
-void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
- llvm::StructType *Ty,
- StringRef suffix) {
- SmallString<256> TypeName;
- llvm::raw_svector_ostream OS(TypeName);
- OS << RD->getKindName() << '.';
-
- // Name the codegen type after the typedef name
- // if there is no tag type name available
- if (RD->getIdentifier()) {
- // FIXME: We should not have to check for a null decl context here.
- // Right now we do it because the implicit Obj-C decls don't have one.
- if (RD->getDeclContext())
- RD->printQualifiedName(OS);
- else
- RD->printName(OS);
- } else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) {
- // FIXME: We should not have to check for a null decl context here.
- // Right now we do it because the implicit Obj-C decls don't have one.
- if (TDD->getDeclContext())
- TDD->printQualifiedName(OS);
- else
- TDD->printName(OS);
- } else
- OS << "anon";
-
- if (!suffix.empty())
- OS << suffix;
-
- Ty->setName(OS.str());
-}
-
-/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
-/// ConvertType in that it is used to convert to the memory representation for
-/// a type. For example, the scalar representation for _Bool is i1, but the
-/// memory representation is usually i8 or i32, depending on the target.
-llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
- llvm::Type *R = ConvertType(T);
-
- // If this is a non-bool type, don't map it.
- if (!R->isIntegerTy(1))
- return R;
-
- // Otherwise, return an integer of the target-specified size.
- return llvm::IntegerType::get(getLLVMContext(),
- (unsigned)Context.getTypeSize(T));
-}
-
-
-/// isRecordLayoutComplete - Return true if the specified type is already
-/// completely laid out.
-bool CodeGenTypes::isRecordLayoutComplete(const Type *Ty) const {
- llvm::DenseMap<const Type*, llvm::StructType *>::const_iterator I =
- RecordDeclTypes.find(Ty);
- return I != RecordDeclTypes.end() && !I->second->isOpaque();
-}
-
-static bool
-isSafeToConvert(QualType T, CodeGenTypes &CGT,
- llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked);
-
-
-/// isSafeToConvert - Return true if it is safe to convert the specified record
-/// decl to IR and lay it out, false if doing so would cause us to get into a
-/// recursive compilation mess.
-static bool
-isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT,
- llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) {
- // If we have already checked this type (maybe the same type is used by-value
- // multiple times in multiple structure fields, don't check again.
- if (!AlreadyChecked.insert(RD).second)
- return true;
-
- const Type *Key = CGT.getContext().getTagDeclType(RD).getTypePtr();
-
- // If this type is already laid out, converting it is a noop.
- if (CGT.isRecordLayoutComplete(Key)) return true;
-
- // If this type is currently being laid out, we can't recursively compile it.
- if (CGT.isRecordBeingLaidOut(Key))
- return false;
-
- // If this type would require laying out bases that are currently being laid
- // out, don't do it. This includes virtual base classes which get laid out
- // when a class is translated, even though they aren't embedded by-value into
- // the class.
- if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (const auto &I : CRD->bases())
- if (!isSafeToConvert(I.getType()->getAs<RecordType>()->getDecl(),
- CGT, AlreadyChecked))
- return false;
- }
-
- // If this type would require laying out members that are currently being laid
- // out, don't do it.
- for (const auto *I : RD->fields())
- if (!isSafeToConvert(I->getType(), CGT, AlreadyChecked))
- return false;
-
- // If there are no problems, lets do it.
- return true;
-}
-
-/// isSafeToConvert - Return true if it is safe to convert this field type,
-/// which requires the structure elements contained by-value to all be
-/// recursively safe to convert.
-static bool
-isSafeToConvert(QualType T, CodeGenTypes &CGT,
- llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) {
- // Strip off atomic type sugar.
- if (const auto *AT = T->getAs<AtomicType>())
- T = AT->getValueType();
-
- // If this is a record, check it.
- if (const auto *RT = T->getAs<RecordType>())
- return isSafeToConvert(RT->getDecl(), CGT, AlreadyChecked);
-
- // If this is an array, check the elements, which are embedded inline.
- if (const auto *AT = CGT.getContext().getAsArrayType(T))
- return isSafeToConvert(AT->getElementType(), CGT, AlreadyChecked);
-
- // Otherwise, there is no concern about transforming this. We only care about
- // things that are contained by-value in a structure that can have another
- // structure as a member.
- return true;
-}
-
-
-/// isSafeToConvert - Return true if it is safe to convert the specified record
-/// decl to IR and lay it out, false if doing so would cause us to get into a
-/// recursive compilation mess.
-static bool isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT) {
- // If no structs are being laid out, we can certainly do this one.
- if (CGT.noRecordsBeingLaidOut()) return true;
-
- llvm::SmallPtrSet<const RecordDecl*, 16> AlreadyChecked;
- return isSafeToConvert(RD, CGT, AlreadyChecked);
-}
-
-/// isFuncParamTypeConvertible - Return true if the specified type in a
-/// function parameter or result position can be converted to an IR type at this
-/// point. This boils down to being whether it is complete, as well as whether
-/// we've temporarily deferred expanding the type because we're in a recursive
-/// context.
-bool CodeGenTypes::isFuncParamTypeConvertible(QualType Ty) {
- // Some ABIs cannot have their member pointers represented in IR unless
- // certain circumstances have been reached.
- if (const auto *MPT = Ty->getAs<MemberPointerType>())
- return getCXXABI().isMemberPointerConvertible(MPT);
-
- // If this isn't a tagged type, we can convert it!
- const TagType *TT = Ty->getAs<TagType>();
- if (!TT) return true;
-
- // Incomplete types cannot be converted.
- if (TT->isIncompleteType())
- return false;
-
- // If this is an enum, then it is always safe to convert.
- const RecordType *RT = dyn_cast<RecordType>(TT);
- if (!RT) return true;
-
- // Otherwise, we have to be careful. If it is a struct that we're in the
- // process of expanding, then we can't convert the function type. That's ok
- // though because we must be in a pointer context under the struct, so we can
- // just convert it to a dummy type.
- //
- // We decide this by checking whether ConvertRecordDeclType returns us an
- // opaque type for a struct that we know is defined.
- return isSafeToConvert(RT->getDecl(), *this);
-}
-
-
-/// Code to verify a given function type is complete, i.e. the return type
-/// and all of the parameter types are complete. Also check to see if we are in
-/// a RS_StructPointer context, and if so whether any struct types have been
-/// pended. If so, we don't want to ask the ABI lowering code to handle a type
-/// that cannot be converted to an IR type.
-bool CodeGenTypes::isFuncTypeConvertible(const FunctionType *FT) {
- if (!isFuncParamTypeConvertible(FT->getReturnType()))
- return false;
-
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
- for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
- if (!isFuncParamTypeConvertible(FPT->getParamType(i)))
- return false;
-
- return true;
-}
-
-/// UpdateCompletedType - When we find the full definition for a TagDecl,
-/// replace the 'opaque' type we previously made for it if applicable.
-void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
- // If this is an enum being completed, then we flush all non-struct types from
- // the cache. This allows function types and other things that may be derived
- // from the enum to be recomputed.
- if (const EnumDecl *ED = dyn_cast<EnumDecl>(TD)) {
- // Only flush the cache if we've actually already converted this type.
- if (TypeCache.count(ED->getTypeForDecl())) {
- // Okay, we formed some types based on this. We speculated that the enum
- // would be lowered to i32, so we only need to flush the cache if this
- // didn't happen.
- if (!ConvertType(ED->getIntegerType())->isIntegerTy(32))
- TypeCache.clear();
- }
- // If necessary, provide the full definition of a type only used with a
- // declaration so far.
- if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
- DI->completeType(ED);
- return;
- }
-
- // If we completed a RecordDecl that we previously used and converted to an
- // anonymous type, then go ahead and complete it now.
- const RecordDecl *RD = cast<RecordDecl>(TD);
- if (RD->isDependentType()) return;
-
- // Only complete it if we converted it already. If we haven't converted it
- // yet, we'll just do it lazily.
- if (RecordDeclTypes.count(Context.getTagDeclType(RD).getTypePtr()))
- ConvertRecordDeclType(RD);
-
- // If necessary, provide the full definition of a type only used with a
- // declaration so far.
- if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
- DI->completeType(RD);
-}
-
-void CodeGenTypes::RefreshTypeCacheForClass(const CXXRecordDecl *RD) {
- QualType T = Context.getRecordType(RD);
- T = Context.getCanonicalType(T);
-
- const Type *Ty = T.getTypePtr();
- if (RecordsWithOpaqueMemberPointers.count(Ty)) {
- TypeCache.clear();
- RecordsWithOpaqueMemberPointers.clear();
- }
-}
-
-static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
- const llvm::fltSemantics &format,
- bool UseNativeHalf = false) {
- if (&format == &llvm::APFloat::IEEEhalf()) {
- if (UseNativeHalf)
- return llvm::Type::getHalfTy(VMContext);
- else
- return llvm::Type::getInt16Ty(VMContext);
- }
- if (&format == &llvm::APFloat::IEEEsingle())
- return llvm::Type::getFloatTy(VMContext);
- if (&format == &llvm::APFloat::IEEEdouble())
- return llvm::Type::getDoubleTy(VMContext);
- if (&format == &llvm::APFloat::IEEEquad())
- return llvm::Type::getFP128Ty(VMContext);
- if (&format == &llvm::APFloat::PPCDoubleDouble())
- return llvm::Type::getPPC_FP128Ty(VMContext);
- if (&format == &llvm::APFloat::x87DoubleExtended())
- return llvm::Type::getX86_FP80Ty(VMContext);
- llvm_unreachable("Unknown float format!");
-}
-
-llvm::Type *CodeGenTypes::ConvertFunctionType(QualType QFT,
- const FunctionDecl *FD) {
- assert(QFT.isCanonical());
- const Type *Ty = QFT.getTypePtr();
- const FunctionType *FT = cast<FunctionType>(QFT.getTypePtr());
- // First, check whether we can build the full function type. If the
- // function type depends on an incomplete type (e.g. a struct or enum), we
- // cannot lower the function type.
- if (!isFuncTypeConvertible(FT)) {
- // This function's type depends on an incomplete tag type.
-
- // Force conversion of all the relevant record types, to make sure
- // we re-convert the FunctionType when appropriate.
- if (const RecordType *RT = FT->getReturnType()->getAs<RecordType>())
- ConvertRecordDeclType(RT->getDecl());
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
- for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
- if (const RecordType *RT = FPT->getParamType(i)->getAs<RecordType>())
- ConvertRecordDeclType(RT->getDecl());
-
- SkippedLayout = true;
-
- // Return a placeholder type.
- return llvm::StructType::get(getLLVMContext());
- }
-
- // While we're converting the parameter types for a function, we don't want
- // to recursively convert any pointed-to structs. Converting directly-used
- // structs is ok though.
- if (!RecordsBeingLaidOut.insert(Ty).second) {
- SkippedLayout = true;
- return llvm::StructType::get(getLLVMContext());
- }
-
- // The function type can be built; call the appropriate routines to
- // build it.
- const CGFunctionInfo *FI;
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
- FI = &arrangeFreeFunctionType(
- CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)), FD);
- } else {
- const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
- FI = &arrangeFreeFunctionType(
- CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
- }
-
- llvm::Type *ResultType = nullptr;
- // If there is something higher level prodding our CGFunctionInfo, then
- // don't recurse into it again.
- if (FunctionsBeingProcessed.count(FI)) {
-
- ResultType = llvm::StructType::get(getLLVMContext());
- SkippedLayout = true;
- } else {
-
- // Otherwise, we're good to go, go ahead and convert it.
- ResultType = GetFunctionType(*FI);
- }
-
- RecordsBeingLaidOut.erase(Ty);
-
- if (SkippedLayout)
- TypeCache.clear();
-
- if (RecordsBeingLaidOut.empty())
- while (!DeferredRecords.empty())
- ConvertRecordDeclType(DeferredRecords.pop_back_val());
- return ResultType;
-}
-
-/// ConvertType - Convert the specified type to its LLVM form.
-llvm::Type *CodeGenTypes::ConvertType(QualType T) {
- T = Context.getCanonicalType(T);
-
- const Type *Ty = T.getTypePtr();
-
- // RecordTypes are cached and processed specially.
- if (const RecordType *RT = dyn_cast<RecordType>(Ty))
- return ConvertRecordDeclType(RT->getDecl());
-
- // See if type is already cached.
- llvm::DenseMap<const Type *, llvm::Type *>::iterator TCI = TypeCache.find(Ty);
- // If type is found in map then use it. Otherwise, convert type T.
- if (TCI != TypeCache.end())
- return TCI->second;
-
- // If we don't have it in the cache, convert it now.
- llvm::Type *ResultType = nullptr;
- switch (Ty->getTypeClass()) {
- case Type::Record: // Handled above.
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Non-canonical or dependent types aren't possible.");
-
- case Type::Builtin: {
- switch (cast<BuiltinType>(Ty)->getKind()) {
- case BuiltinType::Void:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- // LLVM void type can only be used as the result of a function call. Just
- // map to the same as char.
- ResultType = llvm::Type::getInt8Ty(getLLVMContext());
- break;
-
- case BuiltinType::Bool:
- // Note that we always return bool as i1 for use as a scalar type.
- ResultType = llvm::Type::getInt1Ty(getLLVMContext());
- break;
-
- case BuiltinType::Char_S:
- case BuiltinType::Char_U:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::Int:
- case BuiltinType::UInt:
- case BuiltinType::Long:
- case BuiltinType::ULong:
- case BuiltinType::LongLong:
- case BuiltinType::ULongLong:
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- case BuiltinType::Char8:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::ShortAccum:
- case BuiltinType::Accum:
- case BuiltinType::LongAccum:
- case BuiltinType::UShortAccum:
- case BuiltinType::UAccum:
- case BuiltinType::ULongAccum:
- case BuiltinType::ShortFract:
- case BuiltinType::Fract:
- case BuiltinType::LongFract:
- case BuiltinType::UShortFract:
- case BuiltinType::UFract:
- case BuiltinType::ULongFract:
- case BuiltinType::SatShortAccum:
- case BuiltinType::SatAccum:
- case BuiltinType::SatLongAccum:
- case BuiltinType::SatUShortAccum:
- case BuiltinType::SatUAccum:
- case BuiltinType::SatULongAccum:
- case BuiltinType::SatShortFract:
- case BuiltinType::SatFract:
- case BuiltinType::SatLongFract:
- case BuiltinType::SatUShortFract:
- case BuiltinType::SatUFract:
- case BuiltinType::SatULongFract:
- ResultType = llvm::IntegerType::get(getLLVMContext(),
- static_cast<unsigned>(Context.getTypeSize(T)));
- break;
-
- case BuiltinType::Float16:
- ResultType =
- getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T),
- /* UseNativeHalf = */ true);
- break;
-
- case BuiltinType::Half:
- // Half FP can either be storage-only (lowered to i16) or native.
- ResultType = getTypeForFormat(
- getLLVMContext(), Context.getFloatTypeSemantics(T),
- Context.getLangOpts().NativeHalfType ||
- !Context.getTargetInfo().useFP16ConversionIntrinsics());
- break;
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
- case BuiltinType::Float128:
- ResultType = getTypeForFormat(getLLVMContext(),
- Context.getFloatTypeSemantics(T),
- /* UseNativeHalf = */ false);
- break;
-
- case BuiltinType::NullPtr:
- // Model std::nullptr_t as i8*
- ResultType = llvm::Type::getInt8PtrTy(getLLVMContext());
- break;
-
- case BuiltinType::UInt128:
- case BuiltinType::Int128:
- ResultType = llvm::IntegerType::get(getLLVMContext(), 128);
- break;
-
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id:
-#include "clang/Basic/OpenCLImageTypes.def"
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- case BuiltinType::Id:
-#include "clang/Basic/OpenCLExtensionTypes.def"
- case BuiltinType::OCLSampler:
- case BuiltinType::OCLEvent:
- case BuiltinType::OCLClkEvent:
- case BuiltinType::OCLQueue:
- case BuiltinType::OCLReserveID:
- ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty);
- break;
-
- case BuiltinType::Dependent:
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- llvm_unreachable("Unexpected placeholder builtin type!");
- }
- break;
- }
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- llvm_unreachable("Unexpected undeduced type!");
- case Type::Complex: {
- llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType());
- ResultType = llvm::StructType::get(EltTy, EltTy);
- break;
- }
- case Type::LValueReference:
- case Type::RValueReference: {
- const ReferenceType *RTy = cast<ReferenceType>(Ty);
- QualType ETy = RTy->getPointeeType();
- llvm::Type *PointeeType = ConvertTypeForMem(ETy);
- unsigned AS = Context.getTargetAddressSpace(ETy);
- ResultType = llvm::PointerType::get(PointeeType, AS);
- break;
- }
- case Type::Pointer: {
- const PointerType *PTy = cast<PointerType>(Ty);
- QualType ETy = PTy->getPointeeType();
- llvm::Type *PointeeType = ConvertTypeForMem(ETy);
- if (PointeeType->isVoidTy())
- PointeeType = llvm::Type::getInt8Ty(getLLVMContext());
- unsigned AS = Context.getTargetAddressSpace(ETy);
- ResultType = llvm::PointerType::get(PointeeType, AS);
- break;
- }
-
- case Type::VariableArray: {
- const VariableArrayType *A = cast<VariableArrayType>(Ty);
- assert(A->getIndexTypeCVRQualifiers() == 0 &&
- "FIXME: We only handle trivial array types so far!");
- // VLAs resolve to the innermost element type; this matches
- // the return of alloca, and there isn't any obviously better choice.
- ResultType = ConvertTypeForMem(A->getElementType());
- break;
- }
- case Type::IncompleteArray: {
- const IncompleteArrayType *A = cast<IncompleteArrayType>(Ty);
- assert(A->getIndexTypeCVRQualifiers() == 0 &&
- "FIXME: We only handle trivial array types so far!");
- // int X[] -> [0 x int], unless the element type is not sized. If it is
- // unsized (e.g. an incomplete struct) just use [0 x i8].
- ResultType = ConvertTypeForMem(A->getElementType());
- if (!ResultType->isSized()) {
- SkippedLayout = true;
- ResultType = llvm::Type::getInt8Ty(getLLVMContext());
- }
- ResultType = llvm::ArrayType::get(ResultType, 0);
- break;
- }
- case Type::ConstantArray: {
- const ConstantArrayType *A = cast<ConstantArrayType>(Ty);
- llvm::Type *EltTy = ConvertTypeForMem(A->getElementType());
-
- // Lower arrays of undefined struct type to arrays of i8 just to have a
- // concrete type.
- if (!EltTy->isSized()) {
- SkippedLayout = true;
- EltTy = llvm::Type::getInt8Ty(getLLVMContext());
- }
-
- ResultType = llvm::ArrayType::get(EltTy, A->getSize().getZExtValue());
- break;
- }
- case Type::ExtVector:
- case Type::Vector: {
- const VectorType *VT = cast<VectorType>(Ty);
- ResultType = llvm::VectorType::get(ConvertType(VT->getElementType()),
- VT->getNumElements());
- break;
- }
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- ResultType = ConvertFunctionType(T);
- break;
- case Type::ObjCObject:
- ResultType = ConvertType(cast<ObjCObjectType>(Ty)->getBaseType());
- break;
-
- case Type::ObjCInterface: {
- // Objective-C interfaces are always opaque (outside of the
- // runtime, which can do whatever it likes); we never refine
- // these.
- llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(Ty)];
- if (!T)
- T = llvm::StructType::create(getLLVMContext());
- ResultType = T;
- break;
- }
-
- case Type::ObjCObjectPointer: {
- // Protocol qualifications do not influence the LLVM type, we just return a
- // pointer to the underlying interface type. We don't need to worry about
- // recursive conversion.
- llvm::Type *T =
- ConvertTypeForMem(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
- ResultType = T->getPointerTo();
- break;
- }
-
- case Type::Enum: {
- const EnumDecl *ED = cast<EnumType>(Ty)->getDecl();
- if (ED->isCompleteDefinition() || ED->isFixed())
- return ConvertType(ED->getIntegerType());
- // Return a placeholder 'i32' type. This can be changed later when the
- // type is defined (see UpdateCompletedType), but is likely to be the
- // "right" answer.
- ResultType = llvm::Type::getInt32Ty(getLLVMContext());
- break;
- }
-
- case Type::BlockPointer: {
- const QualType FTy = cast<BlockPointerType>(Ty)->getPointeeType();
- llvm::Type *PointeeType = ConvertTypeForMem(FTy);
- unsigned AS = Context.getTargetAddressSpace(FTy);
- ResultType = llvm::PointerType::get(PointeeType, AS);
- break;
- }
-
- case Type::MemberPointer: {
- auto *MPTy = cast<MemberPointerType>(Ty);
- if (!getCXXABI().isMemberPointerConvertible(MPTy)) {
- RecordsWithOpaqueMemberPointers.insert(MPTy->getClass());
- ResultType = llvm::StructType::create(getLLVMContext());
- } else {
- ResultType = getCXXABI().ConvertMemberPointerType(MPTy);
- }
- break;
- }
-
- case Type::Atomic: {
- QualType valueType = cast<AtomicType>(Ty)->getValueType();
- ResultType = ConvertTypeForMem(valueType);
-
- // Pad out to the inflated size if necessary.
- uint64_t valueSize = Context.getTypeSize(valueType);
- uint64_t atomicSize = Context.getTypeSize(Ty);
- if (valueSize != atomicSize) {
- assert(valueSize < atomicSize);
- llvm::Type *elts[] = {
- ResultType,
- llvm::ArrayType::get(CGM.Int8Ty, (atomicSize - valueSize) / 8)
- };
- ResultType = llvm::StructType::get(getLLVMContext(),
- llvm::makeArrayRef(elts));
- }
- break;
- }
- case Type::Pipe: {
- ResultType = CGM.getOpenCLRuntime().getPipeType(cast<PipeType>(Ty));
- break;
- }
- }
-
- assert(ResultType && "Didn't convert a type?");
-
- TypeCache[Ty] = ResultType;
- return ResultType;
-}
-
-bool CodeGenModule::isPaddedAtomicType(QualType type) {
- return isPaddedAtomicType(type->castAs<AtomicType>());
-}
-
-bool CodeGenModule::isPaddedAtomicType(const AtomicType *type) {
- return Context.getTypeSize(type) != Context.getTypeSize(type->getValueType());
-}
-
-/// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
-llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
- // TagDecl's are not necessarily unique, instead use the (clang)
- // type connected to the decl.
- const Type *Key = Context.getTagDeclType(RD).getTypePtr();
-
- llvm::StructType *&Entry = RecordDeclTypes[Key];
-
- // If we don't have a StructType at all yet, create the forward declaration.
- if (!Entry) {
- Entry = llvm::StructType::create(getLLVMContext());
- addRecordTypeName(RD, Entry, "");
- }
- llvm::StructType *Ty = Entry;
-
- // If this is still a forward declaration, or the LLVM type is already
- // complete, there's nothing more to do.
- RD = RD->getDefinition();
- if (!RD || !RD->isCompleteDefinition() || !Ty->isOpaque())
- return Ty;
-
- // If converting this type would cause us to infinitely loop, don't do it!
- if (!isSafeToConvert(RD, *this)) {
- DeferredRecords.push_back(RD);
- return Ty;
- }
-
- // Okay, this is a definition of a type. Compile the implementation now.
- bool InsertResult = RecordsBeingLaidOut.insert(Key).second;
- (void)InsertResult;
- assert(InsertResult && "Recursively compiling a struct?");
-
- // Force conversion of non-virtual base classes recursively.
- if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (const auto &I : CRD->bases()) {
- if (I.isVirtual()) continue;
-
- ConvertRecordDeclType(I.getType()->getAs<RecordType>()->getDecl());
- }
- }
-
- // Layout fields.
- CGRecordLayout *Layout = ComputeRecordLayout(RD, Ty);
- CGRecordLayouts[Key] = Layout;
-
- // We're done laying out this struct.
- bool EraseResult = RecordsBeingLaidOut.erase(Key); (void)EraseResult;
- assert(EraseResult && "struct not in RecordsBeingLaidOut set?");
-
- // If this struct blocked a FunctionType conversion, then recompute whatever
- // was derived from that.
- // FIXME: This is hugely overconservative.
- if (SkippedLayout)
- TypeCache.clear();
-
- // If we're done converting the outer-most record, then convert any deferred
- // structs as well.
- if (RecordsBeingLaidOut.empty())
- while (!DeferredRecords.empty())
- ConvertRecordDeclType(DeferredRecords.pop_back_val());
-
- return Ty;
-}
-
-/// getCGRecordLayout - Return record layout info for the given record decl.
-const CGRecordLayout &
-CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
- const Type *Key = Context.getTagDeclType(RD).getTypePtr();
-
- const CGRecordLayout *Layout = CGRecordLayouts.lookup(Key);
- if (!Layout) {
- // Compute the type information.
- ConvertRecordDeclType(RD);
-
- // Now try again.
- Layout = CGRecordLayouts.lookup(Key);
- }
-
- assert(Layout && "Unable to find record layout information for type");
- return *Layout;
-}
-
-bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
- assert((T->isAnyPointerType() || T->isBlockPointerType()) && "Invalid type");
- return isZeroInitializable(T);
-}
-
-bool CodeGenTypes::isZeroInitializable(QualType T) {
- if (T->getAs<PointerType>())
- return Context.getTargetNullPointerValue(T) == 0;
-
- if (const auto *AT = Context.getAsArrayType(T)) {
- if (isa<IncompleteArrayType>(AT))
- return true;
- if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
- if (Context.getConstantArrayElementCount(CAT) == 0)
- return true;
- T = Context.getBaseElementType(T);
- }
-
- // Records are non-zero-initializable if they contain any
- // non-zero-initializable subobjects.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- return isZeroInitializable(RD);
- }
-
- // We have to ask the ABI about member pointers.
- if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
- return getCXXABI().isZeroInitializable(MPT);
-
- // Everything else is okay.
- return true;
-}
-
-bool CodeGenTypes::isZeroInitializable(const RecordDecl *RD) {
- return getCGRecordLayout(RD).isZeroInitializable();
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h b/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h
deleted file mode 100644
index 8e344e91b8c..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h
+++ /dev/null
@@ -1,381 +0,0 @@
-//===--- CodeGenTypes.h - Type translation for LLVM CodeGen -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the code that handles AST -> LLVM type lowering.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
-#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
-
-#include "CGCall.h"
-#include "clang/Basic/ABI.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/Module.h"
-
-namespace llvm {
-class FunctionType;
-class DataLayout;
-class Type;
-class LLVMContext;
-class StructType;
-}
-
-namespace clang {
-class ASTContext;
-template <typename> class CanQual;
-class CXXConstructorDecl;
-class CXXDestructorDecl;
-class CXXMethodDecl;
-class CodeGenOptions;
-class FieldDecl;
-class FunctionProtoType;
-class ObjCInterfaceDecl;
-class ObjCIvarDecl;
-class PointerType;
-class QualType;
-class RecordDecl;
-class TagDecl;
-class TargetInfo;
-class Type;
-typedef CanQual<Type> CanQualType;
-class GlobalDecl;
-
-namespace CodeGen {
-class ABIInfo;
-class CGCXXABI;
-class CGRecordLayout;
-class CodeGenModule;
-class RequiredArgs;
-
-enum class StructorType {
- Complete, // constructor or destructor
- Base, // constructor or destructor
- Deleting // destructor only
-};
-
-inline CXXCtorType toCXXCtorType(StructorType T) {
- switch (T) {
- case StructorType::Complete:
- return Ctor_Complete;
- case StructorType::Base:
- return Ctor_Base;
- case StructorType::Deleting:
- llvm_unreachable("cannot have a deleting ctor");
- }
- llvm_unreachable("not a StructorType");
-}
-
-inline StructorType getFromCtorType(CXXCtorType T) {
- switch (T) {
- case Ctor_Complete:
- return StructorType::Complete;
- case Ctor_Base:
- return StructorType::Base;
- case Ctor_Comdat:
- llvm_unreachable("not expecting a COMDAT");
- case Ctor_CopyingClosure:
- case Ctor_DefaultClosure:
- llvm_unreachable("not expecting a closure");
- }
- llvm_unreachable("not a CXXCtorType");
-}
-
-inline CXXDtorType toCXXDtorType(StructorType T) {
- switch (T) {
- case StructorType::Complete:
- return Dtor_Complete;
- case StructorType::Base:
- return Dtor_Base;
- case StructorType::Deleting:
- return Dtor_Deleting;
- }
- llvm_unreachable("not a StructorType");
-}
-
-inline StructorType getFromDtorType(CXXDtorType T) {
- switch (T) {
- case Dtor_Deleting:
- return StructorType::Deleting;
- case Dtor_Complete:
- return StructorType::Complete;
- case Dtor_Base:
- return StructorType::Base;
- case Dtor_Comdat:
- llvm_unreachable("not expecting a COMDAT");
- }
- llvm_unreachable("not a CXXDtorType");
-}
-
-/// This class organizes the cross-module state that is used while lowering
-/// AST types to LLVM types.
-class CodeGenTypes {
- CodeGenModule &CGM;
- // Some of this stuff should probably be left on the CGM.
- ASTContext &Context;
- llvm::Module &TheModule;
- const TargetInfo &Target;
- CGCXXABI &TheCXXABI;
-
- // This should not be moved earlier, since its initialization depends on some
- // of the previous reference members being already initialized
- const ABIInfo &TheABIInfo;
-
- /// The opaque type map for Objective-C interfaces. All direct
- /// manipulation is done by the runtime interfaces, which are
- /// responsible for coercing to the appropriate type; these opaque
- /// types are never refined.
- llvm::DenseMap<const ObjCInterfaceType*, llvm::Type *> InterfaceTypes;
-
- /// Maps clang struct type with corresponding record layout info.
- llvm::DenseMap<const Type*, CGRecordLayout *> CGRecordLayouts;
-
- /// Contains the LLVM IR type for any converted RecordDecl.
- llvm::DenseMap<const Type*, llvm::StructType *> RecordDeclTypes;
-
- /// Hold memoized CGFunctionInfo results.
- llvm::FoldingSet<CGFunctionInfo> FunctionInfos;
-
- /// This set keeps track of records that we're currently converting
- /// to an IR type. For example, when converting:
- /// struct A { struct B { int x; } } when processing 'x', the 'A' and 'B'
- /// types will be in this set.
- llvm::SmallPtrSet<const Type*, 4> RecordsBeingLaidOut;
-
- llvm::SmallPtrSet<const CGFunctionInfo*, 4> FunctionsBeingProcessed;
-
- /// True if we didn't layout a function due to a being inside
- /// a recursive struct conversion, set this to true.
- bool SkippedLayout;
-
- SmallVector<const RecordDecl *, 8> DeferredRecords;
-
- /// This map keeps cache of llvm::Types and maps clang::Type to
- /// corresponding llvm::Type.
- llvm::DenseMap<const Type *, llvm::Type *> TypeCache;
-
- llvm::SmallSet<const Type *, 8> RecordsWithOpaqueMemberPointers;
-
-public:
- CodeGenTypes(CodeGenModule &cgm);
- ~CodeGenTypes();
-
- const llvm::DataLayout &getDataLayout() const {
- return TheModule.getDataLayout();
- }
- ASTContext &getContext() const { return Context; }
- const ABIInfo &getABIInfo() const { return TheABIInfo; }
- const TargetInfo &getTarget() const { return Target; }
- CGCXXABI &getCXXABI() const { return TheCXXABI; }
- llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
- const CodeGenOptions &getCodeGenOpts() const;
-
- /// Convert clang calling convention to LLVM callilng convention.
- unsigned ClangCallConvToLLVMCallConv(CallingConv CC);
-
- /// ConvertType - Convert type T into a llvm::Type.
- llvm::Type *ConvertType(QualType T);
-
- /// Converts the GlobalDecl into an llvm::Type. This should be used
- /// when we know the target of the function we want to convert. This is
- /// because some functions (explicitly, those with pass_object_size
- /// parameters) may not have the same signature as their type portrays, and
- /// can only be called directly.
- llvm::Type *ConvertFunctionType(QualType FT,
- const FunctionDecl *FD = nullptr);
-
- /// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
- /// ConvertType in that it is used to convert to the memory representation for
- /// a type. For example, the scalar representation for _Bool is i1, but the
- /// memory representation is usually i8 or i32, depending on the target.
- llvm::Type *ConvertTypeForMem(QualType T);
-
- /// GetFunctionType - Get the LLVM function type for \arg Info.
- llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info);
-
- llvm::FunctionType *GetFunctionType(GlobalDecl GD);
-
- /// isFuncTypeConvertible - Utility to check whether a function type can
- /// be converted to an LLVM type (i.e. doesn't depend on an incomplete tag
- /// type).
- bool isFuncTypeConvertible(const FunctionType *FT);
- bool isFuncParamTypeConvertible(QualType Ty);
-
- /// Determine if a C++ inheriting constructor should have parameters matching
- /// those of its inherited constructor.
- bool inheritingCtorHasParams(const InheritedConstructor &Inherited,
- CXXCtorType Type);
-
- /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable,
- /// given a CXXMethodDecl. If the method to has an incomplete return type,
- /// and/or incomplete argument types, this will return the opaque type.
- llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD);
-
- const CGRecordLayout &getCGRecordLayout(const RecordDecl*);
-
- /// UpdateCompletedType - When we find the full definition for a TagDecl,
- /// replace the 'opaque' type we previously made for it if applicable.
- void UpdateCompletedType(const TagDecl *TD);
-
- /// Remove stale types from the type cache when an inheritance model
- /// gets assigned to a class.
- void RefreshTypeCacheForClass(const CXXRecordDecl *RD);
-
- // The arrangement methods are split into three families:
- // - those meant to drive the signature and prologue/epilogue
- // of a function declaration or definition,
- // - those meant for the computation of the LLVM type for an abstract
- // appearance of a function, and
- // - those meant for performing the IR-generation of a call.
- // They differ mainly in how they deal with optional (i.e. variadic)
- // arguments, as well as unprototyped functions.
- //
- // Key points:
- // - The CGFunctionInfo for emitting a specific call site must include
- // entries for the optional arguments.
- // - The function type used at the call site must reflect the formal
- // signature of the declaration being called, or else the call will
- // go awry.
- // - For the most part, unprototyped functions are called by casting to
- // a formal signature inferred from the specific argument types used
- // at the call-site. However, some targets (e.g. x86-64) screw with
- // this for compatibility reasons.
-
- const CGFunctionInfo &arrangeGlobalDeclaration(GlobalDecl GD);
-
- /// Given a function info for a declaration, return the function info
- /// for a call with the given arguments.
- ///
- /// Often this will be able to simply return the declaration info.
- const CGFunctionInfo &arrangeCall(const CGFunctionInfo &declFI,
- const CallArgList &args);
-
- /// Free functions are functions that are compatible with an ordinary
- /// C function pointer type.
- const CGFunctionInfo &arrangeFunctionDeclaration(const FunctionDecl *FD);
- const CGFunctionInfo &arrangeFreeFunctionCall(const CallArgList &Args,
- const FunctionType *Ty,
- bool ChainCall);
- const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty,
- const FunctionDecl *FD);
- const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);
-
- /// A nullary function is a freestanding function of type 'void ()'.
- /// This method works for both calls and declarations.
- const CGFunctionInfo &arrangeNullaryFunction();
-
- /// A builtin function is a freestanding function using the default
- /// C conventions.
- const CGFunctionInfo &
- arrangeBuiltinFunctionDeclaration(QualType resultType,
- const FunctionArgList &args);
- const CGFunctionInfo &
- arrangeBuiltinFunctionDeclaration(CanQualType resultType,
- ArrayRef<CanQualType> argTypes);
- const CGFunctionInfo &arrangeBuiltinFunctionCall(QualType resultType,
- const CallArgList &args);
-
- /// Objective-C methods are C functions with some implicit parameters.
- const CGFunctionInfo &arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD);
- const CGFunctionInfo &arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
- QualType receiverType);
- const CGFunctionInfo &arrangeUnprototypedObjCMessageSend(
- QualType returnType,
- const CallArgList &args);
-
- /// Block invocation functions are C functions with an implicit parameter.
- const CGFunctionInfo &arrangeBlockFunctionDeclaration(
- const FunctionProtoType *type,
- const FunctionArgList &args);
- const CGFunctionInfo &arrangeBlockFunctionCall(const CallArgList &args,
- const FunctionType *type);
-
- /// C++ methods have some special rules and also have implicit parameters.
- const CGFunctionInfo &arrangeCXXMethodDeclaration(const CXXMethodDecl *MD);
- const CGFunctionInfo &arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
- StructorType Type);
- const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args,
- const CXXConstructorDecl *D,
- CXXCtorType CtorKind,
- unsigned ExtraPrefixArgs,
- unsigned ExtraSuffixArgs,
- bool PassProtoArgs = true);
-
- const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
- const FunctionProtoType *type,
- RequiredArgs required,
- unsigned numPrefixArgs);
- const CGFunctionInfo &
- arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD);
- const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
- CXXCtorType CT);
- const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP,
- const CXXMethodDecl *MD);
-
- /// "Arrange" the LLVM information for a call or type with the given
- /// signature. This is largely an internal method; other clients
- /// should use one of the above routines, which ultimately defer to
- /// this.
- ///
- /// \param argTypes - must all actually be canonical as params
- const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType,
- bool instanceMethod,
- bool chainCall,
- ArrayRef<CanQualType> argTypes,
- FunctionType::ExtInfo info,
- ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
- RequiredArgs args);
-
- /// Compute a new LLVM record layout object for the given record.
- CGRecordLayout *ComputeRecordLayout(const RecordDecl *D,
- llvm::StructType *Ty);
-
- /// addRecordTypeName - Compute a name from the given record decl with an
- /// optional suffix and name the given LLVM type using it.
- void addRecordTypeName(const RecordDecl *RD, llvm::StructType *Ty,
- StringRef suffix);
-
-
-public: // These are internal details of CGT that shouldn't be used externally.
- /// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
- llvm::StructType *ConvertRecordDeclType(const RecordDecl *TD);
-
- /// getExpandedTypes - Expand the type \arg Ty into the LLVM
- /// argument types it would be passed as. See ABIArgInfo::Expand.
- void getExpandedTypes(QualType Ty,
- SmallVectorImpl<llvm::Type *>::iterator &TI);
-
- /// IsZeroInitializable - Return whether a type can be
- /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
- bool isZeroInitializable(QualType T);
-
- /// Check if the pointer type can be zero-initialized (in the C++ sense)
- /// with an LLVM zeroinitializer.
- bool isPointerZeroInitializable(QualType T);
-
- /// IsZeroInitializable - Return whether a record type can be
- /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
- bool isZeroInitializable(const RecordDecl *RD);
-
- bool isRecordLayoutComplete(const Type *Ty) const;
- bool noRecordsBeingLaidOut() const {
- return RecordsBeingLaidOut.empty();
- }
- bool isRecordBeingLaidOut(const Type *Ty) const {
- return RecordsBeingLaidOut.count(Ty);
- }
-
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/ConstantEmitter.h b/gnu/llvm/tools/clang/lib/CodeGen/ConstantEmitter.h
deleted file mode 100644
index 7ad8e5d37cd..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/ConstantEmitter.h
+++ /dev/null
@@ -1,181 +0,0 @@
-//===--- ConstantEmitter.h - IR constant emission ---------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// A helper class for emitting expressions and values as llvm::Constants
-// and as initializers for global variables.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H
-#define LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H
-
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-
-namespace clang {
-namespace CodeGen {
-
-class ConstantEmitter {
-public:
- CodeGenModule &CGM;
- CodeGenFunction *CGF;
-
-private:
- bool Abstract = false;
-
- /// Whether non-abstract components of the emitter have been initialized.
- bool InitializedNonAbstract = false;
-
- /// Whether the emitter has been finalized.
- bool Finalized = false;
-
- /// Whether the constant-emission failed.
- bool Failed = false;
-
- /// Whether we're in a constant context.
- bool InConstantContext = false;
-
- /// The AST address space where this (non-abstract) initializer is going.
- /// Used for generating appropriate placeholders.
- LangAS DestAddressSpace;
-
- llvm::SmallVector<std::pair<llvm::Constant *, llvm::GlobalVariable*>, 4>
- PlaceholderAddresses;
-
-public:
- ConstantEmitter(CodeGenModule &CGM, CodeGenFunction *CGF = nullptr)
- : CGM(CGM), CGF(CGF) {}
-
- /// Initialize this emission in the context of the given function.
- /// Use this if the expression might contain contextual references like
- /// block addresses or PredefinedExprs.
- ConstantEmitter(CodeGenFunction &CGF)
- : CGM(CGF.CGM), CGF(&CGF) {}
-
- ConstantEmitter(const ConstantEmitter &other) = delete;
- ConstantEmitter &operator=(const ConstantEmitter &other) = delete;
-
- ~ConstantEmitter();
-
- /// Is the current emission context abstract?
- bool isAbstract() const {
- return Abstract;
- }
-
- /// Try to emit the initiaizer of the given declaration as an abstract
- /// constant. If this succeeds, the emission must be finalized.
- llvm::Constant *tryEmitForInitializer(const VarDecl &D);
- llvm::Constant *tryEmitForInitializer(const Expr *E, LangAS destAddrSpace,
- QualType destType);
- llvm::Constant *emitForInitializer(const APValue &value, LangAS destAddrSpace,
- QualType destType);
-
- void finalize(llvm::GlobalVariable *global);
-
- // All of the "abstract" emission methods below permit the emission to
- // be immediately discarded without finalizing anything. Therefore, they
- // must also promise not to do anything that will, in the future, require
- // finalization:
- //
- // - using the CGF (if present) for anything other than establishing
- // semantic context; for example, an expression with ignored
- // side-effects must not be emitted as an abstract expression
- //
- // - doing anything that would not be safe to duplicate within an
- // initializer or to propagate to another context; for example,
- // side effects, or emitting an initialization that requires a
- // reference to its current location.
-
- /// Try to emit the initializer of the given declaration as an abstract
- /// constant.
- llvm::Constant *tryEmitAbstractForInitializer(const VarDecl &D);
-
- /// Emit the result of the given expression as an abstract constant,
- /// asserting that it succeeded. This is only safe to do when the
- /// expression is known to be a constant expression with either a fairly
- /// simple type or a known simple form.
- llvm::Constant *emitAbstract(const Expr *E, QualType T);
- llvm::Constant *emitAbstract(SourceLocation loc, const APValue &value,
- QualType T);
-
- /// Try to emit the result of the given expression as an abstract constant.
- llvm::Constant *tryEmitAbstract(const Expr *E, QualType T);
- llvm::Constant *tryEmitAbstractForMemory(const Expr *E, QualType T);
-
- llvm::Constant *tryEmitAbstract(const APValue &value, QualType T);
- llvm::Constant *tryEmitAbstractForMemory(const APValue &value, QualType T);
-
- llvm::Constant *emitNullForMemory(QualType T) {
- return emitNullForMemory(CGM, T);
- }
- llvm::Constant *emitForMemory(llvm::Constant *C, QualType T) {
- return emitForMemory(CGM, C, T);
- }
-
- static llvm::Constant *emitNullForMemory(CodeGenModule &CGM, QualType T);
- static llvm::Constant *emitForMemory(CodeGenModule &CGM, llvm::Constant *C,
- QualType T);
-
- // These are private helper routines of the constant emitter that
- // can't actually be private because things are split out into helper
- // functions and classes.
-
- llvm::Constant *tryEmitPrivateForVarInit(const VarDecl &D);
-
- llvm::Constant *tryEmitPrivate(const Expr *E, QualType T);
- llvm::Constant *tryEmitPrivateForMemory(const Expr *E, QualType T);
-
- llvm::Constant *tryEmitPrivate(const APValue &value, QualType T);
- llvm::Constant *tryEmitPrivateForMemory(const APValue &value, QualType T);
-
- /// Get the address of the current location. This is a constant
- /// that will resolve, after finalization, to the address of the
- /// 'signal' value that is registered with the emitter later.
- llvm::GlobalValue *getCurrentAddrPrivate();
-
- /// Register a 'signal' value with the emitter to inform it where to
- /// resolve a placeholder. The signal value must be unique in the
- /// initializer; it might, for example, be the address of a global that
- /// refers to the current-address value in its own initializer.
- ///
- /// Uses of the placeholder must be properly anchored before finalizing
- /// the emitter, e.g. by being installed as the initializer of a global
- /// variable. That is, it must be possible to replaceAllUsesWith
- /// the placeholder with the proper address of the signal.
- void registerCurrentAddrPrivate(llvm::Constant *signal,
- llvm::GlobalValue *placeholder);
-
-private:
- void initializeNonAbstract(LangAS destAS) {
- assert(!InitializedNonAbstract);
- InitializedNonAbstract = true;
- DestAddressSpace = destAS;
- }
- llvm::Constant *markIfFailed(llvm::Constant *init) {
- if (!init)
- Failed = true;
- return init;
- }
-
- struct AbstractState {
- bool OldValue;
- size_t OldPlaceholdersSize;
- };
- AbstractState pushAbstract() {
- AbstractState saved = { Abstract, PlaceholderAddresses.size() };
- Abstract = true;
- return saved;
- }
- llvm::Constant *validateAndPopAbstract(llvm::Constant *C, AbstractState save);
-};
-
-}
-}
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp b/gnu/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp
deleted file mode 100644
index 59e66b88fb0..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-//===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines out-of-line routines for building initializers for
-// global variables, in particular the kind of globals that are implicitly
-// introduced by various language ABIs.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "CodeGenModule.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-llvm::Type *ConstantInitFuture::getType() const {
- assert(Data && "dereferencing null future");
- if (Data.is<llvm::Constant*>()) {
- return Data.get<llvm::Constant*>()->getType();
- } else {
- return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
- }
-}
-
-void ConstantInitFuture::abandon() {
- assert(Data && "abandoning null future");
- if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
- builder->abandon(0);
- }
- Data = nullptr;
-}
-
-void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
- assert(Data && "installing null future");
- if (Data.is<llvm::Constant*>()) {
- GV->setInitializer(Data.get<llvm::Constant*>());
- } else {
- auto &builder = *Data.get<ConstantInitBuilderBase*>();
- assert(builder.Buffer.size() == 1);
- builder.setGlobalInitializer(GV, builder.Buffer[0]);
- builder.Buffer.clear();
- Data = nullptr;
- }
-}
-
-ConstantInitFuture
-ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
- assert(Buffer.empty() && "buffer not current empty");
- Buffer.push_back(initializer);
- return ConstantInitFuture(this);
-}
-
-// Only used in this file.
-inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
- : Data(builder) {
- assert(!builder->Frozen);
- assert(builder->Buffer.size() == 1);
- assert(builder->Buffer[0] != nullptr);
-}
-
-llvm::GlobalVariable *
-ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
- const llvm::Twine &name,
- CharUnits alignment,
- bool constant,
- llvm::GlobalValue::LinkageTypes linkage,
- unsigned addressSpace) {
- auto GV = new llvm::GlobalVariable(CGM.getModule(),
- initializer->getType(),
- constant,
- linkage,
- initializer,
- name,
- /*insert before*/ nullptr,
- llvm::GlobalValue::NotThreadLocal,
- addressSpace);
- GV->setAlignment(alignment.getQuantity());
- resolveSelfReferences(GV);
- return GV;
-}
-
-void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
- llvm::Constant *initializer){
- GV->setInitializer(initializer);
-
- if (!SelfReferences.empty())
- resolveSelfReferences(GV);
-}
-
-void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
- for (auto &entry : SelfReferences) {
- llvm::Constant *resolvedReference =
- llvm::ConstantExpr::getInBoundsGetElementPtr(
- GV->getValueType(), GV, entry.Indices);
- auto dummy = entry.Dummy;
- dummy->replaceAllUsesWith(resolvedReference);
- dummy->eraseFromParent();
- }
- SelfReferences.clear();
-}
-
-void ConstantInitBuilderBase::abandon(size_t newEnd) {
- // Remove all the entries we've added.
- Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
-
- // If we're abandoning all the way to the beginning, destroy
- // all the self-references, because we might not get another
- // opportunity.
- if (newEnd == 0) {
- for (auto &entry : SelfReferences) {
- auto dummy = entry.Dummy;
- dummy->replaceAllUsesWith(llvm::UndefValue::get(dummy->getType()));
- dummy->eraseFromParent();
- }
- SelfReferences.clear();
- }
-}
-
-void ConstantAggregateBuilderBase::addSize(CharUnits size) {
- add(Builder.CGM.getSize(size));
-}
-
-llvm::Constant *
-ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
- llvm::Constant *target) {
- // Compute the address of the relative-address slot.
- auto base = getAddrOfCurrentPosition(offsetType);
-
- // Subtract.
- base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
- target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
- llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
-
- // Truncate to the relative-address type if necessary.
- if (Builder.CGM.IntPtrTy != offsetType) {
- offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
- }
-
- return offset;
-}
-
-llvm::Constant *
-ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {
- // Make a global variable. We will replace this with a GEP to this
- // position after installing the initializer.
- auto dummy =
- new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
- llvm::GlobalVariable::PrivateLinkage,
- nullptr, "");
- Builder.SelfReferences.emplace_back(dummy);
- auto &entry = Builder.SelfReferences.back();
- (void) getGEPIndicesToCurrentPosition(entry.Indices);
- return dummy;
-}
-
-void ConstantAggregateBuilderBase::getGEPIndicesTo(
- llvm::SmallVectorImpl<llvm::Constant*> &indices,
- size_t position) const {
- // Recurse on the parent builder if present.
- if (Parent) {
- Parent->getGEPIndicesTo(indices, Begin);
-
- // Otherwise, add an index to drill into the first level of pointer.
- } else {
- assert(indices.empty());
- indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
- }
-
- assert(position >= Begin);
- // We have to use i32 here because struct GEPs demand i32 indices.
- // It's rather unlikely to matter in practice.
- indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
- position - Begin));
-}
-
-ConstantAggregateBuilderBase::PlaceholderPosition
-ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
- // Bring the offset up to the last field.
- CharUnits offset = getNextOffsetFromGlobal();
-
- // Create the placeholder.
- auto position = addPlaceholder();
-
- // Advance the offset past that field.
- auto &layout = Builder.CGM.getDataLayout();
- if (!Packed)
- offset = offset.alignTo(CharUnits::fromQuantity(
- layout.getABITypeAlignment(type)));
- offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
-
- CachedOffsetEnd = Builder.Buffer.size();
- CachedOffsetFromGlobal = offset;
-
- return position;
-}
-
-CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
- size_t cacheEnd = CachedOffsetEnd;
- assert(cacheEnd <= end);
-
- // Fast path: if the cache is valid, just use it.
- if (cacheEnd == end) {
- return CachedOffsetFromGlobal;
- }
-
- // If the cached range ends before the index at which the current
- // aggregate starts, recurse for the parent.
- CharUnits offset;
- if (cacheEnd < Begin) {
- assert(cacheEnd == 0);
- assert(Parent && "Begin != 0 for root builder");
- cacheEnd = Begin;
- offset = Parent->getOffsetFromGlobalTo(Begin);
- } else {
- offset = CachedOffsetFromGlobal;
- }
-
- // Perform simple layout on the elements in cacheEnd..<end.
- if (cacheEnd != end) {
- auto &layout = Builder.CGM.getDataLayout();
- do {
- llvm::Constant *element = Builder.Buffer[cacheEnd];
- assert(element != nullptr &&
- "cannot compute offset when a placeholder is present");
- llvm::Type *elementType = element->getType();
- if (!Packed)
- offset = offset.alignTo(CharUnits::fromQuantity(
- layout.getABITypeAlignment(elementType)));
- offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
- } while (++cacheEnd != end);
- }
-
- // Cache and return.
- CachedOffsetEnd = cacheEnd;
- CachedOffsetFromGlobal = offset;
- return offset;
-}
-
-llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
- markFinished();
-
- auto &buffer = getBuffer();
- assert((Begin < buffer.size() ||
- (Begin == buffer.size() && eltTy))
- && "didn't add any array elements without element type");
- auto elts = llvm::makeArrayRef(buffer).slice(Begin);
- if (!eltTy) eltTy = elts[0]->getType();
- auto type = llvm::ArrayType::get(eltTy, elts.size());
- auto constant = llvm::ConstantArray::get(type, elts);
- buffer.erase(buffer.begin() + Begin, buffer.end());
- return constant;
-}
-
-llvm::Constant *
-ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
- markFinished();
-
- auto &buffer = getBuffer();
- auto elts = llvm::makeArrayRef(buffer).slice(Begin);
-
- if (ty == nullptr && elts.empty())
- ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
-
- llvm::Constant *constant;
- if (ty) {
- assert(ty->isPacked() == Packed);
- constant = llvm::ConstantStruct::get(ty, elts);
- } else {
- constant = llvm::ConstantStruct::getAnon(elts, Packed);
- }
-
- buffer.erase(buffer.begin() + Begin, buffer.end());
- return constant;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp
deleted file mode 100644
index 35962c73d9a..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ /dev/null
@@ -1,1476 +0,0 @@
-//===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Instrumentation-based code coverage mapping generator
-//
-//===----------------------------------------------------------------------===//
-
-#include "CoverageMappingGen.h"
-#include "CodeGenFunction.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ProfileData/Coverage/CoverageMapping.h"
-#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
-#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
-#include "llvm/ProfileData/InstrProfReader.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-
-using namespace clang;
-using namespace CodeGen;
-using namespace llvm::coverage;
-
-void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
- SkippedRanges.push_back(Range);
-}
-
-namespace {
-
-/// A region of source code that can be mapped to a counter.
-class SourceMappingRegion {
- Counter Count;
-
- /// The region's starting location.
- Optional<SourceLocation> LocStart;
-
- /// The region's ending location.
- Optional<SourceLocation> LocEnd;
-
- /// Whether this region should be emitted after its parent is emitted.
- bool DeferRegion;
-
- /// Whether this region is a gap region. The count from a gap region is set
- /// as the line execution count if there are no other regions on the line.
- bool GapRegion;
-
-public:
- SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart,
- Optional<SourceLocation> LocEnd, bool DeferRegion = false,
- bool GapRegion = false)
- : Count(Count), LocStart(LocStart), LocEnd(LocEnd),
- DeferRegion(DeferRegion), GapRegion(GapRegion) {}
-
- const Counter &getCounter() const { return Count; }
-
- void setCounter(Counter C) { Count = C; }
-
- bool hasStartLoc() const { return LocStart.hasValue(); }
-
- void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
-
- SourceLocation getBeginLoc() const {
- assert(LocStart && "Region has no start location");
- return *LocStart;
- }
-
- bool hasEndLoc() const { return LocEnd.hasValue(); }
-
- void setEndLoc(SourceLocation Loc) {
- assert(Loc.isValid() && "Setting an invalid end location");
- LocEnd = Loc;
- }
-
- SourceLocation getEndLoc() const {
- assert(LocEnd && "Region has no end location");
- return *LocEnd;
- }
-
- bool isDeferred() const { return DeferRegion; }
-
- void setDeferred(bool Deferred) { DeferRegion = Deferred; }
-
- bool isGap() const { return GapRegion; }
-
- void setGap(bool Gap) { GapRegion = Gap; }
-};
-
-/// Spelling locations for the start and end of a source region.
-struct SpellingRegion {
- /// The line where the region starts.
- unsigned LineStart;
-
- /// The column where the region starts.
- unsigned ColumnStart;
-
- /// The line where the region ends.
- unsigned LineEnd;
-
- /// The column where the region ends.
- unsigned ColumnEnd;
-
- SpellingRegion(SourceManager &SM, SourceLocation LocStart,
- SourceLocation LocEnd) {
- LineStart = SM.getSpellingLineNumber(LocStart);
- ColumnStart = SM.getSpellingColumnNumber(LocStart);
- LineEnd = SM.getSpellingLineNumber(LocEnd);
- ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
- }
-
- SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
- : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
-
- /// Check if the start and end locations appear in source order, i.e
- /// top->bottom, left->right.
- bool isInSourceOrder() const {
- return (LineStart < LineEnd) ||
- (LineStart == LineEnd && ColumnStart <= ColumnEnd);
- }
-};
-
-/// Provides the common functionality for the different
-/// coverage mapping region builders.
-class CoverageMappingBuilder {
-public:
- CoverageMappingModuleGen &CVM;
- SourceManager &SM;
- const LangOptions &LangOpts;
-
-private:
- /// Map of clang's FileIDs to IDs used for coverage mapping.
- llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
- FileIDMapping;
-
-public:
- /// The coverage mapping regions for this function
- llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
- /// The source mapping regions for this function.
- std::vector<SourceMappingRegion> SourceRegions;
-
- /// A set of regions which can be used as a filter.
- ///
- /// It is produced by emitExpansionRegions() and is used in
- /// emitSourceRegions() to suppress producing code regions if
- /// the same area is covered by expansion regions.
- typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
- SourceRegionFilter;
-
- CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
- const LangOptions &LangOpts)
- : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
-
- /// Return the precise end location for the given token.
- SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
- // We avoid getLocForEndOfToken here, because it doesn't do what we want for
- // macro locations, which we just treat as expanded files.
- unsigned TokLen =
- Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
- return Loc.getLocWithOffset(TokLen);
- }
-
- /// Return the start location of an included file or expanded macro.
- SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
- if (Loc.isMacroID())
- return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
- return SM.getLocForStartOfFile(SM.getFileID(Loc));
- }
-
- /// Return the end location of an included file or expanded macro.
- SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
- if (Loc.isMacroID())
- return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
- SM.getFileOffset(Loc));
- return SM.getLocForEndOfFile(SM.getFileID(Loc));
- }
-
- /// Find out where the current file is included or macro is expanded.
- SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
- return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
- : SM.getIncludeLoc(SM.getFileID(Loc));
- }
-
- /// Return true if \c Loc is a location in a built-in macro.
- bool isInBuiltin(SourceLocation Loc) {
- return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
- }
-
- /// Check whether \c Loc is included or expanded from \c Parent.
- bool isNestedIn(SourceLocation Loc, FileID Parent) {
- do {
- Loc = getIncludeOrExpansionLoc(Loc);
- if (Loc.isInvalid())
- return false;
- } while (!SM.isInFileID(Loc, Parent));
- return true;
- }
-
- /// Get the start of \c S ignoring macro arguments and builtin macros.
- SourceLocation getStart(const Stmt *S) {
- SourceLocation Loc = S->getBeginLoc();
- while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
- Loc = SM.getImmediateExpansionRange(Loc).getBegin();
- return Loc;
- }
-
- /// Get the end of \c S ignoring macro arguments and builtin macros.
- SourceLocation getEnd(const Stmt *S) {
- SourceLocation Loc = S->getEndLoc();
- while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
- Loc = SM.getImmediateExpansionRange(Loc).getBegin();
- return getPreciseTokenLocEnd(Loc);
- }
-
- /// Find the set of files we have regions for and assign IDs
- ///
- /// Fills \c Mapping with the virtual file mapping needed to write out
- /// coverage and collects the necessary file information to emit source and
- /// expansion regions.
- void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
- FileIDMapping.clear();
-
- llvm::SmallSet<FileID, 8> Visited;
- SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
- for (const auto &Region : SourceRegions) {
- SourceLocation Loc = Region.getBeginLoc();
- FileID File = SM.getFileID(Loc);
- if (!Visited.insert(File).second)
- continue;
-
- // Do not map FileID's associated with system headers.
- if (SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
- continue;
-
- unsigned Depth = 0;
- for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
- Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
- ++Depth;
- FileLocs.push_back(std::make_pair(Loc, Depth));
- }
- std::stable_sort(FileLocs.begin(), FileLocs.end(), llvm::less_second());
-
- for (const auto &FL : FileLocs) {
- SourceLocation Loc = FL.first;
- FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
- auto Entry = SM.getFileEntryForID(SpellingFile);
- if (!Entry)
- continue;
-
- FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
- Mapping.push_back(CVM.getFileID(Entry));
- }
- }
-
- /// Get the coverage mapping file ID for \c Loc.
- ///
- /// If such file id doesn't exist, return None.
- Optional<unsigned> getCoverageFileID(SourceLocation Loc) {
- auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
- if (Mapping != FileIDMapping.end())
- return Mapping->second.first;
- return None;
- }
-
- /// Gather all the regions that were skipped by the preprocessor
- /// using the constructs like #if.
- void gatherSkippedRegions() {
- /// An array of the minimum lineStarts and the maximum lineEnds
- /// for mapping regions from the appropriate source files.
- llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
- FileLineRanges.resize(
- FileIDMapping.size(),
- std::make_pair(std::numeric_limits<unsigned>::max(), 0));
- for (const auto &R : MappingRegions) {
- FileLineRanges[R.FileID].first =
- std::min(FileLineRanges[R.FileID].first, R.LineStart);
- FileLineRanges[R.FileID].second =
- std::max(FileLineRanges[R.FileID].second, R.LineEnd);
- }
-
- auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
- for (const auto &I : SkippedRanges) {
- auto LocStart = I.getBegin();
- auto LocEnd = I.getEnd();
- assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
- "region spans multiple files");
-
- auto CovFileID = getCoverageFileID(LocStart);
- if (!CovFileID)
- continue;
- SpellingRegion SR{SM, LocStart, LocEnd};
- auto Region = CounterMappingRegion::makeSkipped(
- *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd);
- // Make sure that we only collect the regions that are inside
- // the source code of this function.
- if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
- Region.LineEnd <= FileLineRanges[*CovFileID].second)
- MappingRegions.push_back(Region);
- }
- }
-
- /// Generate the coverage counter mapping regions from collected
- /// source regions.
- void emitSourceRegions(const SourceRegionFilter &Filter) {
- for (const auto &Region : SourceRegions) {
- assert(Region.hasEndLoc() && "incomplete region");
-
- SourceLocation LocStart = Region.getBeginLoc();
- assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
-
- // Ignore regions from system headers.
- if (SM.isInSystemHeader(SM.getSpellingLoc(LocStart)))
- continue;
-
- auto CovFileID = getCoverageFileID(LocStart);
- // Ignore regions that don't have a file, such as builtin macros.
- if (!CovFileID)
- continue;
-
- SourceLocation LocEnd = Region.getEndLoc();
- assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
- "region spans multiple files");
-
- // Don't add code regions for the area covered by expansion regions.
- // This not only suppresses redundant regions, but sometimes prevents
- // creating regions with wrong counters if, for example, a statement's
- // body ends at the end of a nested macro.
- if (Filter.count(std::make_pair(LocStart, LocEnd)))
- continue;
-
- // Find the spelling locations for the mapping region.
- SpellingRegion SR{SM, LocStart, LocEnd};
- assert(SR.isInSourceOrder() && "region start and end out of order");
-
- if (Region.isGap()) {
- MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
- Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
- SR.LineEnd, SR.ColumnEnd));
- } else {
- MappingRegions.push_back(CounterMappingRegion::makeRegion(
- Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
- SR.LineEnd, SR.ColumnEnd));
- }
- }
- }
-
- /// Generate expansion regions for each virtual file we've seen.
- SourceRegionFilter emitExpansionRegions() {
- SourceRegionFilter Filter;
- for (const auto &FM : FileIDMapping) {
- SourceLocation ExpandedLoc = FM.second.second;
- SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
- if (ParentLoc.isInvalid())
- continue;
-
- auto ParentFileID = getCoverageFileID(ParentLoc);
- if (!ParentFileID)
- continue;
- auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
- assert(ExpandedFileID && "expansion in uncovered file");
-
- SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
- assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
- "region spans multiple files");
- Filter.insert(std::make_pair(ParentLoc, LocEnd));
-
- SpellingRegion SR{SM, ParentLoc, LocEnd};
- assert(SR.isInSourceOrder() && "region start and end out of order");
- MappingRegions.push_back(CounterMappingRegion::makeExpansion(
- *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
- SR.LineEnd, SR.ColumnEnd));
- }
- return Filter;
- }
-};
-
-/// Creates unreachable coverage regions for the functions that
-/// are not emitted.
-struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
- EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
- const LangOptions &LangOpts)
- : CoverageMappingBuilder(CVM, SM, LangOpts) {}
-
- void VisitDecl(const Decl *D) {
- if (!D->hasBody())
- return;
- auto Body = D->getBody();
- SourceLocation Start = getStart(Body);
- SourceLocation End = getEnd(Body);
- if (!SM.isWrittenInSameFile(Start, End)) {
- // Walk up to find the common ancestor.
- // Correct the locations accordingly.
- FileID StartFileID = SM.getFileID(Start);
- FileID EndFileID = SM.getFileID(End);
- while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
- Start = getIncludeOrExpansionLoc(Start);
- assert(Start.isValid() &&
- "Declaration start location not nested within a known region");
- StartFileID = SM.getFileID(Start);
- }
- while (StartFileID != EndFileID) {
- End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
- assert(End.isValid() &&
- "Declaration end location not nested within a known region");
- EndFileID = SM.getFileID(End);
- }
- }
- SourceRegions.emplace_back(Counter(), Start, End);
- }
-
- /// Write the mapping data to the output stream
- void write(llvm::raw_ostream &OS) {
- SmallVector<unsigned, 16> FileIDMapping;
- gatherFileIDs(FileIDMapping);
- emitSourceRegions(SourceRegionFilter());
-
- if (MappingRegions.empty())
- return;
-
- CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
- Writer.write(OS);
- }
-};
-
-/// A StmtVisitor that creates coverage mapping regions which map
-/// from the source code locations to the PGO counters.
-struct CounterCoverageMappingBuilder
- : public CoverageMappingBuilder,
- public ConstStmtVisitor<CounterCoverageMappingBuilder> {
- /// The map of statements to count values.
- llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
-
- /// A stack of currently live regions.
- std::vector<SourceMappingRegion> RegionStack;
-
- /// The currently deferred region: its end location and count can be set once
- /// its parent has been popped from the region stack.
- Optional<SourceMappingRegion> DeferredRegion;
-
- CounterExpressionBuilder Builder;
-
- /// A location in the most recently visited file or macro.
- ///
- /// This is used to adjust the active source regions appropriately when
- /// expressions cross file or macro boundaries.
- SourceLocation MostRecentLocation;
-
- /// Location of the last terminated region.
- Optional<std::pair<SourceLocation, size_t>> LastTerminatedRegion;
-
- /// Return a counter for the subtraction of \c RHS from \c LHS
- Counter subtractCounters(Counter LHS, Counter RHS) {
- return Builder.subtract(LHS, RHS);
- }
-
- /// Return a counter for the sum of \c LHS and \c RHS.
- Counter addCounters(Counter LHS, Counter RHS) {
- return Builder.add(LHS, RHS);
- }
-
- Counter addCounters(Counter C1, Counter C2, Counter C3) {
- return addCounters(addCounters(C1, C2), C3);
- }
-
- /// Return the region counter for the given statement.
- ///
- /// This should only be called on statements that have a dedicated counter.
- Counter getRegionCounter(const Stmt *S) {
- return Counter::getCounter(CounterMap[S]);
- }
-
- /// Push a region onto the stack.
- ///
- /// Returns the index on the stack where the region was pushed. This can be
- /// used with popRegions to exit a "scope", ending the region that was pushed.
- size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None,
- Optional<SourceLocation> EndLoc = None) {
- if (StartLoc) {
- MostRecentLocation = *StartLoc;
- completeDeferred(Count, MostRecentLocation);
- }
- RegionStack.emplace_back(Count, StartLoc, EndLoc);
-
- return RegionStack.size() - 1;
- }
-
- /// Complete any pending deferred region by setting its end location and
- /// count, and then pushing it onto the region stack.
- size_t completeDeferred(Counter Count, SourceLocation DeferredEndLoc) {
- size_t Index = RegionStack.size();
- if (!DeferredRegion)
- return Index;
-
- // Consume the pending region.
- SourceMappingRegion DR = DeferredRegion.getValue();
- DeferredRegion = None;
-
- // If the region ends in an expansion, find the expansion site.
- FileID StartFile = SM.getFileID(DR.getBeginLoc());
- if (SM.getFileID(DeferredEndLoc) != StartFile) {
- if (isNestedIn(DeferredEndLoc, StartFile)) {
- do {
- DeferredEndLoc = getIncludeOrExpansionLoc(DeferredEndLoc);
- } while (StartFile != SM.getFileID(DeferredEndLoc));
- } else {
- return Index;
- }
- }
-
- // The parent of this deferred region ends where the containing decl ends,
- // so the region isn't useful.
- if (DR.getBeginLoc() == DeferredEndLoc)
- return Index;
-
- // If we're visiting statements in non-source order (e.g switch cases or
- // a loop condition) we can't construct a sensible deferred region.
- if (!SpellingRegion(SM, DR.getBeginLoc(), DeferredEndLoc).isInSourceOrder())
- return Index;
-
- DR.setGap(true);
- DR.setCounter(Count);
- DR.setEndLoc(DeferredEndLoc);
- handleFileExit(DeferredEndLoc);
- RegionStack.push_back(DR);
- return Index;
- }
-
- /// Complete a deferred region created after a terminated region at the
- /// top-level.
- void completeTopLevelDeferredRegion(Counter Count,
- SourceLocation DeferredEndLoc) {
- if (DeferredRegion || !LastTerminatedRegion)
- return;
-
- if (LastTerminatedRegion->second != RegionStack.size())
- return;
-
- SourceLocation Start = LastTerminatedRegion->first;
- if (SM.getFileID(Start) != SM.getMainFileID())
- return;
-
- SourceMappingRegion DR = RegionStack.back();
- DR.setStartLoc(Start);
- DR.setDeferred(false);
- DeferredRegion = DR;
- completeDeferred(Count, DeferredEndLoc);
- }
-
- size_t locationDepth(SourceLocation Loc) {
- size_t Depth = 0;
- while (Loc.isValid()) {
- Loc = getIncludeOrExpansionLoc(Loc);
- Depth++;
- }
- return Depth;
- }
-
- /// Pop regions from the stack into the function's list of regions.
- ///
- /// Adds all regions from \c ParentIndex to the top of the stack to the
- /// function's \c SourceRegions.
- void popRegions(size_t ParentIndex) {
- assert(RegionStack.size() >= ParentIndex && "parent not in stack");
- bool ParentOfDeferredRegion = false;
- while (RegionStack.size() > ParentIndex) {
- SourceMappingRegion &Region = RegionStack.back();
- if (Region.hasStartLoc()) {
- SourceLocation StartLoc = Region.getBeginLoc();
- SourceLocation EndLoc = Region.hasEndLoc()
- ? Region.getEndLoc()
- : RegionStack[ParentIndex].getEndLoc();
- size_t StartDepth = locationDepth(StartLoc);
- size_t EndDepth = locationDepth(EndLoc);
- while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
- bool UnnestStart = StartDepth >= EndDepth;
- bool UnnestEnd = EndDepth >= StartDepth;
- if (UnnestEnd) {
- // The region ends in a nested file or macro expansion. Create a
- // separate region for each expansion.
- SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
- assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
-
- if (!isRegionAlreadyAdded(NestedLoc, EndLoc))
- SourceRegions.emplace_back(Region.getCounter(), NestedLoc, EndLoc);
-
- EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
- if (EndLoc.isInvalid())
- llvm::report_fatal_error("File exit not handled before popRegions");
- EndDepth--;
- }
- if (UnnestStart) {
- // The region begins in a nested file or macro expansion. Create a
- // separate region for each expansion.
- SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
- assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
-
- if (!isRegionAlreadyAdded(StartLoc, NestedLoc))
- SourceRegions.emplace_back(Region.getCounter(), StartLoc, NestedLoc);
-
- StartLoc = getIncludeOrExpansionLoc(StartLoc);
- if (StartLoc.isInvalid())
- llvm::report_fatal_error("File exit not handled before popRegions");
- StartDepth--;
- }
- }
- Region.setStartLoc(StartLoc);
- Region.setEndLoc(EndLoc);
-
- MostRecentLocation = EndLoc;
- // If this region happens to span an entire expansion, we need to make
- // sure we don't overlap the parent region with it.
- if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
- EndLoc == getEndOfFileOrMacro(EndLoc))
- MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
-
- assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
- assert(SpellingRegion(SM, Region).isInSourceOrder());
- SourceRegions.push_back(Region);
-
- if (ParentOfDeferredRegion) {
- ParentOfDeferredRegion = false;
-
- // If there's an existing deferred region, keep the old one, because
- // it means there are two consecutive returns (or a similar pattern).
- if (!DeferredRegion.hasValue() &&
- // File IDs aren't gathered within macro expansions, so it isn't
- // useful to try and create a deferred region inside of one.
- !EndLoc.isMacroID())
- DeferredRegion =
- SourceMappingRegion(Counter::getZero(), EndLoc, None);
- }
- } else if (Region.isDeferred()) {
- assert(!ParentOfDeferredRegion && "Consecutive deferred regions");
- ParentOfDeferredRegion = true;
- }
- RegionStack.pop_back();
-
- // If the zero region pushed after the last terminated region no longer
- // exists, clear its cached information.
- if (LastTerminatedRegion &&
- RegionStack.size() < LastTerminatedRegion->second)
- LastTerminatedRegion = None;
- }
- assert(!ParentOfDeferredRegion && "Deferred region with no parent");
- }
-
- /// Return the currently active region.
- SourceMappingRegion &getRegion() {
- assert(!RegionStack.empty() && "statement has no region");
- return RegionStack.back();
- }
-
- /// Propagate counts through the children of \p S if \p VisitChildren is true.
- /// Otherwise, only emit a count for \p S itself.
- Counter propagateCounts(Counter TopCount, const Stmt *S,
- bool VisitChildren = true) {
- SourceLocation StartLoc = getStart(S);
- SourceLocation EndLoc = getEnd(S);
- size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
- if (VisitChildren)
- Visit(S);
- Counter ExitCount = getRegion().getCounter();
- popRegions(Index);
-
- // The statement may be spanned by an expansion. Make sure we handle a file
- // exit out of this expansion before moving to the next statement.
- if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
- MostRecentLocation = EndLoc;
-
- return ExitCount;
- }
-
- /// Check whether a region with bounds \c StartLoc and \c EndLoc
- /// is already added to \c SourceRegions.
- bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc) {
- return SourceRegions.rend() !=
- std::find_if(SourceRegions.rbegin(), SourceRegions.rend(),
- [&](const SourceMappingRegion &Region) {
- return Region.getBeginLoc() == StartLoc &&
- Region.getEndLoc() == EndLoc;
- });
- }
-
- /// Adjust the most recently visited location to \c EndLoc.
- ///
- /// This should be used after visiting any statements in non-source order.
- void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
- MostRecentLocation = EndLoc;
- // The code region for a whole macro is created in handleFileExit() when
- // it detects exiting of the virtual file of that macro. If we visited
- // statements in non-source order, we might already have such a region
- // added, for example, if a body of a loop is divided among multiple
- // macros. Avoid adding duplicate regions in such case.
- if (getRegion().hasEndLoc() &&
- MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
- isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
- MostRecentLocation))
- MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
- }
-
- /// Adjust regions and state when \c NewLoc exits a file.
- ///
- /// If moving from our most recently tracked location to \c NewLoc exits any
- /// files, this adjusts our current region stack and creates the file regions
- /// for the exited file.
- void handleFileExit(SourceLocation NewLoc) {
- if (NewLoc.isInvalid() ||
- SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
- return;
-
- // If NewLoc is not in a file that contains MostRecentLocation, walk up to
- // find the common ancestor.
- SourceLocation LCA = NewLoc;
- FileID ParentFile = SM.getFileID(LCA);
- while (!isNestedIn(MostRecentLocation, ParentFile)) {
- LCA = getIncludeOrExpansionLoc(LCA);
- if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
- // Since there isn't a common ancestor, no file was exited. We just need
- // to adjust our location to the new file.
- MostRecentLocation = NewLoc;
- return;
- }
- ParentFile = SM.getFileID(LCA);
- }
-
- llvm::SmallSet<SourceLocation, 8> StartLocs;
- Optional<Counter> ParentCounter;
- for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
- if (!I.hasStartLoc())
- continue;
- SourceLocation Loc = I.getBeginLoc();
- if (!isNestedIn(Loc, ParentFile)) {
- ParentCounter = I.getCounter();
- break;
- }
-
- while (!SM.isInFileID(Loc, ParentFile)) {
- // The most nested region for each start location is the one with the
- // correct count. We avoid creating redundant regions by stopping once
- // we've seen this region.
- if (StartLocs.insert(Loc).second)
- SourceRegions.emplace_back(I.getCounter(), Loc,
- getEndOfFileOrMacro(Loc));
- Loc = getIncludeOrExpansionLoc(Loc);
- }
- I.setStartLoc(getPreciseTokenLocEnd(Loc));
- }
-
- if (ParentCounter) {
- // If the file is contained completely by another region and doesn't
- // immediately start its own region, the whole file gets a region
- // corresponding to the parent.
- SourceLocation Loc = MostRecentLocation;
- while (isNestedIn(Loc, ParentFile)) {
- SourceLocation FileStart = getStartOfFileOrMacro(Loc);
- if (StartLocs.insert(FileStart).second) {
- SourceRegions.emplace_back(*ParentCounter, FileStart,
- getEndOfFileOrMacro(Loc));
- assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
- }
- Loc = getIncludeOrExpansionLoc(Loc);
- }
- }
-
- MostRecentLocation = NewLoc;
- }
-
- /// Ensure that \c S is included in the current region.
- void extendRegion(const Stmt *S) {
- SourceMappingRegion &Region = getRegion();
- SourceLocation StartLoc = getStart(S);
-
- handleFileExit(StartLoc);
- if (!Region.hasStartLoc())
- Region.setStartLoc(StartLoc);
-
- completeDeferred(Region.getCounter(), StartLoc);
- }
-
- /// Mark \c S as a terminator, starting a zero region.
- void terminateRegion(const Stmt *S) {
- extendRegion(S);
- SourceMappingRegion &Region = getRegion();
- SourceLocation EndLoc = getEnd(S);
- if (!Region.hasEndLoc())
- Region.setEndLoc(EndLoc);
- pushRegion(Counter::getZero());
- auto &ZeroRegion = getRegion();
- ZeroRegion.setDeferred(true);
- LastTerminatedRegion = {EndLoc, RegionStack.size()};
- }
-
- /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
- Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
- SourceLocation BeforeLoc) {
- // If the start and end locations of the gap are both within the same macro
- // file, the range may not be in source order.
- if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
- return None;
- if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc))
- return None;
- return {{AfterLoc, BeforeLoc}};
- }
-
- /// Find the source range after \p AfterStmt and before \p BeforeStmt.
- Optional<SourceRange> findGapAreaBetween(const Stmt *AfterStmt,
- const Stmt *BeforeStmt) {
- return findGapAreaBetween(getPreciseTokenLocEnd(getEnd(AfterStmt)),
- getStart(BeforeStmt));
- }
-
- /// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
- void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
- Counter Count) {
- if (StartLoc == EndLoc)
- return;
- assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
- handleFileExit(StartLoc);
- size_t Index = pushRegion(Count, StartLoc, EndLoc);
- getRegion().setGap(true);
- handleFileExit(EndLoc);
- popRegions(Index);
- }
-
- /// Keep counts of breaks and continues inside loops.
- struct BreakContinue {
- Counter BreakCount;
- Counter ContinueCount;
- };
- SmallVector<BreakContinue, 8> BreakContinueStack;
-
- CounterCoverageMappingBuilder(
- CoverageMappingModuleGen &CVM,
- llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
- const LangOptions &LangOpts)
- : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
- DeferredRegion(None) {}
-
- /// Write the mapping data to the output stream
- void write(llvm::raw_ostream &OS) {
- llvm::SmallVector<unsigned, 8> VirtualFileMapping;
- gatherFileIDs(VirtualFileMapping);
- SourceRegionFilter Filter = emitExpansionRegions();
- assert(!DeferredRegion && "Deferred region never completed");
- emitSourceRegions(Filter);
- gatherSkippedRegions();
-
- if (MappingRegions.empty())
- return;
-
- CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
- MappingRegions);
- Writer.write(OS);
- }
-
- void VisitStmt(const Stmt *S) {
- if (S->getBeginLoc().isValid())
- extendRegion(S);
- for (const Stmt *Child : S->children())
- if (Child)
- this->Visit(Child);
- handleFileExit(getEnd(S));
- }
-
- void VisitDecl(const Decl *D) {
- assert(!DeferredRegion && "Deferred region never completed");
-
- Stmt *Body = D->getBody();
-
- // Do not propagate region counts into system headers.
- if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
- return;
-
- // Do not visit the artificial children nodes of defaulted methods. The
- // lexer may not be able to report back precise token end locations for
- // these children nodes (llvm.org/PR39822), and moreover users will not be
- // able to see coverage for them.
- bool Defaulted = false;
- if (auto *Method = dyn_cast<CXXMethodDecl>(D))
- Defaulted = Method->isDefaulted();
-
- propagateCounts(getRegionCounter(Body), Body,
- /*VisitChildren=*/!Defaulted);
- assert(RegionStack.empty() && "Regions entered but never exited");
-
- // Discard the last uncompleted deferred region in a decl, if one exists.
- // This prevents lines at the end of a function containing only whitespace
- // or closing braces from being marked as uncovered.
- DeferredRegion = None;
- }
-
- void VisitReturnStmt(const ReturnStmt *S) {
- extendRegion(S);
- if (S->getRetValue())
- Visit(S->getRetValue());
- terminateRegion(S);
- }
-
- void VisitCXXThrowExpr(const CXXThrowExpr *E) {
- extendRegion(E);
- if (E->getSubExpr())
- Visit(E->getSubExpr());
- terminateRegion(E);
- }
-
- void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
-
- void VisitLabelStmt(const LabelStmt *S) {
- Counter LabelCount = getRegionCounter(S);
- SourceLocation Start = getStart(S);
- completeTopLevelDeferredRegion(LabelCount, Start);
- completeDeferred(LabelCount, Start);
- // We can't extendRegion here or we risk overlapping with our new region.
- handleFileExit(Start);
- pushRegion(LabelCount, Start);
- Visit(S->getSubStmt());
- }
-
- void VisitBreakStmt(const BreakStmt *S) {
- assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
- BreakContinueStack.back().BreakCount = addCounters(
- BreakContinueStack.back().BreakCount, getRegion().getCounter());
- // FIXME: a break in a switch should terminate regions for all preceding
- // case statements, not just the most recent one.
- terminateRegion(S);
- }
-
- void VisitContinueStmt(const ContinueStmt *S) {
- assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
- BreakContinueStack.back().ContinueCount = addCounters(
- BreakContinueStack.back().ContinueCount, getRegion().getCounter());
- terminateRegion(S);
- }
-
- void VisitCallExpr(const CallExpr *E) {
- VisitStmt(E);
-
- // Terminate the region when we hit a noreturn function.
- // (This is helpful dealing with switch statements.)
- QualType CalleeType = E->getCallee()->getType();
- if (getFunctionExtInfo(*CalleeType).getNoReturn())
- terminateRegion(E);
- }
-
- void VisitWhileStmt(const WhileStmt *S) {
- extendRegion(S);
-
- Counter ParentCount = getRegion().getCounter();
- Counter BodyCount = getRegionCounter(S);
-
- // Handle the body first so that we can get the backedge count.
- BreakContinueStack.push_back(BreakContinue());
- extendRegion(S->getBody());
- Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- // Go back to handle the condition.
- Counter CondCount =
- addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
- propagateCounts(CondCount, S->getCond());
- adjustForOutOfOrderTraversal(getEnd(S));
-
- // The body count applies to the area immediately after the increment.
- auto Gap = findGapAreaBetween(S->getCond(), S->getBody());
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
-
- Counter OutCount =
- addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
- if (OutCount != ParentCount)
- pushRegion(OutCount);
- }
-
- void VisitDoStmt(const DoStmt *S) {
- extendRegion(S);
-
- Counter ParentCount = getRegion().getCounter();
- Counter BodyCount = getRegionCounter(S);
-
- BreakContinueStack.push_back(BreakContinue());
- extendRegion(S->getBody());
- Counter BackedgeCount =
- propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
- propagateCounts(CondCount, S->getCond());
-
- Counter OutCount =
- addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
- if (OutCount != ParentCount)
- pushRegion(OutCount);
- }
-
- void VisitForStmt(const ForStmt *S) {
- extendRegion(S);
- if (S->getInit())
- Visit(S->getInit());
-
- Counter ParentCount = getRegion().getCounter();
- Counter BodyCount = getRegionCounter(S);
-
- // The loop increment may contain a break or continue.
- if (S->getInc())
- BreakContinueStack.emplace_back();
-
- // Handle the body first so that we can get the backedge count.
- BreakContinueStack.emplace_back();
- extendRegion(S->getBody());
- Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
- BreakContinue BodyBC = BreakContinueStack.pop_back_val();
-
- // The increment is essentially part of the body but it needs to include
- // the count for all the continue statements.
- BreakContinue IncrementBC;
- if (const Stmt *Inc = S->getInc()) {
- propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
- IncrementBC = BreakContinueStack.pop_back_val();
- }
-
- // Go back to handle the condition.
- Counter CondCount = addCounters(
- addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
- IncrementBC.ContinueCount);
- if (const Expr *Cond = S->getCond()) {
- propagateCounts(CondCount, Cond);
- adjustForOutOfOrderTraversal(getEnd(S));
- }
-
- // The body count applies to the area immediately after the increment.
- auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()),
- getStart(S->getBody()));
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
-
- Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
- subtractCounters(CondCount, BodyCount));
- if (OutCount != ParentCount)
- pushRegion(OutCount);
- }
-
- void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
- extendRegion(S);
- if (S->getInit())
- Visit(S->getInit());
- Visit(S->getLoopVarStmt());
- Visit(S->getRangeStmt());
-
- Counter ParentCount = getRegion().getCounter();
- Counter BodyCount = getRegionCounter(S);
-
- BreakContinueStack.push_back(BreakContinue());
- extendRegion(S->getBody());
- Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- // The body count applies to the area immediately after the range.
- auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()),
- getStart(S->getBody()));
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
-
- Counter LoopCount =
- addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
- Counter OutCount =
- addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
- if (OutCount != ParentCount)
- pushRegion(OutCount);
- }
-
- void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
- extendRegion(S);
- Visit(S->getElement());
-
- Counter ParentCount = getRegion().getCounter();
- Counter BodyCount = getRegionCounter(S);
-
- BreakContinueStack.push_back(BreakContinue());
- extendRegion(S->getBody());
- Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- // The body count applies to the area immediately after the collection.
- auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()),
- getStart(S->getBody()));
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
-
- Counter LoopCount =
- addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
- Counter OutCount =
- addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
- if (OutCount != ParentCount)
- pushRegion(OutCount);
- }
-
- void VisitSwitchStmt(const SwitchStmt *S) {
- extendRegion(S);
- if (S->getInit())
- Visit(S->getInit());
- Visit(S->getCond());
-
- BreakContinueStack.push_back(BreakContinue());
-
- const Stmt *Body = S->getBody();
- extendRegion(Body);
- if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
- if (!CS->body_empty()) {
- // Make a region for the body of the switch. If the body starts with
- // a case, that case will reuse this region; otherwise, this covers
- // the unreachable code at the beginning of the switch body.
- size_t Index =
- pushRegion(Counter::getZero(), getStart(CS->body_front()));
- for (const auto *Child : CS->children())
- Visit(Child);
-
- // Set the end for the body of the switch, if it isn't already set.
- for (size_t i = RegionStack.size(); i != Index; --i) {
- if (!RegionStack[i - 1].hasEndLoc())
- RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
- }
-
- popRegions(Index);
- }
- } else
- propagateCounts(Counter::getZero(), Body);
- BreakContinue BC = BreakContinueStack.pop_back_val();
-
- if (!BreakContinueStack.empty())
- BreakContinueStack.back().ContinueCount = addCounters(
- BreakContinueStack.back().ContinueCount, BC.ContinueCount);
-
- Counter ExitCount = getRegionCounter(S);
- SourceLocation ExitLoc = getEnd(S);
- pushRegion(ExitCount);
-
- // Ensure that handleFileExit recognizes when the end location is located
- // in a different file.
- MostRecentLocation = getStart(S);
- handleFileExit(ExitLoc);
- }
-
- void VisitSwitchCase(const SwitchCase *S) {
- extendRegion(S);
-
- SourceMappingRegion &Parent = getRegion();
-
- Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
- // Reuse the existing region if it starts at our label. This is typical of
- // the first case in a switch.
- if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
- Parent.setCounter(Count);
- else
- pushRegion(Count, getStart(S));
-
- if (const auto *CS = dyn_cast<CaseStmt>(S)) {
- Visit(CS->getLHS());
- if (const Expr *RHS = CS->getRHS())
- Visit(RHS);
- }
- Visit(S->getSubStmt());
- }
-
- void VisitIfStmt(const IfStmt *S) {
- extendRegion(S);
- if (S->getInit())
- Visit(S->getInit());
-
- // Extend into the condition before we propagate through it below - this is
- // needed to handle macros that generate the "if" but not the condition.
- extendRegion(S->getCond());
-
- Counter ParentCount = getRegion().getCounter();
- Counter ThenCount = getRegionCounter(S);
-
- // Emitting a counter for the condition makes it easier to interpret the
- // counter for the body when looking at the coverage.
- propagateCounts(ParentCount, S->getCond());
-
- // The 'then' count applies to the area immediately after the condition.
- auto Gap = findGapAreaBetween(S->getCond(), S->getThen());
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
-
- extendRegion(S->getThen());
- Counter OutCount = propagateCounts(ThenCount, S->getThen());
-
- Counter ElseCount = subtractCounters(ParentCount, ThenCount);
- if (const Stmt *Else = S->getElse()) {
- // The 'else' count applies to the area immediately after the 'then'.
- Gap = findGapAreaBetween(S->getThen(), Else);
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
- extendRegion(Else);
- OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
- } else
- OutCount = addCounters(OutCount, ElseCount);
-
- if (OutCount != ParentCount)
- pushRegion(OutCount);
- }
-
- void VisitCXXTryStmt(const CXXTryStmt *S) {
- extendRegion(S);
- // Handle macros that generate the "try" but not the rest.
- extendRegion(S->getTryBlock());
-
- Counter ParentCount = getRegion().getCounter();
- propagateCounts(ParentCount, S->getTryBlock());
-
- for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
- Visit(S->getHandler(I));
-
- Counter ExitCount = getRegionCounter(S);
- pushRegion(ExitCount);
- }
-
- void VisitCXXCatchStmt(const CXXCatchStmt *S) {
- propagateCounts(getRegionCounter(S), S->getHandlerBlock());
- }
-
- void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
- extendRegion(E);
-
- Counter ParentCount = getRegion().getCounter();
- Counter TrueCount = getRegionCounter(E);
-
- Visit(E->getCond());
-
- if (!isa<BinaryConditionalOperator>(E)) {
- // The 'then' count applies to the area immediately after the condition.
- auto Gap =
- findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
-
- extendRegion(E->getTrueExpr());
- propagateCounts(TrueCount, E->getTrueExpr());
- }
-
- extendRegion(E->getFalseExpr());
- propagateCounts(subtractCounters(ParentCount, TrueCount),
- E->getFalseExpr());
- }
-
- void VisitBinLAnd(const BinaryOperator *E) {
- extendRegion(E->getLHS());
- propagateCounts(getRegion().getCounter(), E->getLHS());
- handleFileExit(getEnd(E->getLHS()));
-
- extendRegion(E->getRHS());
- propagateCounts(getRegionCounter(E), E->getRHS());
- }
-
- void VisitBinLOr(const BinaryOperator *E) {
- extendRegion(E->getLHS());
- propagateCounts(getRegion().getCounter(), E->getLHS());
- handleFileExit(getEnd(E->getLHS()));
-
- extendRegion(E->getRHS());
- propagateCounts(getRegionCounter(E), E->getRHS());
- }
-
- void VisitLambdaExpr(const LambdaExpr *LE) {
- // Lambdas are treated as their own functions for now, so we shouldn't
- // propagate counts into them.
- }
-};
-
-std::string getCoverageSection(const CodeGenModule &CGM) {
- return llvm::getInstrProfSectionName(
- llvm::IPSK_covmap,
- CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
-}
-
-std::string normalizeFilename(StringRef Filename) {
- llvm::SmallString<256> Path(Filename);
- llvm::sys::fs::make_absolute(Path);
- llvm::sys::path::remove_dots(Path, /*remove_dot_dots=*/true);
- return Path.str().str();
-}
-
-} // end anonymous namespace
-
-static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
- ArrayRef<CounterExpression> Expressions,
- ArrayRef<CounterMappingRegion> Regions) {
- OS << FunctionName << ":\n";
- CounterMappingContext Ctx(Expressions);
- for (const auto &R : Regions) {
- OS.indent(2);
- switch (R.Kind) {
- case CounterMappingRegion::CodeRegion:
- break;
- case CounterMappingRegion::ExpansionRegion:
- OS << "Expansion,";
- break;
- case CounterMappingRegion::SkippedRegion:
- OS << "Skipped,";
- break;
- case CounterMappingRegion::GapRegion:
- OS << "Gap,";
- break;
- }
-
- OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
- << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
- Ctx.dump(R.Count, OS);
- if (R.Kind == CounterMappingRegion::ExpansionRegion)
- OS << " (Expanded file = " << R.ExpandedFileID << ")";
- OS << "\n";
- }
-}
-
-void CoverageMappingModuleGen::addFunctionMappingRecord(
- llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
- const std::string &CoverageMapping, bool IsUsed) {
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
- if (!FunctionRecordTy) {
-#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
- llvm::Type *FunctionRecordTypes[] = {
- #include "llvm/ProfileData/InstrProfData.inc"
- };
- FunctionRecordTy =
- llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
- /*isPacked=*/true);
- }
-
- #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
- llvm::Constant *FunctionRecordVals[] = {
- #include "llvm/ProfileData/InstrProfData.inc"
- };
- FunctionRecords.push_back(llvm::ConstantStruct::get(
- FunctionRecordTy, makeArrayRef(FunctionRecordVals)));
- if (!IsUsed)
- FunctionNames.push_back(
- llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
- CoverageMappings.push_back(CoverageMapping);
-
- if (CGM.getCodeGenOpts().DumpCoverageMapping) {
- // Dump the coverage mapping data for this function by decoding the
- // encoded data. This allows us to dump the mapping regions which were
- // also processed by the CoverageMappingWriter which performs
- // additional minimization operations such as reducing the number of
- // expressions.
- std::vector<StringRef> Filenames;
- std::vector<CounterExpression> Expressions;
- std::vector<CounterMappingRegion> Regions;
- llvm::SmallVector<std::string, 16> FilenameStrs;
- llvm::SmallVector<StringRef, 16> FilenameRefs;
- FilenameStrs.resize(FileEntries.size());
- FilenameRefs.resize(FileEntries.size());
- for (const auto &Entry : FileEntries) {
- auto I = Entry.second;
- FilenameStrs[I] = normalizeFilename(Entry.first->getName());
- FilenameRefs[I] = FilenameStrs[I];
- }
- RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
- Expressions, Regions);
- if (Reader.read())
- return;
- dump(llvm::outs(), NameValue, Expressions, Regions);
- }
-}
-
-void CoverageMappingModuleGen::emit() {
- if (FunctionRecords.empty())
- return;
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
- auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
-
- // Create the filenames and merge them with coverage mappings
- llvm::SmallVector<std::string, 16> FilenameStrs;
- llvm::SmallVector<StringRef, 16> FilenameRefs;
- FilenameStrs.resize(FileEntries.size());
- FilenameRefs.resize(FileEntries.size());
- for (const auto &Entry : FileEntries) {
- auto I = Entry.second;
- FilenameStrs[I] = normalizeFilename(Entry.first->getName());
- FilenameRefs[I] = FilenameStrs[I];
- }
-
- std::string FilenamesAndCoverageMappings;
- llvm::raw_string_ostream OS(FilenamesAndCoverageMappings);
- CoverageFilenamesSectionWriter(FilenameRefs).write(OS);
- std::string RawCoverageMappings =
- llvm::join(CoverageMappings.begin(), CoverageMappings.end(), "");
- OS << RawCoverageMappings;
- size_t CoverageMappingSize = RawCoverageMappings.size();
- size_t FilenamesSize = OS.str().size() - CoverageMappingSize;
- // Append extra zeroes if necessary to ensure that the size of the filenames
- // and coverage mappings is a multiple of 8.
- if (size_t Rem = OS.str().size() % 8) {
- CoverageMappingSize += 8 - Rem;
- OS.write_zeros(8 - Rem);
- }
- auto *FilenamesAndMappingsVal =
- llvm::ConstantDataArray::getString(Ctx, OS.str(), false);
-
- // Create the deferred function records array
- auto RecordsTy =
- llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size());
- auto RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords);
-
- llvm::Type *CovDataHeaderTypes[] = {
-#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
-#include "llvm/ProfileData/InstrProfData.inc"
- };
- auto CovDataHeaderTy =
- llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
- llvm::Constant *CovDataHeaderVals[] = {
-#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
-#include "llvm/ProfileData/InstrProfData.inc"
- };
- auto CovDataHeaderVal = llvm::ConstantStruct::get(
- CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
-
- // Create the coverage data record
- llvm::Type *CovDataTypes[] = {CovDataHeaderTy, RecordsTy,
- FilenamesAndMappingsVal->getType()};
- auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
- llvm::Constant *TUDataVals[] = {CovDataHeaderVal, RecordsVal,
- FilenamesAndMappingsVal};
- auto CovDataVal =
- llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
- auto CovData = new llvm::GlobalVariable(
- CGM.getModule(), CovDataTy, true, llvm::GlobalValue::InternalLinkage,
- CovDataVal, llvm::getCoverageMappingVarName());
-
- CovData->setSection(getCoverageSection(CGM));
- CovData->setAlignment(8);
-
- // Make sure the data doesn't get deleted.
- CGM.addUsedGlobal(CovData);
- // Create the deferred function records array
- if (!FunctionNames.empty()) {
- auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
- FunctionNames.size());
- auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
- // This variable will *NOT* be emitted to the object file. It is used
- // to pass the list of names referenced to codegen.
- new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
- llvm::GlobalValue::InternalLinkage, NamesArrVal,
- llvm::getCoverageUnusedNamesVarName());
- }
-}
-
-unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
- auto It = FileEntries.find(File);
- if (It != FileEntries.end())
- return It->second;
- unsigned FileID = FileEntries.size();
- FileEntries.insert(std::make_pair(File, FileID));
- return FileID;
-}
-
-void CoverageMappingGen::emitCounterMapping(const Decl *D,
- llvm::raw_ostream &OS) {
- assert(CounterMap);
- CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
- Walker.VisitDecl(D);
- Walker.write(OS);
-}
-
-void CoverageMappingGen::emitEmptyMapping(const Decl *D,
- llvm::raw_ostream &OS) {
- EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
- Walker.VisitDecl(D);
- Walker.write(OS);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h b/gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h
deleted file mode 100644
index c62db096952..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h
+++ /dev/null
@@ -1,114 +0,0 @@
-//===---- CoverageMappingGen.h - Coverage mapping generation ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Instrumentation-based code coverage mapping generator
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_COVERAGEMAPPINGGEN_H
-#define LLVM_CLANG_LIB_CODEGEN_COVERAGEMAPPINGGEN_H
-
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Lex/PPCallbacks.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace clang {
-
-class LangOptions;
-class SourceManager;
-class FileEntry;
-class Preprocessor;
-class Decl;
-class Stmt;
-
-/// Stores additional source code information like skipped ranges which
-/// is required by the coverage mapping generator and is obtained from
-/// the preprocessor.
-class CoverageSourceInfo : public PPCallbacks {
- std::vector<SourceRange> SkippedRanges;
-public:
- ArrayRef<SourceRange> getSkippedRanges() const { return SkippedRanges; }
-
- void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override;
-};
-
-namespace CodeGen {
-
-class CodeGenModule;
-
-/// Organizes the cross-function state that is used while generating
-/// code coverage mapping data.
-class CoverageMappingModuleGen {
- CodeGenModule &CGM;
- CoverageSourceInfo &SourceInfo;
- llvm::SmallDenseMap<const FileEntry *, unsigned, 8> FileEntries;
- std::vector<llvm::Constant *> FunctionRecords;
- std::vector<llvm::Constant *> FunctionNames;
- llvm::StructType *FunctionRecordTy;
- std::vector<std::string> CoverageMappings;
-
-public:
- CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
- : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {}
-
- CoverageSourceInfo &getSourceInfo() const {
- return SourceInfo;
- }
-
- /// Add a function's coverage mapping record to the collection of the
- /// function mapping records.
- void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName,
- StringRef FunctionNameValue,
- uint64_t FunctionHash,
- const std::string &CoverageMapping,
- bool IsUsed = true);
-
- /// Emit the coverage mapping data for a translation unit.
- void emit();
-
- /// Return the coverage mapping translation unit file id
- /// for the given file.
- unsigned getFileID(const FileEntry *File);
-};
-
-/// Organizes the per-function state that is used while generating
-/// code coverage mapping data.
-class CoverageMappingGen {
- CoverageMappingModuleGen &CVM;
- SourceManager &SM;
- const LangOptions &LangOpts;
- llvm::DenseMap<const Stmt *, unsigned> *CounterMap;
-
-public:
- CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM,
- const LangOptions &LangOpts)
- : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(nullptr) {}
-
- CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM,
- const LangOptions &LangOpts,
- llvm::DenseMap<const Stmt *, unsigned> *CounterMap)
- : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(CounterMap) {}
-
- /// Emit the coverage mapping data which maps the regions of
- /// code to counters that will be used to find the execution
- /// counts for those regions.
- void emitCounterMapping(const Decl *D, llvm::raw_ostream &OS);
-
- /// Emit the coverage mapping data for an unused function.
- /// It creates mapping regions with the counter of zero.
- void emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS);
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/EHScopeStack.h b/gnu/llvm/tools/clang/lib/CodeGen/EHScopeStack.h
deleted file mode 100644
index c7bdeac58a1..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/EHScopeStack.h
+++ /dev/null
@@ -1,421 +0,0 @@
-//===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes should be the minimum interface required for other parts of
-// CodeGen to emit cleanups. The implementation is in CGCleanup.cpp and other
-// implemenentation details that are not widely needed are in CGCleanup.h.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
-#define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Value.h"
-
-namespace clang {
-namespace CodeGen {
-
-class CodeGenFunction;
-
-/// A branch fixup. These are required when emitting a goto to a
-/// label which hasn't been emitted yet. The goto is optimistically
-/// emitted as a branch to the basic block for the label, and (if it
-/// occurs in a scope with non-trivial cleanups) a fixup is added to
-/// the innermost cleanup. When a (normal) cleanup is popped, any
-/// unresolved fixups in that scope are threaded through the cleanup.
-struct BranchFixup {
- /// The block containing the terminator which needs to be modified
- /// into a switch if this fixup is resolved into the current scope.
- /// If null, LatestBranch points directly to the destination.
- llvm::BasicBlock *OptimisticBranchBlock;
-
- /// The ultimate destination of the branch.
- ///
- /// This can be set to null to indicate that this fixup was
- /// successfully resolved.
- llvm::BasicBlock *Destination;
-
- /// The destination index value.
- unsigned DestinationIndex;
-
- /// The initial branch of the fixup.
- llvm::BranchInst *InitialBranch;
-};
-
-template <class T> struct InvariantValue {
- typedef T type;
- typedef T saved_type;
- static bool needsSaving(type value) { return false; }
- static saved_type save(CodeGenFunction &CGF, type value) { return value; }
- static type restore(CodeGenFunction &CGF, saved_type value) { return value; }
-};
-
-/// A metaprogramming class for ensuring that a value will dominate an
-/// arbitrary position in a function.
-template <class T> struct DominatingValue : InvariantValue<T> {};
-
-template <class T, bool mightBeInstruction =
- std::is_base_of<llvm::Value, T>::value &&
- !std::is_base_of<llvm::Constant, T>::value &&
- !std::is_base_of<llvm::BasicBlock, T>::value>
-struct DominatingPointer;
-template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {};
-// template <class T> struct DominatingPointer<T,true> at end of file
-
-template <class T> struct DominatingValue<T*> : DominatingPointer<T> {};
-
-enum CleanupKind : unsigned {
- /// Denotes a cleanup that should run when a scope is exited using exceptional
- /// control flow (a throw statement leading to stack unwinding, ).
- EHCleanup = 0x1,
-
- /// Denotes a cleanup that should run when a scope is exited using normal
- /// control flow (falling off the end of the scope, return, goto, ...).
- NormalCleanup = 0x2,
-
- NormalAndEHCleanup = EHCleanup | NormalCleanup,
-
- InactiveCleanup = 0x4,
- InactiveEHCleanup = EHCleanup | InactiveCleanup,
- InactiveNormalCleanup = NormalCleanup | InactiveCleanup,
- InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup,
-
- LifetimeMarker = 0x8,
- NormalEHLifetimeMarker = LifetimeMarker | NormalAndEHCleanup,
-};
-
-/// A stack of scopes which respond to exceptions, including cleanups
-/// and catch blocks.
-class EHScopeStack {
-public:
- /* Should switch to alignof(uint64_t) instead of 8, when EHCleanupScope can */
- enum { ScopeStackAlignment = 8 };
-
- /// A saved depth on the scope stack. This is necessary because
- /// pushing scopes onto the stack invalidates iterators.
- class stable_iterator {
- friend class EHScopeStack;
-
- /// Offset from StartOfData to EndOfBuffer.
- ptrdiff_t Size;
-
- stable_iterator(ptrdiff_t Size) : Size(Size) {}
-
- public:
- static stable_iterator invalid() { return stable_iterator(-1); }
- stable_iterator() : Size(-1) {}
-
- bool isValid() const { return Size >= 0; }
-
- /// Returns true if this scope encloses I.
- /// Returns false if I is invalid.
- /// This scope must be valid.
- bool encloses(stable_iterator I) const { return Size <= I.Size; }
-
- /// Returns true if this scope strictly encloses I: that is,
- /// if it encloses I and is not I.
- /// Returns false is I is invalid.
- /// This scope must be valid.
- bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; }
-
- friend bool operator==(stable_iterator A, stable_iterator B) {
- return A.Size == B.Size;
- }
- friend bool operator!=(stable_iterator A, stable_iterator B) {
- return A.Size != B.Size;
- }
- };
-
- /// Information for lazily generating a cleanup. Subclasses must be
- /// POD-like: cleanups will not be destructed, and they will be
- /// allocated on the cleanup stack and freely copied and moved
- /// around.
- ///
- /// Cleanup implementations should generally be declared in an
- /// anonymous namespace.
- class Cleanup {
- // Anchor the construction vtable.
- virtual void anchor();
-
- protected:
- ~Cleanup() = default;
-
- public:
- Cleanup(const Cleanup &) = default;
- Cleanup(Cleanup &&) {}
- Cleanup() = default;
-
- /// Generation flags.
- class Flags {
- enum {
- F_IsForEH = 0x1,
- F_IsNormalCleanupKind = 0x2,
- F_IsEHCleanupKind = 0x4
- };
- unsigned flags;
-
- public:
- Flags() : flags(0) {}
-
- /// isForEH - true if the current emission is for an EH cleanup.
- bool isForEHCleanup() const { return flags & F_IsForEH; }
- bool isForNormalCleanup() const { return !isForEHCleanup(); }
- void setIsForEHCleanup() { flags |= F_IsForEH; }
-
- bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; }
- void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; }
-
- /// isEHCleanupKind - true if the cleanup was pushed as an EH
- /// cleanup.
- bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; }
- void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; }
- };
-
-
- /// Emit the cleanup. For normal cleanups, this is run in the
- /// same EH context as when the cleanup was pushed, i.e. the
- /// immediately-enclosing context of the cleanup scope. For
- /// EH cleanups, this is run in a terminate context.
- ///
- // \param flags cleanup kind.
- virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
- };
-
- /// ConditionalCleanup stores the saved form of its parameters,
- /// then restores them and performs the cleanup.
- template <class T, class... As>
- class ConditionalCleanup final : public Cleanup {
- typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
- SavedTuple Saved;
-
- template <std::size_t... Is>
- T restore(CodeGenFunction &CGF, llvm::index_sequence<Is...>) {
- // It's important that the restores are emitted in order. The braced init
- // list guarantees that.
- return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...};
- }
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- restore(CGF, llvm::index_sequence_for<As...>()).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup(typename DominatingValue<As>::saved_type... A)
- : Saved(A...) {}
-
- ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {}
- };
-
-private:
- // The implementation for this class is in CGException.h and
- // CGException.cpp; the definition is here because it's used as a
- // member of CodeGenFunction.
-
- /// The start of the scope-stack buffer, i.e. the allocated pointer
- /// for the buffer. All of these pointers are either simultaneously
- /// null or simultaneously valid.
- char *StartOfBuffer;
-
- /// The end of the buffer.
- char *EndOfBuffer;
-
- /// The first valid entry in the buffer.
- char *StartOfData;
-
- /// The innermost normal cleanup on the stack.
- stable_iterator InnermostNormalCleanup;
-
- /// The innermost EH scope on the stack.
- stable_iterator InnermostEHScope;
-
- /// The current set of branch fixups. A branch fixup is a jump to
- /// an as-yet unemitted label, i.e. a label for which we don't yet
- /// know the EH stack depth. Whenever we pop a cleanup, we have
- /// to thread all the current branch fixups through it.
- ///
- /// Fixups are recorded as the Use of the respective branch or
- /// switch statement. The use points to the final destination.
- /// When popping out of a cleanup, these uses are threaded through
- /// the cleanup and adjusted to point to the new cleanup.
- ///
- /// Note that branches are allowed to jump into protected scopes
- /// in certain situations; e.g. the following code is legal:
- /// struct A { ~A(); }; // trivial ctor, non-trivial dtor
- /// goto foo;
- /// A a;
- /// foo:
- /// bar();
- SmallVector<BranchFixup, 8> BranchFixups;
-
- char *allocate(size_t Size);
- void deallocate(size_t Size);
-
- void *pushCleanup(CleanupKind K, size_t DataSize);
-
-public:
- EHScopeStack() : StartOfBuffer(nullptr), EndOfBuffer(nullptr),
- StartOfData(nullptr), InnermostNormalCleanup(stable_end()),
- InnermostEHScope(stable_end()) {}
- ~EHScopeStack() { delete[] StartOfBuffer; }
-
- /// Push a lazily-created cleanup on the stack.
- template <class T, class... As> void pushCleanup(CleanupKind Kind, As... A) {
- static_assert(alignof(T) <= ScopeStackAlignment,
- "Cleanup's alignment is too large.");
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new (Buffer) T(A...);
- (void) Obj;
- }
-
- /// Push a lazily-created cleanup on the stack. Tuple version.
- template <class T, class... As>
- void pushCleanupTuple(CleanupKind Kind, std::tuple<As...> A) {
- static_assert(alignof(T) <= ScopeStackAlignment,
- "Cleanup's alignment is too large.");
- void *Buffer = pushCleanup(Kind, sizeof(T));
- Cleanup *Obj = new (Buffer) T(std::move(A));
- (void) Obj;
- }
-
- // Feel free to add more variants of the following:
-
- /// Push a cleanup with non-constant storage requirements on the
- /// stack. The cleanup type must provide an additional static method:
- /// static size_t getExtraSize(size_t);
- /// The argument to this method will be the value N, which will also
- /// be passed as the first argument to the constructor.
- ///
- /// The data stored in the extra storage must obey the same
- /// restrictions as normal cleanup member data.
- ///
- /// The pointer returned from this method is valid until the cleanup
- /// stack is modified.
- template <class T, class... As>
- T *pushCleanupWithExtra(CleanupKind Kind, size_t N, As... A) {
- static_assert(alignof(T) <= ScopeStackAlignment,
- "Cleanup's alignment is too large.");
- void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N));
- return new (Buffer) T(N, A...);
- }
-
- void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) {
- void *Buffer = pushCleanup(Kind, Size);
- std::memcpy(Buffer, Cleanup, Size);
- }
-
- /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp.
- void popCleanup();
-
- /// Push a set of catch handlers on the stack. The catch is
- /// uninitialized and will need to have the given number of handlers
- /// set on it.
- class EHCatchScope *pushCatch(unsigned NumHandlers);
-
- /// Pops a catch scope off the stack. This is private to CGException.cpp.
- void popCatch();
-
- /// Push an exceptions filter on the stack.
- class EHFilterScope *pushFilter(unsigned NumFilters);
-
- /// Pops an exceptions filter off the stack.
- void popFilter();
-
- /// Push a terminate handler on the stack.
- void pushTerminate();
-
- /// Pops a terminate handler off the stack.
- void popTerminate();
-
- // Returns true iff the current scope is either empty or contains only
- // lifetime markers, i.e. no real cleanup code
- bool containsOnlyLifetimeMarkers(stable_iterator Old) const;
-
- /// Determines whether the exception-scopes stack is empty.
- bool empty() const { return StartOfData == EndOfBuffer; }
-
- bool requiresLandingPad() const;
-
- /// Determines whether there are any normal cleanups on the stack.
- bool hasNormalCleanups() const {
- return InnermostNormalCleanup != stable_end();
- }
-
- /// Returns the innermost normal cleanup on the stack, or
- /// stable_end() if there are no normal cleanups.
- stable_iterator getInnermostNormalCleanup() const {
- return InnermostNormalCleanup;
- }
- stable_iterator getInnermostActiveNormalCleanup() const;
-
- stable_iterator getInnermostEHScope() const {
- return InnermostEHScope;
- }
-
-
- /// An unstable reference to a scope-stack depth. Invalidated by
- /// pushes but not pops.
- class iterator;
-
- /// Returns an iterator pointing to the innermost EH scope.
- iterator begin() const;
-
- /// Returns an iterator pointing to the outermost EH scope.
- iterator end() const;
-
- /// Create a stable reference to the top of the EH stack. The
- /// returned reference is valid until that scope is popped off the
- /// stack.
- stable_iterator stable_begin() const {
- return stable_iterator(EndOfBuffer - StartOfData);
- }
-
- /// Create a stable reference to the bottom of the EH stack.
- static stable_iterator stable_end() {
- return stable_iterator(0);
- }
-
- /// Translates an iterator into a stable_iterator.
- stable_iterator stabilize(iterator it) const;
-
- /// Turn a stable reference to a scope depth into a unstable pointer
- /// to the EH stack.
- iterator find(stable_iterator save) const;
-
- /// Add a branch fixup to the current cleanup scope.
- BranchFixup &addBranchFixup() {
- assert(hasNormalCleanups() && "adding fixup in scope without cleanups");
- BranchFixups.push_back(BranchFixup());
- return BranchFixups.back();
- }
-
- unsigned getNumBranchFixups() const { return BranchFixups.size(); }
- BranchFixup &getBranchFixup(unsigned I) {
- assert(I < getNumBranchFixups());
- return BranchFixups[I];
- }
-
- /// Pops lazily-removed fixups from the end of the list. This
- /// should only be called by procedures which have just popped a
- /// cleanup or resolved one or more fixups.
- void popNullFixups();
-
- /// Clears the branch-fixups list. This should only be called by
- /// ResolveAllBranchFixups.
- void clearFixups() { BranchFixups.clear(); }
-};
-
-} // namespace CodeGen
-} // namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/gnu/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
deleted file mode 100644
index c56875a0368..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ /dev/null
@@ -1,4281 +0,0 @@
-//===------- ItaniumCXXABI.cpp - Emit LLVM Code from ASTs for a Module ----===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides C++ code generation targeting the Itanium C++ ABI. The class
-// in this file generates structures that follow the Itanium C++ ABI, which is
-// documented at:
-// http://www.codesourcery.com/public/cxx-abi/abi.html
-// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
-//
-// It also supports the closely-related ARM ABI, documented at:
-// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-#include "CGRecordLayout.h"
-#include "CGVTables.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "clang/AST/Mangle.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/StmtCXX.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Value.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-class ItaniumCXXABI : public CodeGen::CGCXXABI {
- /// VTables - All the vtables which have been defined.
- llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
-
-protected:
- bool UseARMMethodPtrABI;
- bool UseARMGuardVarABI;
- bool Use32BitVTableOffsetABI;
-
- ItaniumMangleContext &getMangleContext() {
- return cast<ItaniumMangleContext>(CodeGen::CGCXXABI::getMangleContext());
- }
-
-public:
- ItaniumCXXABI(CodeGen::CodeGenModule &CGM,
- bool UseARMMethodPtrABI = false,
- bool UseARMGuardVarABI = false) :
- CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI),
- UseARMGuardVarABI(UseARMGuardVarABI),
- Use32BitVTableOffsetABI(false) { }
-
- bool classifyReturnType(CGFunctionInfo &FI) const override;
-
- bool passClassIndirect(const CXXRecordDecl *RD) const {
- return !canCopyArgument(RD);
- }
-
- RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
- // If C++ prohibits us from making a copy, pass by address.
- if (passClassIndirect(RD))
- return RAA_Indirect;
- return RAA_Default;
- }
-
- bool isThisCompleteObject(GlobalDecl GD) const override {
- // The Itanium ABI has separate complete-object vs. base-object
- // variants of both constructors and destructors.
- if (isa<CXXDestructorDecl>(GD.getDecl())) {
- switch (GD.getDtorType()) {
- case Dtor_Complete:
- case Dtor_Deleting:
- return true;
-
- case Dtor_Base:
- return false;
-
- case Dtor_Comdat:
- llvm_unreachable("emitting dtor comdat as function?");
- }
- llvm_unreachable("bad dtor kind");
- }
- if (isa<CXXConstructorDecl>(GD.getDecl())) {
- switch (GD.getCtorType()) {
- case Ctor_Complete:
- return true;
-
- case Ctor_Base:
- return false;
-
- case Ctor_CopyingClosure:
- case Ctor_DefaultClosure:
- llvm_unreachable("closure ctors in Itanium ABI?");
-
- case Ctor_Comdat:
- llvm_unreachable("emitting ctor comdat as function?");
- }
- llvm_unreachable("bad dtor kind");
- }
-
- // No other kinds.
- return false;
- }
-
- bool isZeroInitializable(const MemberPointerType *MPT) override;
-
- llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
-
- CGCallee
- EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
- const Expr *E,
- Address This,
- llvm::Value *&ThisPtrForCall,
- llvm::Value *MemFnPtr,
- const MemberPointerType *MPT) override;
-
- llvm::Value *
- EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
- Address Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) override;
-
- llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
- const CastExpr *E,
- llvm::Value *Src) override;
- llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *Src) override;
-
- llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT) override;
-
- llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD) override;
- llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset) override;
- llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT) override;
- llvm::Constant *BuildMemberPointer(const CXXMethodDecl *MD,
- CharUnits ThisAdjustment);
-
- llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L, llvm::Value *R,
- const MemberPointerType *MPT,
- bool Inequality) override;
-
- llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *Addr,
- const MemberPointerType *MPT) override;
-
- void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE,
- Address Ptr, QualType ElementType,
- const CXXDestructorDecl *Dtor) override;
-
- /// Itanium says that an _Unwind_Exception has to be "double-word"
- /// aligned (and thus the end of it is also so-aligned), meaning 16
- /// bytes. Of course, that was written for the actual Itanium,
- /// which is a 64-bit platform. Classically, the ABI doesn't really
- /// specify the alignment on other platforms, but in practice
- /// libUnwind declares the struct with __attribute__((aligned)), so
- /// we assume that alignment here. (It's generally 16 bytes, but
- /// some targets overwrite it.)
- CharUnits getAlignmentOfExnObject() {
- auto align = CGM.getContext().getTargetDefaultAlignForAttributeAligned();
- return CGM.getContext().toCharUnitsFromBits(align);
- }
-
- void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
- void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override;
-
- void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override;
-
- llvm::CallInst *
- emitTerminateForUnexpectedException(CodeGenFunction &CGF,
- llvm::Value *Exn) override;
-
- void EmitFundamentalRTTIDescriptors(const CXXRecordDecl *RD);
- llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
- CatchTypeInfo
- getAddrOfCXXCatchHandlerType(QualType Ty,
- QualType CatchHandlerType) override {
- return CatchTypeInfo{getAddrOfRTTIDescriptor(Ty), 0};
- }
-
- bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
- void EmitBadTypeidCall(CodeGenFunction &CGF) override;
- llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
- Address ThisPtr,
- llvm::Type *StdTypeInfoPtrTy) override;
-
- bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
- QualType SrcRecordTy) override;
-
- llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy, QualType DestTy,
- QualType DestRecordTy,
- llvm::BasicBlock *CastEnd) override;
-
- llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy,
- QualType DestTy) override;
-
- bool EmitBadCastCall(CodeGenFunction &CGF) override;
-
- llvm::Value *
- GetVirtualBaseClassOffset(CodeGenFunction &CGF, Address This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) override;
-
- void EmitCXXConstructors(const CXXConstructorDecl *D) override;
-
- AddedStructorArgs
- buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) override;
-
- bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const override {
- // Itanium does not emit any destructor variant as an inline thunk.
- // Delegating may occur as an optimization, but all variants are either
- // emitted with external linkage or as linkonce if they are inline and used.
- return false;
- }
-
- void EmitCXXDestructors(const CXXDestructorDecl *D) override;
-
- void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy,
- FunctionArgList &Params) override;
-
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
-
- AddedStructorArgs
- addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating, CallArgList &Args) override;
-
- void EmitDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *DD,
- CXXDtorType Type, bool ForVirtualBase,
- bool Delegating, Address This) override;
-
- void emitVTableDefinitions(CodeGenVTables &CGVT,
- const CXXRecordDecl *RD) override;
-
- bool isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF,
- CodeGenFunction::VPtr Vptr) override;
-
- bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) override {
- return true;
- }
-
- llvm::Constant *
- getVTableAddressPoint(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) override;
-
- llvm::Value *getVTableAddressPointInStructor(
- CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
- BaseSubobject Base, const CXXRecordDecl *NearestVBase) override;
-
- llvm::Value *getVTableAddressPointInStructorWithVTT(
- CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
- BaseSubobject Base, const CXXRecordDecl *NearestVBase);
-
- llvm::Constant *
- getVTableAddressPointForConstExpr(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) override;
-
- llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
- CharUnits VPtrOffset) override;
-
- CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
- Address This, llvm::Type *Ty,
- SourceLocation Loc) override;
-
- llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- Address This,
- const CXXMemberCallExpr *CE) override;
-
- void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
-
- bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override;
- bool canSpeculativelyEmitVTableAsBaseClass(const CXXRecordDecl *RD) const;
-
- void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD,
- bool ReturnAdjustment) override {
- // Allow inlining of thunks by emitting them with available_externally
- // linkage together with vtables when needed.
- if (ForVTable && !Thunk->hasLocalLinkage())
- Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
- CGM.setGVProperties(Thunk, GD);
- }
-
- bool exportThunk() override { return true; }
-
- llvm::Value *performThisAdjustment(CodeGenFunction &CGF, Address This,
- const ThisAdjustment &TA) override;
-
- llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, Address Ret,
- const ReturnAdjustment &RA) override;
-
- size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
- FunctionArgList &Args) const override {
- assert(!Args.empty() && "expected the arglist to not be empty!");
- return Args.size() - 1;
- }
-
- StringRef GetPureVirtualCallName() override { return "__cxa_pure_virtual"; }
- StringRef GetDeletedVirtualCallName() override
- { return "__cxa_deleted_virtual"; }
-
- CharUnits getArrayCookieSizeImpl(QualType elementType) override;
- Address InitializeArrayCookie(CodeGenFunction &CGF,
- Address NewPtr,
- llvm::Value *NumElements,
- const CXXNewExpr *expr,
- QualType ElementType) override;
- llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
- Address allocPtr,
- CharUnits cookieSize) override;
-
- void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr,
- bool PerformInit) override;
- void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *dtor, llvm::Constant *addr) override;
-
- llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD,
- llvm::Value *Val);
- void EmitThreadLocalInitFuncs(
- CodeGenModule &CGM,
- ArrayRef<const VarDecl *> CXXThreadLocals,
- ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
-
- bool usesThreadWrapperFunction() const override { return true; }
- LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
- QualType LValType) override;
-
- bool NeedsVTTParameter(GlobalDecl GD) override;
-
- /**************************** RTTI Uniqueness ******************************/
-
-protected:
- /// Returns true if the ABI requires RTTI type_info objects to be unique
- /// across a program.
- virtual bool shouldRTTIBeUnique() const { return true; }
-
-public:
- /// What sort of unique-RTTI behavior should we use?
- enum RTTIUniquenessKind {
- /// We are guaranteeing, or need to guarantee, that the RTTI string
- /// is unique.
- RUK_Unique,
-
- /// We are not guaranteeing uniqueness for the RTTI string, so we
- /// can demote to hidden visibility but must use string comparisons.
- RUK_NonUniqueHidden,
-
- /// We are not guaranteeing uniqueness for the RTTI string, so we
- /// have to use string comparisons, but we also have to emit it with
- /// non-hidden visibility.
- RUK_NonUniqueVisible
- };
-
- /// Return the required visibility status for the given type and linkage in
- /// the current ABI.
- RTTIUniquenessKind
- classifyRTTIUniqueness(QualType CanTy,
- llvm::GlobalValue::LinkageTypes Linkage) const;
- friend class ItaniumRTTIBuilder;
-
- void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
-
- std::pair<llvm::Value *, const CXXRecordDecl *>
- LoadVTablePtr(CodeGenFunction &CGF, Address This,
- const CXXRecordDecl *RD) override;
-
- private:
- bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const {
- const auto &VtableLayout =
- CGM.getItaniumVTableContext().getVTableLayout(RD);
-
- for (const auto &VtableComponent : VtableLayout.vtable_components()) {
- // Skip empty slot.
- if (!VtableComponent.isUsedFunctionPointerKind())
- continue;
-
- const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
- if (!Method->getCanonicalDecl()->isInlined())
- continue;
-
- StringRef Name = CGM.getMangledName(VtableComponent.getGlobalDecl());
- auto *Entry = CGM.GetGlobalValue(Name);
- // This checks if virtual inline function has already been emitted.
- // Note that it is possible that this inline function would be emitted
- // after trying to emit vtable speculatively. Because of this we do
- // an extra pass after emitting all deferred vtables to find and emit
- // these vtables opportunistically.
- if (!Entry || Entry->isDeclaration())
- return true;
- }
- return false;
- }
-
- bool isVTableHidden(const CXXRecordDecl *RD) const {
- const auto &VtableLayout =
- CGM.getItaniumVTableContext().getVTableLayout(RD);
-
- for (const auto &VtableComponent : VtableLayout.vtable_components()) {
- if (VtableComponent.isRTTIKind()) {
- const CXXRecordDecl *RTTIDecl = VtableComponent.getRTTIDecl();
- if (RTTIDecl->getVisibility() == Visibility::HiddenVisibility)
- return true;
- } else if (VtableComponent.isUsedFunctionPointerKind()) {
- const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
- if (Method->getVisibility() == Visibility::HiddenVisibility &&
- !Method->isDefined())
- return true;
- }
- }
- return false;
- }
-};
-
-class ARMCXXABI : public ItaniumCXXABI {
-public:
- ARMCXXABI(CodeGen::CodeGenModule &CGM) :
- ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
- /* UseARMGuardVarABI = */ true) {}
-
- bool HasThisReturn(GlobalDecl GD) const override {
- return (isa<CXXConstructorDecl>(GD.getDecl()) || (
- isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() != Dtor_Deleting));
- }
-
- void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV,
- QualType ResTy) override;
-
- CharUnits getArrayCookieSizeImpl(QualType elementType) override;
- Address InitializeArrayCookie(CodeGenFunction &CGF,
- Address NewPtr,
- llvm::Value *NumElements,
- const CXXNewExpr *expr,
- QualType ElementType) override;
- llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, Address allocPtr,
- CharUnits cookieSize) override;
-};
-
-class iOS64CXXABI : public ARMCXXABI {
-public:
- iOS64CXXABI(CodeGen::CodeGenModule &CGM) : ARMCXXABI(CGM) {
- Use32BitVTableOffsetABI = true;
- }
-
- // ARM64 libraries are prepared for non-unique RTTI.
- bool shouldRTTIBeUnique() const override { return false; }
-};
-
-class WebAssemblyCXXABI final : public ItaniumCXXABI {
-public:
- explicit WebAssemblyCXXABI(CodeGen::CodeGenModule &CGM)
- : ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true,
- /*UseARMGuardVarABI=*/true) {}
- void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override;
-
-private:
- bool HasThisReturn(GlobalDecl GD) const override {
- return isa<CXXConstructorDecl>(GD.getDecl()) ||
- (isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() != Dtor_Deleting);
- }
- bool canCallMismatchedFunctionType() const override { return false; }
-};
-}
-
-CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
- switch (CGM.getTarget().getCXXABI().getKind()) {
- // For IR-generation purposes, there's no significant difference
- // between the ARM and iOS ABIs.
- case TargetCXXABI::GenericARM:
- case TargetCXXABI::iOS:
- case TargetCXXABI::WatchOS:
- return new ARMCXXABI(CGM);
-
- case TargetCXXABI::iOS64:
- return new iOS64CXXABI(CGM);
-
- // Note that AArch64 uses the generic ItaniumCXXABI class since it doesn't
- // include the other 32-bit ARM oddities: constructor/destructor return values
- // and array cookies.
- case TargetCXXABI::GenericAArch64:
- return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
- /* UseARMGuardVarABI = */ true);
-
- case TargetCXXABI::GenericMIPS:
- return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true);
-
- case TargetCXXABI::WebAssembly:
- return new WebAssemblyCXXABI(CGM);
-
- case TargetCXXABI::GenericItanium:
- if (CGM.getContext().getTargetInfo().getTriple().getArch()
- == llvm::Triple::le32) {
- // For PNaCl, use ARM-style method pointers so that PNaCl code
- // does not assume anything about the alignment of function
- // pointers.
- return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
- /* UseARMGuardVarABI = */ false);
- }
- return new ItaniumCXXABI(CGM);
-
- case TargetCXXABI::Microsoft:
- llvm_unreachable("Microsoft ABI is not Itanium-based");
- }
- llvm_unreachable("bad ABI kind");
-}
-
-llvm::Type *
-ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
- if (MPT->isMemberDataPointer())
- return CGM.PtrDiffTy;
- return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy);
-}
-
-/// In the Itanium and ARM ABIs, method pointers have the form:
-/// struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr;
-///
-/// In the Itanium ABI:
-/// - method pointers are virtual if (memptr.ptr & 1) is nonzero
-/// - the this-adjustment is (memptr.adj)
-/// - the virtual offset is (memptr.ptr - 1)
-///
-/// In the ARM ABI:
-/// - method pointers are virtual if (memptr.adj & 1) is nonzero
-/// - the this-adjustment is (memptr.adj >> 1)
-/// - the virtual offset is (memptr.ptr)
-/// ARM uses 'adj' for the virtual flag because Thumb functions
-/// may be only single-byte aligned.
-///
-/// If the member is virtual, the adjusted 'this' pointer points
-/// to a vtable pointer from which the virtual offset is applied.
-///
-/// If the member is non-virtual, memptr.ptr is the address of
-/// the function to call.
-CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
- CodeGenFunction &CGF, const Expr *E, Address ThisAddr,
- llvm::Value *&ThisPtrForCall,
- llvm::Value *MemFnPtr, const MemberPointerType *MPT) {
- CGBuilderTy &Builder = CGF.Builder;
-
- const FunctionProtoType *FPT =
- MPT->getPointeeType()->getAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
-
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
- CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
-
- llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);
-
- llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual");
- llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual");
- llvm::BasicBlock *FnEnd = CGF.createBasicBlock("memptr.end");
-
- // Extract memptr.adj, which is in the second field.
- llvm::Value *RawAdj = Builder.CreateExtractValue(MemFnPtr, 1, "memptr.adj");
-
- // Compute the true adjustment.
- llvm::Value *Adj = RawAdj;
- if (UseARMMethodPtrABI)
- Adj = Builder.CreateAShr(Adj, ptrdiff_1, "memptr.adj.shifted");
-
- // Apply the adjustment and cast back to the original struct type
- // for consistency.
- llvm::Value *This = ThisAddr.getPointer();
- llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy());
- Ptr = Builder.CreateInBoundsGEP(Ptr, Adj);
- This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted");
- ThisPtrForCall = This;
-
- // Load the function pointer.
- llvm::Value *FnAsInt = Builder.CreateExtractValue(MemFnPtr, 0, "memptr.ptr");
-
- // If the LSB in the function pointer is 1, the function pointer points to
- // a virtual function.
- llvm::Value *IsVirtual;
- if (UseARMMethodPtrABI)
- IsVirtual = Builder.CreateAnd(RawAdj, ptrdiff_1);
- else
- IsVirtual = Builder.CreateAnd(FnAsInt, ptrdiff_1);
- IsVirtual = Builder.CreateIsNotNull(IsVirtual, "memptr.isvirtual");
- Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
-
- // In the virtual path, the adjustment left 'This' pointing to the
- // vtable of the correct base subobject. The "function pointer" is an
- // offset within the vtable (+1 for the virtual flag on non-ARM).
- CGF.EmitBlock(FnVirtual);
-
- // Cast the adjusted this to a pointer to vtable pointer and load.
- llvm::Type *VTableTy = Builder.getInt8PtrTy();
- CharUnits VTablePtrAlign =
- CGF.CGM.getDynamicOffsetAlignment(ThisAddr.getAlignment(), RD,
- CGF.getPointerAlign());
- llvm::Value *VTable =
- CGF.GetVTablePtr(Address(This, VTablePtrAlign), VTableTy, RD);
-
- // Apply the offset.
- // On ARM64, to reserve extra space in virtual member function pointers,
- // we only pay attention to the low 32 bits of the offset.
- llvm::Value *VTableOffset = FnAsInt;
- if (!UseARMMethodPtrABI)
- VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1);
- if (Use32BitVTableOffsetABI) {
- VTableOffset = Builder.CreateTrunc(VTableOffset, CGF.Int32Ty);
- VTableOffset = Builder.CreateZExt(VTableOffset, CGM.PtrDiffTy);
- }
- // Compute the address of the virtual function pointer.
- llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);
-
- // Check the address of the function pointer if CFI on member function
- // pointers is enabled.
- llvm::Constant *CheckSourceLocation;
- llvm::Constant *CheckTypeDesc;
- bool ShouldEmitCFICheck = CGF.SanOpts.has(SanitizerKind::CFIMFCall) &&
- CGM.HasHiddenLTOVisibility(RD);
- if (ShouldEmitCFICheck) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
-
- CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getBeginLoc());
- CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
- llvm::Constant *StaticData[] = {
- llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
- CheckSourceLocation,
- CheckTypeDesc,
- };
-
- llvm::Metadata *MD =
- CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
- llvm::Value *TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
-
- llvm::Value *TypeTest = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test), {VFPAddr, TypeId});
-
- if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
- CGF.EmitTrapCheck(TypeTest);
- } else {
- llvm::Value *AllVtables = llvm::MetadataAsValue::get(
- CGM.getLLVMContext(),
- llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
- llvm::Value *ValidVtable = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
- CGF.EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIMFCall),
- SanitizerHandler::CFICheckFail, StaticData,
- {VTable, ValidVtable});
- }
-
- FnVirtual = Builder.GetInsertBlock();
- }
-
- // Load the virtual function to call.
- VFPAddr = Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
- llvm::Value *VirtualFn = Builder.CreateAlignedLoad(
- VFPAddr, CGF.getPointerAlign(), "memptr.virtualfn");
- CGF.EmitBranch(FnEnd);
-
- // In the non-virtual path, the function pointer is actually a
- // function pointer.
- CGF.EmitBlock(FnNonVirtual);
- llvm::Value *NonVirtualFn =
- Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo(), "memptr.nonvirtualfn");
-
- // Check the function pointer if CFI on member function pointers is enabled.
- if (ShouldEmitCFICheck) {
- CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- if (RD->hasDefinition()) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
-
- llvm::Constant *StaticData[] = {
- llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_NVMFCall),
- CheckSourceLocation,
- CheckTypeDesc,
- };
-
- llvm::Value *Bit = Builder.getFalse();
- llvm::Value *CastedNonVirtualFn =
- Builder.CreateBitCast(NonVirtualFn, CGF.Int8PtrTy);
- for (const CXXRecordDecl *Base : CGM.getMostBaseClasses(RD)) {
- llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(
- getContext().getMemberPointerType(
- MPT->getPointeeType(),
- getContext().getRecordType(Base).getTypePtr()));
- llvm::Value *TypeId =
- llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
-
- llvm::Value *TypeTest =
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
- {CastedNonVirtualFn, TypeId});
- Bit = Builder.CreateOr(Bit, TypeTest);
- }
-
- CGF.EmitCheck(std::make_pair(Bit, SanitizerKind::CFIMFCall),
- SanitizerHandler::CFICheckFail, StaticData,
- {CastedNonVirtualFn, llvm::UndefValue::get(CGF.IntPtrTy)});
-
- FnNonVirtual = Builder.GetInsertBlock();
- }
- }
-
- // We're done.
- CGF.EmitBlock(FnEnd);
- llvm::PHINode *CalleePtr = Builder.CreatePHI(FTy->getPointerTo(), 2);
- CalleePtr->addIncoming(VirtualFn, FnVirtual);
- CalleePtr->addIncoming(NonVirtualFn, FnNonVirtual);
-
- CGCallee Callee(FPT, CalleePtr);
- return Callee;
-}
-
-/// Compute an l-value by applying the given pointer-to-member to a
-/// base object.
-llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
- CodeGenFunction &CGF, const Expr *E, Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
- assert(MemPtr->getType() == CGM.PtrDiffTy);
-
- CGBuilderTy &Builder = CGF.Builder;
-
- // Cast to char*.
- Base = Builder.CreateElementBitCast(Base, CGF.Int8Ty);
-
- // Apply the offset, which we assume is non-null.
- llvm::Value *Addr =
- Builder.CreateInBoundsGEP(Base.getPointer(), MemPtr, "memptr.offset");
-
- // Cast the address to the appropriate pointer type, adopting the
- // address space of the base pointer.
- llvm::Type *PType = CGF.ConvertTypeForMem(MPT->getPointeeType())
- ->getPointerTo(Base.getAddressSpace());
- return Builder.CreateBitCast(Addr, PType);
-}
-
-/// Perform a bitcast, derived-to-base, or base-to-derived member pointer
-/// conversion.
-///
-/// Bitcast conversions are always a no-op under Itanium.
-///
-/// Obligatory offset/adjustment diagram:
-/// <-- offset --> <-- adjustment -->
-/// |--------------------------|----------------------|--------------------|
-/// ^Derived address point ^Base address point ^Member address point
-///
-/// So when converting a base member pointer to a derived member pointer,
-/// we add the offset to the adjustment because the address point has
-/// decreased; and conversely, when converting a derived MP to a base MP
-/// we subtract the offset from the adjustment because the address point
-/// has increased.
-///
-/// The standard forbids (at compile time) conversion to and from
-/// virtual bases, which is why we don't have to consider them here.
-///
-/// The standard forbids (at run time) casting a derived MP to a base
-/// MP when the derived MP does not point to a member of the base.
-/// This is why -1 is a reasonable choice for null data member
-/// pointers.
-llvm::Value *
-ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
- const CastExpr *E,
- llvm::Value *src) {
- assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
- E->getCastKind() == CK_BaseToDerivedMemberPointer ||
- E->getCastKind() == CK_ReinterpretMemberPointer);
-
- // Under Itanium, reinterprets don't require any additional processing.
- if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
-
- // Use constant emission if we can.
- if (isa<llvm::Constant>(src))
- return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));
-
- llvm::Constant *adj = getMemberPointerAdjustment(E);
- if (!adj) return src;
-
- CGBuilderTy &Builder = CGF.Builder;
- bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
-
- const MemberPointerType *destTy =
- E->getType()->castAs<MemberPointerType>();
-
- // For member data pointers, this is just a matter of adding the
- // offset if the source is non-null.
- if (destTy->isMemberDataPointer()) {
- llvm::Value *dst;
- if (isDerivedToBase)
- dst = Builder.CreateNSWSub(src, adj, "adj");
- else
- dst = Builder.CreateNSWAdd(src, adj, "adj");
-
- // Null check.
- llvm::Value *null = llvm::Constant::getAllOnesValue(src->getType());
- llvm::Value *isNull = Builder.CreateICmpEQ(src, null, "memptr.isnull");
- return Builder.CreateSelect(isNull, src, dst);
- }
-
- // The this-adjustment is left-shifted by 1 on ARM.
- if (UseARMMethodPtrABI) {
- uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue();
- offset <<= 1;
- adj = llvm::ConstantInt::get(adj->getType(), offset);
- }
-
- llvm::Value *srcAdj = Builder.CreateExtractValue(src, 1, "src.adj");
- llvm::Value *dstAdj;
- if (isDerivedToBase)
- dstAdj = Builder.CreateNSWSub(srcAdj, adj, "adj");
- else
- dstAdj = Builder.CreateNSWAdd(srcAdj, adj, "adj");
-
- return Builder.CreateInsertValue(src, dstAdj, 1);
-}
-
-llvm::Constant *
-ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *src) {
- assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
- E->getCastKind() == CK_BaseToDerivedMemberPointer ||
- E->getCastKind() == CK_ReinterpretMemberPointer);
-
- // Under Itanium, reinterprets don't require any additional processing.
- if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
-
- // If the adjustment is trivial, we don't need to do anything.
- llvm::Constant *adj = getMemberPointerAdjustment(E);
- if (!adj) return src;
-
- bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
-
- const MemberPointerType *destTy =
- E->getType()->castAs<MemberPointerType>();
-
- // For member data pointers, this is just a matter of adding the
- // offset if the source is non-null.
- if (destTy->isMemberDataPointer()) {
- // null maps to null.
- if (src->isAllOnesValue()) return src;
-
- if (isDerivedToBase)
- return llvm::ConstantExpr::getNSWSub(src, adj);
- else
- return llvm::ConstantExpr::getNSWAdd(src, adj);
- }
-
- // The this-adjustment is left-shifted by 1 on ARM.
- if (UseARMMethodPtrABI) {
- uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue();
- offset <<= 1;
- adj = llvm::ConstantInt::get(adj->getType(), offset);
- }
-
- llvm::Constant *srcAdj = llvm::ConstantExpr::getExtractValue(src, 1);
- llvm::Constant *dstAdj;
- if (isDerivedToBase)
- dstAdj = llvm::ConstantExpr::getNSWSub(srcAdj, adj);
- else
- dstAdj = llvm::ConstantExpr::getNSWAdd(srcAdj, adj);
-
- return llvm::ConstantExpr::getInsertValue(src, dstAdj, 1);
-}
-
-llvm::Constant *
-ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- // Itanium C++ ABI 2.3:
- // A NULL pointer is represented as -1.
- if (MPT->isMemberDataPointer())
- return llvm::ConstantInt::get(CGM.PtrDiffTy, -1ULL, /*isSigned=*/true);
-
- llvm::Constant *Zero = llvm::ConstantInt::get(CGM.PtrDiffTy, 0);
- llvm::Constant *Values[2] = { Zero, Zero };
- return llvm::ConstantStruct::getAnon(Values);
-}
-
-llvm::Constant *
-ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset) {
- // Itanium C++ ABI 2.3:
- // A pointer to data member is an offset from the base address of
- // the class object containing it, represented as a ptrdiff_t
- return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity());
-}
-
-llvm::Constant *
-ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
- return BuildMemberPointer(MD, CharUnits::Zero());
-}
-
-llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
- CharUnits ThisAdjustment) {
- assert(MD->isInstance() && "Member function must not be static!");
-
- CodeGenTypes &Types = CGM.getTypes();
-
- // Get the function pointer (or index if this is a virtual function).
- llvm::Constant *MemPtr[2];
- if (MD->isVirtual()) {
- uint64_t Index = CGM.getItaniumVTableContext().getMethodVTableIndex(MD);
-
- const ASTContext &Context = getContext();
- CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- uint64_t VTableOffset = (Index * PointerWidth.getQuantity());
-
- if (UseARMMethodPtrABI) {
- // ARM C++ ABI 3.2.1:
- // This ABI specifies that adj contains twice the this
- // adjustment, plus 1 if the member function is virtual. The
- // least significant bit of adj then makes exactly the same
- // discrimination as the least significant bit of ptr does for
- // Itanium.
- MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
- MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
- 2 * ThisAdjustment.getQuantity() + 1);
- } else {
- // Itanium C++ ABI 2.3:
- // For a virtual function, [the pointer field] is 1 plus the
- // virtual table offset (in bytes) of the function,
- // represented as a ptrdiff_t.
- MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset + 1);
- MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
- ThisAdjustment.getQuantity());
- }
- } else {
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- llvm::Type *Ty;
- // Check whether the function has a computable LLVM signature.
- if (Types.isFuncTypeConvertible(FPT)) {
- // The function has a computable LLVM signature; use the correct type.
- Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD));
- } else {
- // Use an arbitrary non-function type to tell GetAddrOfFunction that the
- // function type is incomplete.
- Ty = CGM.PtrDiffTy;
- }
- llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
-
- MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy);
- MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
- (UseARMMethodPtrABI ? 2 : 1) *
- ThisAdjustment.getQuantity());
- }
-
- return llvm::ConstantStruct::getAnon(MemPtr);
-}
-
-llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,
- QualType MPType) {
- const MemberPointerType *MPT = MPType->castAs<MemberPointerType>();
- const ValueDecl *MPD = MP.getMemberPointerDecl();
- if (!MPD)
- return EmitNullMemberPointer(MPT);
-
- CharUnits ThisAdjustment = getMemberPointerPathAdjustment(MP);
-
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
- return BuildMemberPointer(MD, ThisAdjustment);
-
- CharUnits FieldOffset =
- getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
- return EmitMemberDataPointer(MPT, ThisAdjustment + FieldOffset);
-}
-
-/// The comparison algorithm is pretty easy: the member pointers are
-/// the same if they're either bitwise identical *or* both null.
-///
-/// ARM is different here only because null-ness is more complicated.
-llvm::Value *
-ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L,
- llvm::Value *R,
- const MemberPointerType *MPT,
- bool Inequality) {
- CGBuilderTy &Builder = CGF.Builder;
-
- llvm::ICmpInst::Predicate Eq;
- llvm::Instruction::BinaryOps And, Or;
- if (Inequality) {
- Eq = llvm::ICmpInst::ICMP_NE;
- And = llvm::Instruction::Or;
- Or = llvm::Instruction::And;
- } else {
- Eq = llvm::ICmpInst::ICMP_EQ;
- And = llvm::Instruction::And;
- Or = llvm::Instruction::Or;
- }
-
- // Member data pointers are easy because there's a unique null
- // value, so it just comes down to bitwise equality.
- if (MPT->isMemberDataPointer())
- return Builder.CreateICmp(Eq, L, R);
-
- // For member function pointers, the tautologies are more complex.
- // The Itanium tautology is:
- // (L == R) <==> (L.ptr == R.ptr && (L.ptr == 0 || L.adj == R.adj))
- // The ARM tautology is:
- // (L == R) <==> (L.ptr == R.ptr &&
- // (L.adj == R.adj ||
- // (L.ptr == 0 && ((L.adj|R.adj) & 1) == 0)))
- // The inequality tautologies have exactly the same structure, except
- // applying De Morgan's laws.
-
- llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr");
- llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr");
-
- // This condition tests whether L.ptr == R.ptr. This must always be
- // true for equality to hold.
- llvm::Value *PtrEq = Builder.CreateICmp(Eq, LPtr, RPtr, "cmp.ptr");
-
- // This condition, together with the assumption that L.ptr == R.ptr,
- // tests whether the pointers are both null. ARM imposes an extra
- // condition.
- llvm::Value *Zero = llvm::Constant::getNullValue(LPtr->getType());
- llvm::Value *EqZero = Builder.CreateICmp(Eq, LPtr, Zero, "cmp.ptr.null");
-
- // This condition tests whether L.adj == R.adj. If this isn't
- // true, the pointers are unequal unless they're both null.
- llvm::Value *LAdj = Builder.CreateExtractValue(L, 1, "lhs.memptr.adj");
- llvm::Value *RAdj = Builder.CreateExtractValue(R, 1, "rhs.memptr.adj");
- llvm::Value *AdjEq = Builder.CreateICmp(Eq, LAdj, RAdj, "cmp.adj");
-
- // Null member function pointers on ARM clear the low bit of Adj,
- // so the zero condition has to check that neither low bit is set.
- if (UseARMMethodPtrABI) {
- llvm::Value *One = llvm::ConstantInt::get(LPtr->getType(), 1);
-
- // Compute (l.adj | r.adj) & 1 and test it against zero.
- llvm::Value *OrAdj = Builder.CreateOr(LAdj, RAdj, "or.adj");
- llvm::Value *OrAdjAnd1 = Builder.CreateAnd(OrAdj, One);
- llvm::Value *OrAdjAnd1EqZero = Builder.CreateICmp(Eq, OrAdjAnd1, Zero,
- "cmp.or.adj");
- EqZero = Builder.CreateBinOp(And, EqZero, OrAdjAnd1EqZero);
- }
-
- // Tie together all our conditions.
- llvm::Value *Result = Builder.CreateBinOp(Or, EqZero, AdjEq);
- Result = Builder.CreateBinOp(And, PtrEq, Result,
- Inequality ? "memptr.ne" : "memptr.eq");
- return Result;
-}
-
-llvm::Value *
-ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
- CGBuilderTy &Builder = CGF.Builder;
-
- /// For member data pointers, this is just a check against -1.
- if (MPT->isMemberDataPointer()) {
- assert(MemPtr->getType() == CGM.PtrDiffTy);
- llvm::Value *NegativeOne =
- llvm::Constant::getAllOnesValue(MemPtr->getType());
- return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool");
- }
-
- // In Itanium, a member function pointer is not null if 'ptr' is not null.
- llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr");
-
- llvm::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0);
- llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool");
-
- // On ARM, a member function pointer is also non-null if the low bit of 'adj'
- // (the virtual bit) is set.
- if (UseARMMethodPtrABI) {
- llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1);
- llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj");
- llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit");
- llvm::Value *IsVirtual = Builder.CreateICmpNE(VirtualBit, Zero,
- "memptr.isvirtual");
- Result = Builder.CreateOr(Result, IsVirtual);
- }
-
- return Result;
-}
-
-bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
- const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl();
- if (!RD)
- return false;
-
- // If C++ prohibits us from making a copy, return by address.
- if (passClassIndirect(RD)) {
- auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType());
- FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
- return true;
- }
- return false;
-}
-
-/// The Itanium ABI requires non-zero initialization only for data
-/// member pointers, for which '0' is a valid offset.
-bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
- return MPT->isMemberFunctionPointer();
-}
-
-/// The Itanium ABI always places an offset to the complete object
-/// at entry -2 in the vtable.
-void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- Address Ptr,
- QualType ElementType,
- const CXXDestructorDecl *Dtor) {
- bool UseGlobalDelete = DE->isGlobalDelete();
- if (UseGlobalDelete) {
- // Derive the complete-object pointer, which is what we need
- // to pass to the deallocation function.
-
- // Grab the vtable pointer as an intptr_t*.
- auto *ClassDecl =
- cast<CXXRecordDecl>(ElementType->getAs<RecordType>()->getDecl());
- llvm::Value *VTable =
- CGF.GetVTablePtr(Ptr, CGF.IntPtrTy->getPointerTo(), ClassDecl);
-
- // Track back to entry -2 and pull out the offset there.
- llvm::Value *OffsetPtr = CGF.Builder.CreateConstInBoundsGEP1_64(
- VTable, -2, "complete-offset.ptr");
- llvm::Value *Offset =
- CGF.Builder.CreateAlignedLoad(OffsetPtr, CGF.getPointerAlign());
-
- // Apply the offset.
- llvm::Value *CompletePtr =
- CGF.Builder.CreateBitCast(Ptr.getPointer(), CGF.Int8PtrTy);
- CompletePtr = CGF.Builder.CreateInBoundsGEP(CompletePtr, Offset);
-
- // If we're supposed to call the global delete, make sure we do so
- // even if the destructor throws.
- CGF.pushCallObjectDeleteCleanup(DE->getOperatorDelete(), CompletePtr,
- ElementType);
- }
-
- // FIXME: Provide a source location here even though there's no
- // CXXMemberCallExpr for dtor call.
- CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
- EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, /*CE=*/nullptr);
-
- if (UseGlobalDelete)
- CGF.PopCleanupBlock();
-}
-
-void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
- // void __cxa_rethrow();
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
-
- llvm::Constant *Fn = CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
-
- if (isNoReturn)
- CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, None);
- else
- CGF.EmitRuntimeCallOrInvoke(Fn);
-}
-
-static llvm::Constant *getAllocateExceptionFn(CodeGenModule &CGM) {
- // void *__cxa_allocate_exception(size_t thrown_size);
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
-}
-
-static llvm::Constant *getThrowFn(CodeGenModule &CGM) {
- // void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
- // void (*dest) (void *));
-
- llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.Int8PtrTy, CGM.Int8PtrTy };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
-}
-
-void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
- QualType ThrowType = E->getSubExpr()->getType();
- // Now allocate the exception object.
- llvm::Type *SizeTy = CGF.ConvertType(getContext().getSizeType());
- uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
-
- llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM);
- llvm::CallInst *ExceptionPtr = CGF.EmitNounwindRuntimeCall(
- AllocExceptionFn, llvm::ConstantInt::get(SizeTy, TypeSize), "exception");
-
- CharUnits ExnAlign = getAlignmentOfExnObject();
- CGF.EmitAnyExprToExn(E->getSubExpr(), Address(ExceptionPtr, ExnAlign));
-
- // Now throw the exception.
- llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType,
- /*ForEH=*/true);
-
- // The address of the destructor. If the exception type has a
- // trivial destructor (or isn't a record), we just pass null.
- llvm::Constant *Dtor = nullptr;
- if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!Record->hasTrivialDestructor()) {
- CXXDestructorDecl *DtorD = Record->getDestructor();
- Dtor = CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete);
- Dtor = llvm::ConstantExpr::getBitCast(Dtor, CGM.Int8PtrTy);
- }
- }
- if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
-
- llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor };
- CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
-}
-
-static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
- // void *__dynamic_cast(const void *sub,
- // const abi::__class_type_info *src,
- // const abi::__class_type_info *dst,
- // std::ptrdiff_t src2dst_offset);
-
- llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
- llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
-
- llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
-
- // Mark the function as nounwind readonly.
- llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
- llvm::Attribute::ReadOnly };
- llvm::AttributeList Attrs = llvm::AttributeList::get(
- CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
-}
-
-static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
- // void __cxa_bad_cast();
- llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
-}
-
-/// Compute the src2dst_offset hint as described in the
-/// Itanium C++ ABI [2.9.7]
-static CharUnits computeOffsetHint(ASTContext &Context,
- const CXXRecordDecl *Src,
- const CXXRecordDecl *Dst) {
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
-
- // If Dst is not derived from Src we can skip the whole computation below and
- // return that Src is not a public base of Dst. Record all inheritance paths.
- if (!Dst->isDerivedFrom(Src, Paths))
- return CharUnits::fromQuantity(-2ULL);
-
- unsigned NumPublicPaths = 0;
- CharUnits Offset;
-
- // Now walk all possible inheritance paths.
- for (const CXXBasePath &Path : Paths) {
- if (Path.Access != AS_public) // Ignore non-public inheritance.
- continue;
-
- ++NumPublicPaths;
-
- for (const CXXBasePathElement &PathElement : Path) {
- // If the path contains a virtual base class we can't give any hint.
- // -1: no hint.
- if (PathElement.Base->isVirtual())
- return CharUnits::fromQuantity(-1ULL);
-
- if (NumPublicPaths > 1) // Won't use offsets, skip computation.
- continue;
-
- // Accumulate the base class offsets.
- const ASTRecordLayout &L = Context.getASTRecordLayout(PathElement.Class);
- Offset += L.getBaseClassOffset(
- PathElement.Base->getType()->getAsCXXRecordDecl());
- }
- }
-
- // -2: Src is not a public base of Dst.
- if (NumPublicPaths == 0)
- return CharUnits::fromQuantity(-2ULL);
-
- // -3: Src is a multiple public base type but never a virtual base type.
- if (NumPublicPaths > 1)
- return CharUnits::fromQuantity(-3ULL);
-
- // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
- // Return the offset of Src from the origin of Dst.
- return Offset;
-}
-
-static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
- // void __cxa_bad_typeid();
- llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
-}
-
-bool ItaniumCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
- QualType SrcRecordTy) {
- return IsDeref;
-}
-
-void ItaniumCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
- llvm::Value *Fn = getBadTypeidFn(CGF);
- CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
-}
-
-llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,
- QualType SrcRecordTy,
- Address ThisPtr,
- llvm::Type *StdTypeInfoPtrTy) {
- auto *ClassDecl =
- cast<CXXRecordDecl>(SrcRecordTy->getAs<RecordType>()->getDecl());
- llvm::Value *Value =
- CGF.GetVTablePtr(ThisPtr, StdTypeInfoPtrTy->getPointerTo(), ClassDecl);
-
- // Load the type info.
- Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
- return CGF.Builder.CreateAlignedLoad(Value, CGF.getPointerAlign());
-}
-
-bool ItaniumCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
- QualType SrcRecordTy) {
- return SrcIsPtr;
-}
-
-llvm::Value *ItaniumCXXABI::EmitDynamicCastCall(
- CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
- QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
- llvm::Type *PtrDiffLTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
- llvm::Type *DestLTy = CGF.ConvertType(DestTy);
-
- llvm::Value *SrcRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
- llvm::Value *DestRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
-
- // Compute the offset hint.
- const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
- const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
- llvm::Value *OffsetHint = llvm::ConstantInt::get(
- PtrDiffLTy,
- computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl).getQuantity());
-
- // Emit the call to __dynamic_cast.
- llvm::Value *Value = ThisAddr.getPointer();
- Value = CGF.EmitCastToVoidPtr(Value);
-
- llvm::Value *args[] = {Value, SrcRTTI, DestRTTI, OffsetHint};
- Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), args);
- Value = CGF.Builder.CreateBitCast(Value, DestLTy);
-
- /// C++ [expr.dynamic.cast]p9:
- /// A failed cast to reference type throws std::bad_cast
- if (DestTy->isReferenceType()) {
- llvm::BasicBlock *BadCastBlock =
- CGF.createBasicBlock("dynamic_cast.bad_cast");
-
- llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);
- CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);
-
- CGF.EmitBlock(BadCastBlock);
- EmitBadCastCall(CGF);
- }
-
- return Value;
-}
-
-llvm::Value *ItaniumCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF,
- Address ThisAddr,
- QualType SrcRecordTy,
- QualType DestTy) {
- llvm::Type *PtrDiffLTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
- llvm::Type *DestLTy = CGF.ConvertType(DestTy);
-
- auto *ClassDecl =
- cast<CXXRecordDecl>(SrcRecordTy->getAs<RecordType>()->getDecl());
- // Get the vtable pointer.
- llvm::Value *VTable = CGF.GetVTablePtr(ThisAddr, PtrDiffLTy->getPointerTo(),
- ClassDecl);
-
- // Get the offset-to-top from the vtable.
- llvm::Value *OffsetToTop =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);
- OffsetToTop =
- CGF.Builder.CreateAlignedLoad(OffsetToTop, CGF.getPointerAlign(),
- "offset.to.top");
-
- // Finally, add the offset to the pointer.
- llvm::Value *Value = ThisAddr.getPointer();
- Value = CGF.EmitCastToVoidPtr(Value);
- Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);
-
- return CGF.Builder.CreateBitCast(Value, DestLTy);
-}
-
-bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
- llvm::Value *Fn = getBadCastFn(CGF);
- CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
- return true;
-}
-
-llvm::Value *
-ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
- Address This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- llvm::Value *VTablePtr = CGF.GetVTablePtr(This, CGM.Int8PtrTy, ClassDecl);
- CharUnits VBaseOffsetOffset =
- CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(ClassDecl,
- BaseClassDecl);
-
- llvm::Value *VBaseOffsetPtr =
- CGF.Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(),
- "vbase.offset.ptr");
- VBaseOffsetPtr = CGF.Builder.CreateBitCast(VBaseOffsetPtr,
- CGM.PtrDiffTy->getPointerTo());
-
- llvm::Value *VBaseOffset =
- CGF.Builder.CreateAlignedLoad(VBaseOffsetPtr, CGF.getPointerAlign(),
- "vbase.offset");
-
- return VBaseOffset;
-}
-
-void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
- // Just make sure we're in sync with TargetCXXABI.
- assert(CGM.getTarget().getCXXABI().hasConstructorVariants());
-
- // The constructor used for constructing this as a base class;
- // ignores virtual bases.
- CGM.EmitGlobal(GlobalDecl(D, Ctor_Base));
-
- // The constructor used for constructing this as a complete class;
- // constructs the virtual bases, then calls the base constructor.
- if (!D->getParent()->isAbstract()) {
- // We don't need to emit the complete ctor if the class is abstract.
- CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
- }
-}
-
-CGCXXABI::AddedStructorArgs
-ItaniumCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) {
- ASTContext &Context = getContext();
-
- // All parameters are already in place except VTT, which goes after 'this'.
- // These are Clang types, so we don't need to worry about sret yet.
-
- // Check if we need to add a VTT parameter (which has type void **).
- if (T == StructorType::Base && MD->getParent()->getNumVBases() != 0) {
- ArgTys.insert(ArgTys.begin() + 1,
- Context.getPointerType(Context.VoidPtrTy));
- return AddedStructorArgs::prefix(1);
- }
- return AddedStructorArgs{};
-}
-
-void ItaniumCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
- // The destructor used for destructing this as a base class; ignores
- // virtual bases.
- CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
-
- // The destructor used for destructing this as a most-derived class;
- // call the base destructor and then destructs any virtual bases.
- CGM.EmitGlobal(GlobalDecl(D, Dtor_Complete));
-
- // The destructor in a virtual table is always a 'deleting'
- // destructor, which calls the complete destructor and then uses the
- // appropriate operator delete.
- if (D->isVirtual())
- CGM.EmitGlobal(GlobalDecl(D, Dtor_Deleting));
-}
-
-void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
- assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
-
- // Check if we need a VTT parameter as well.
- if (NeedsVTTParameter(CGF.CurGD)) {
- ASTContext &Context = getContext();
-
- // FIXME: avoid the fake decl
- QualType T = Context.getPointerType(Context.VoidPtrTy);
- auto *VTTDecl = ImplicitParamDecl::Create(
- Context, /*DC=*/nullptr, MD->getLocation(), &Context.Idents.get("vtt"),
- T, ImplicitParamDecl::CXXVTT);
- Params.insert(Params.begin() + 1, VTTDecl);
- getStructorImplicitParamDecl(CGF) = VTTDecl;
- }
-}
-
-void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
- // Naked functions have no prolog.
- if (CGF.CurFuncDecl && CGF.CurFuncDecl->hasAttr<NakedAttr>())
- return;
-
- /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue
- /// adjustments are required, because they are all handled by thunks.
- setCXXABIThisValue(CGF, loadIncomingCXXThis(CGF));
-
- /// Initialize the 'vtt' slot if needed.
- if (getStructorImplicitParamDecl(CGF)) {
- getStructorImplicitParamValue(CGF) = CGF.Builder.CreateLoad(
- CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)), "vtt");
- }
-
- /// If this is a function that the ABI specifies returns 'this', initialize
- /// the return slot to 'this' at the start of the function.
- ///
- /// Unlike the setting of return types, this is done within the ABI
- /// implementation instead of by clients of CGCXXABI because:
- /// 1) getThisValue is currently protected
- /// 2) in theory, an ABI could implement 'this' returns some other way;
- /// HasThisReturn only specifies a contract, not the implementation
- if (HasThisReturn(CGF.CurGD))
- CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
-}
-
-CGCXXABI::AddedStructorArgs ItaniumCXXABI::addImplicitConstructorArgs(
- CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, bool Delegating, CallArgList &Args) {
- if (!NeedsVTTParameter(GlobalDecl(D, Type)))
- return AddedStructorArgs{};
-
- // Insert the implicit 'vtt' argument as the second argument.
- llvm::Value *VTT =
- CGF.GetVTTParameter(GlobalDecl(D, Type), ForVirtualBase, Delegating);
- QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
- Args.insert(Args.begin() + 1, CallArg(RValue::get(VTT), VTTTy));
- return AddedStructorArgs::prefix(1); // Added one arg.
-}
-
-void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *DD,
- CXXDtorType Type, bool ForVirtualBase,
- bool Delegating, Address This) {
- GlobalDecl GD(DD, Type);
- llvm::Value *VTT = CGF.GetVTTParameter(GD, ForVirtualBase, Delegating);
- QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
-
- CGCallee Callee;
- if (getContext().getLangOpts().AppleKext &&
- Type != Dtor_Base && DD->isVirtual())
- Callee = CGF.BuildAppleKextVirtualDestructorCall(DD, Type, DD->getParent());
- else
- Callee = CGCallee::forDirect(
- CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type)), GD);
-
- CGF.EmitCXXMemberOrOperatorCall(DD, Callee, ReturnValueSlot(),
- This.getPointer(), VTT, VTTTy,
- nullptr, nullptr);
-}
-
-void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
- const CXXRecordDecl *RD) {
- llvm::GlobalVariable *VTable = getAddrOfVTable(RD, CharUnits());
- if (VTable->hasInitializer())
- return;
-
- ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
- const VTableLayout &VTLayout = VTContext.getVTableLayout(RD);
- llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
- llvm::Constant *RTTI =
- CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD));
-
- // Create and set the initializer.
- ConstantInitBuilder Builder(CGM);
- auto Components = Builder.beginStruct();
- CGVT.createVTableInitializer(Components, VTLayout, RTTI);
- Components.finishAndSetAsInitializer(VTable);
-
- // Set the correct linkage.
- VTable->setLinkage(Linkage);
-
- if (CGM.supportsCOMDAT() && VTable->isWeakForLinker())
- VTable->setComdat(CGM.getModule().getOrInsertComdat(VTable->getName()));
-
- // Set the right visibility.
- CGM.setGVProperties(VTable, RD);
-
- // If this is the magic class __cxxabiv1::__fundamental_type_info,
- // we will emit the typeinfo for the fundamental types. This is the
- // same behaviour as GCC.
- const DeclContext *DC = RD->getDeclContext();
- if (RD->getIdentifier() &&
- RD->getIdentifier()->isStr("__fundamental_type_info") &&
- isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
- cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
- DC->getParent()->isTranslationUnit())
- EmitFundamentalRTTIDescriptors(RD);
-
- if (!VTable->isDeclarationForLinker())
- CGM.EmitVTableTypeMetadata(VTable, VTLayout);
-}
-
-bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
- CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) {
- if (Vptr.NearestVBase == nullptr)
- return false;
- return NeedsVTTParameter(CGF.CurGD);
-}
-
-llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
- CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
- const CXXRecordDecl *NearestVBase) {
-
- if ((Base.getBase()->getNumVBases() || NearestVBase != nullptr) &&
- NeedsVTTParameter(CGF.CurGD)) {
- return getVTableAddressPointInStructorWithVTT(CGF, VTableClass, Base,
- NearestVBase);
- }
- return getVTableAddressPoint(Base, VTableClass);
-}
-
-llvm::Constant *
-ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) {
- llvm::GlobalValue *VTable = getAddrOfVTable(VTableClass, CharUnits());
-
- // Find the appropriate vtable within the vtable group, and the address point
- // within that vtable.
- VTableLayout::AddressPointLocation AddressPoint =
- CGM.getItaniumVTableContext()
- .getVTableLayout(VTableClass)
- .getAddressPoint(Base);
- llvm::Value *Indices[] = {
- llvm::ConstantInt::get(CGM.Int32Ty, 0),
- llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.VTableIndex),
- llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.AddressPointIndex),
- };
-
- return llvm::ConstantExpr::getGetElementPtr(VTable->getValueType(), VTable,
- Indices, /*InBounds=*/true,
- /*InRangeIndex=*/1);
-}
-
-llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
- CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
- const CXXRecordDecl *NearestVBase) {
- assert((Base.getBase()->getNumVBases() || NearestVBase != nullptr) &&
- NeedsVTTParameter(CGF.CurGD) && "This class doesn't have VTT");
-
- // Get the secondary vpointer index.
- uint64_t VirtualPointerIndex =
- CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
-
- /// Load the VTT.
- llvm::Value *VTT = CGF.LoadCXXVTT();
- if (VirtualPointerIndex)
- VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex);
-
- // And load the address point from the VTT.
- return CGF.Builder.CreateAlignedLoad(VTT, CGF.getPointerAlign());
-}
-
-llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr(
- BaseSubobject Base, const CXXRecordDecl *VTableClass) {
- return getVTableAddressPoint(Base, VTableClass);
-}
-
-llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
- CharUnits VPtrOffset) {
- assert(VPtrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");
-
- llvm::GlobalVariable *&VTable = VTables[RD];
- if (VTable)
- return VTable;
-
- // Queue up this vtable for possible deferred emission.
- CGM.addDeferredVTable(RD);
-
- SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- getMangleContext().mangleCXXVTable(RD, Out);
-
- const VTableLayout &VTLayout =
- CGM.getItaniumVTableContext().getVTableLayout(RD);
- llvm::Type *VTableType = CGM.getVTables().getVTableType(VTLayout);
-
- // Use pointer alignment for the vtable. Otherwise we would align them based
- // on the size of the initializer which doesn't make sense as only single
- // values are read.
- unsigned PAlign = CGM.getTarget().getPointerAlign(0);
-
- VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name, VTableType, llvm::GlobalValue::ExternalLinkage,
- getContext().toCharUnitsFromBits(PAlign).getQuantity());
- VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- CGM.setGVProperties(VTable, RD);
-
- return VTable;
-}
-
-CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
- GlobalDecl GD,
- Address This,
- llvm::Type *Ty,
- SourceLocation Loc) {
- Ty = Ty->getPointerTo()->getPointerTo();
- auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
- llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent());
-
- uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
- llvm::Value *VFunc;
- if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) {
- VFunc = CGF.EmitVTableTypeCheckedLoad(
- MethodDecl->getParent(), VTable,
- VTableIndex * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8);
- } else {
- CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
-
- llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
- auto *VFuncLoad =
- CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
-
- // Add !invariant.load md to virtual function load to indicate that
- // function didn't change inside vtable.
- // It's safe to add it without -fstrict-vtable-pointers, but it would not
- // help in devirtualization because it will only matter if we will have 2
- // the same virtual function loads from the same vtable load, which won't
- // happen without enabled devirtualization with -fstrict-vtable-pointers.
- if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- CGM.getCodeGenOpts().StrictVTablePointers)
- VFuncLoad->setMetadata(
- llvm::LLVMContext::MD_invariant_load,
- llvm::MDNode::get(CGM.getLLVMContext(),
- llvm::ArrayRef<llvm::Metadata *>()));
- VFunc = VFuncLoad;
- }
-
- CGCallee Callee(GD, VFunc);
- return Callee;
-}
-
-llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
- CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
- Address This, const CXXMemberCallExpr *CE) {
- assert(CE == nullptr || CE->arg_begin() == CE->arg_end());
- assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
-
- const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
- Dtor, getFromDtorType(DtorType));
- llvm::FunctionType *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- CGCallee Callee =
- CGCallee::forVirtual(CE, GlobalDecl(Dtor, DtorType), This, Ty);
-
- CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(),
- This.getPointer(), /*ImplicitParam=*/nullptr,
- QualType(), CE, nullptr);
- return nullptr;
-}
-
-void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
- CodeGenVTables &VTables = CGM.getVTables();
- llvm::GlobalVariable *VTT = VTables.GetAddrOfVTT(RD);
- VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
-}
-
-bool ItaniumCXXABI::canSpeculativelyEmitVTableAsBaseClass(
- const CXXRecordDecl *RD) const {
- // We don't emit available_externally vtables if we are in -fapple-kext mode
- // because kext mode does not permit devirtualization.
- if (CGM.getLangOpts().AppleKext)
- return false;
-
- // If the vtable is hidden then it is not safe to emit an available_externally
- // copy of vtable.
- if (isVTableHidden(RD))
- return false;
-
- if (CGM.getCodeGenOpts().ForceEmitVTables)
- return true;
-
- // If we don't have any not emitted inline virtual function then we are safe
- // to emit an available_externally copy of vtable.
- // FIXME we can still emit a copy of the vtable if we
- // can emit definition of the inline functions.
- if (hasAnyUnusedVirtualInlineFunction(RD))
- return false;
-
- // For a class with virtual bases, we must also be able to speculatively
- // emit the VTT, because CodeGen doesn't have separate notions of "can emit
- // the vtable" and "can emit the VTT". For a base subobject, this means we
- // need to be able to emit non-virtual base vtables.
- if (RD->getNumVBases()) {
- for (const auto &B : RD->bases()) {
- auto *BRD = B.getType()->getAsCXXRecordDecl();
- assert(BRD && "no class for base specifier");
- if (B.isVirtual() || !BRD->isDynamicClass())
- continue;
- if (!canSpeculativelyEmitVTableAsBaseClass(BRD))
- return false;
- }
- }
-
- return true;
-}
-
-bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const {
- if (!canSpeculativelyEmitVTableAsBaseClass(RD))
- return false;
-
- // For a complete-object vtable (or more specifically, for the VTT), we need
- // to be able to speculatively emit the vtables of all dynamic virtual bases.
- for (const auto &B : RD->vbases()) {
- auto *BRD = B.getType()->getAsCXXRecordDecl();
- assert(BRD && "no class for base specifier");
- if (!BRD->isDynamicClass())
- continue;
- if (!canSpeculativelyEmitVTableAsBaseClass(BRD))
- return false;
- }
-
- return true;
-}
-static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
- Address InitialPtr,
- int64_t NonVirtualAdjustment,
- int64_t VirtualAdjustment,
- bool IsReturnAdjustment) {
- if (!NonVirtualAdjustment && !VirtualAdjustment)
- return InitialPtr.getPointer();
-
- Address V = CGF.Builder.CreateElementBitCast(InitialPtr, CGF.Int8Ty);
-
- // In a base-to-derived cast, the non-virtual adjustment is applied first.
- if (NonVirtualAdjustment && !IsReturnAdjustment) {
- V = CGF.Builder.CreateConstInBoundsByteGEP(V,
- CharUnits::fromQuantity(NonVirtualAdjustment));
- }
-
- // Perform the virtual adjustment if we have one.
- llvm::Value *ResultPtr;
- if (VirtualAdjustment) {
- llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
-
- Address VTablePtrPtr = CGF.Builder.CreateElementBitCast(V, CGF.Int8PtrTy);
- llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
-
- llvm::Value *OffsetPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
-
- OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
-
- // Load the adjustment offset from the vtable.
- llvm::Value *Offset =
- CGF.Builder.CreateAlignedLoad(OffsetPtr, CGF.getPointerAlign());
-
- // Adjust our pointer.
- ResultPtr = CGF.Builder.CreateInBoundsGEP(V.getPointer(), Offset);
- } else {
- ResultPtr = V.getPointer();
- }
-
- // In a derived-to-base conversion, the non-virtual adjustment is
- // applied second.
- if (NonVirtualAdjustment && IsReturnAdjustment) {
- ResultPtr = CGF.Builder.CreateConstInBoundsGEP1_64(ResultPtr,
- NonVirtualAdjustment);
- }
-
- // Cast back to the original type.
- return CGF.Builder.CreateBitCast(ResultPtr, InitialPtr.getType());
-}
-
-llvm::Value *ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF,
- Address This,
- const ThisAdjustment &TA) {
- return performTypeAdjustment(CGF, This, TA.NonVirtual,
- TA.Virtual.Itanium.VCallOffsetOffset,
- /*IsReturnAdjustment=*/false);
-}
-
-llvm::Value *
-ItaniumCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret,
- const ReturnAdjustment &RA) {
- return performTypeAdjustment(CGF, Ret, RA.NonVirtual,
- RA.Virtual.Itanium.VBaseOffsetOffset,
- /*IsReturnAdjustment=*/true);
-}
-
-void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
- RValue RV, QualType ResultType) {
- if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
- return ItaniumCXXABI::EmitReturnFromThunk(CGF, RV, ResultType);
-
- // Destructor thunks in the ARM ABI have indeterminate results.
- llvm::Type *T = CGF.ReturnValue.getElementType();
- RValue Undef = RValue::get(llvm::UndefValue::get(T));
- return ItaniumCXXABI::EmitReturnFromThunk(CGF, Undef, ResultType);
-}
-
-/************************** Array allocation cookies **************************/
-
-CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
- // The array cookie is a size_t; pad that up to the element alignment.
- // The cookie is actually right-justified in that space.
- return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),
- CGM.getContext().getTypeAlignInChars(elementType));
-}
-
-Address ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
- Address NewPtr,
- llvm::Value *NumElements,
- const CXXNewExpr *expr,
- QualType ElementType) {
- assert(requiresArrayCookie(expr));
-
- unsigned AS = NewPtr.getAddressSpace();
-
- ASTContext &Ctx = getContext();
- CharUnits SizeSize = CGF.getSizeSize();
-
- // The size of the cookie.
- CharUnits CookieSize =
- std::max(SizeSize, Ctx.getTypeAlignInChars(ElementType));
- assert(CookieSize == getArrayCookieSizeImpl(ElementType));
-
- // Compute an offset to the cookie.
- Address CookiePtr = NewPtr;
- CharUnits CookieOffset = CookieSize - SizeSize;
- if (!CookieOffset.isZero())
- CookiePtr = CGF.Builder.CreateConstInBoundsByteGEP(CookiePtr, CookieOffset);
-
- // Write the number of elements into the appropriate slot.
- Address NumElementsPtr =
- CGF.Builder.CreateElementBitCast(CookiePtr, CGF.SizeTy);
- llvm::Instruction *SI = CGF.Builder.CreateStore(NumElements, NumElementsPtr);
-
- // Handle the array cookie specially in ASan.
- if (CGM.getLangOpts().Sanitize.has(SanitizerKind::Address) && AS == 0 &&
- (expr->getOperatorNew()->isReplaceableGlobalAllocationFunction() ||
- CGM.getCodeGenOpts().SanitizeAddressPoisonCustomArrayCookie)) {
- // The store to the CookiePtr does not need to be instrumented.
- CGM.getSanitizerMetadata()->disableSanitizerForInstruction(SI);
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, NumElementsPtr.getType(), false);
- llvm::Constant *F =
- CGM.CreateRuntimeFunction(FTy, "__asan_poison_cxx_array_cookie");
- CGF.Builder.CreateCall(F, NumElementsPtr.getPointer());
- }
-
- // Finally, compute a pointer to the actual data buffer by skipping
- // over the cookie completely.
- return CGF.Builder.CreateConstInBoundsByteGEP(NewPtr, CookieSize);
-}
-
-llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
- Address allocPtr,
- CharUnits cookieSize) {
- // The element size is right-justified in the cookie.
- Address numElementsPtr = allocPtr;
- CharUnits numElementsOffset = cookieSize - CGF.getSizeSize();
- if (!numElementsOffset.isZero())
- numElementsPtr =
- CGF.Builder.CreateConstInBoundsByteGEP(numElementsPtr, numElementsOffset);
-
- unsigned AS = allocPtr.getAddressSpace();
- numElementsPtr = CGF.Builder.CreateElementBitCast(numElementsPtr, CGF.SizeTy);
- if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Address) || AS != 0)
- return CGF.Builder.CreateLoad(numElementsPtr);
- // In asan mode emit a function call instead of a regular load and let the
- // run-time deal with it: if the shadow is properly poisoned return the
- // cookie, otherwise return 0 to avoid an infinite loop calling DTORs.
- // We can't simply ignore this load using nosanitize metadata because
- // the metadata may be lost.
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.SizeTy, CGF.SizeTy->getPointerTo(0), false);
- llvm::Constant *F =
- CGM.CreateRuntimeFunction(FTy, "__asan_load_cxx_array_cookie");
- return CGF.Builder.CreateCall(F, numElementsPtr.getPointer());
-}
-
-CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
- // ARM says that the cookie is always:
- // struct array_cookie {
- // std::size_t element_size; // element_size != 0
- // std::size_t element_count;
- // };
- // But the base ABI doesn't give anything an alignment greater than
- // 8, so we can dismiss this as typical ABI-author blindness to
- // actual language complexity and round up to the element alignment.
- return std::max(CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes),
- CGM.getContext().getTypeAlignInChars(elementType));
-}
-
-Address ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
- Address newPtr,
- llvm::Value *numElements,
- const CXXNewExpr *expr,
- QualType elementType) {
- assert(requiresArrayCookie(expr));
-
- // The cookie is always at the start of the buffer.
- Address cookie = newPtr;
-
- // The first element is the element size.
- cookie = CGF.Builder.CreateElementBitCast(cookie, CGF.SizeTy);
- llvm::Value *elementSize = llvm::ConstantInt::get(CGF.SizeTy,
- getContext().getTypeSizeInChars(elementType).getQuantity());
- CGF.Builder.CreateStore(elementSize, cookie);
-
- // The second element is the element count.
- cookie = CGF.Builder.CreateConstInBoundsGEP(cookie, 1, CGF.getSizeSize());
- CGF.Builder.CreateStore(numElements, cookie);
-
- // Finally, compute a pointer to the actual data buffer by skipping
- // over the cookie completely.
- CharUnits cookieSize = ARMCXXABI::getArrayCookieSizeImpl(elementType);
- return CGF.Builder.CreateConstInBoundsByteGEP(newPtr, cookieSize);
-}
-
-llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
- Address allocPtr,
- CharUnits cookieSize) {
- // The number of elements is at offset sizeof(size_t) relative to
- // the allocated pointer.
- Address numElementsPtr
- = CGF.Builder.CreateConstInBoundsByteGEP(allocPtr, CGF.getSizeSize());
-
- numElementsPtr = CGF.Builder.CreateElementBitCast(numElementsPtr, CGF.SizeTy);
- return CGF.Builder.CreateLoad(numElementsPtr);
-}
-
-/*********************** Static local initialization **************************/
-
-static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
- llvm::PointerType *GuardPtrTy) {
- // int __cxa_guard_acquire(__guard *guard_object);
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
- GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(
- FTy, "__cxa_guard_acquire",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind));
-}
-
-static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
- llvm::PointerType *GuardPtrTy) {
- // void __cxa_guard_release(__guard *guard_object);
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(
- FTy, "__cxa_guard_release",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind));
-}
-
-static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
- llvm::PointerType *GuardPtrTy) {
- // void __cxa_guard_abort(__guard *guard_object);
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(
- FTy, "__cxa_guard_abort",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind));
-}
-
-namespace {
- struct CallGuardAbort final : EHScopeStack::Cleanup {
- llvm::GlobalVariable *Guard;
- CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitNounwindRuntimeCall(getGuardAbortFn(CGF.CGM, Guard->getType()),
- Guard);
- }
- };
-}
-
-/// The ARM code here follows the Itanium code closely enough that we
-/// just special-case it at particular places.
-void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
- const VarDecl &D,
- llvm::GlobalVariable *var,
- bool shouldPerformInit) {
- CGBuilderTy &Builder = CGF.Builder;
-
- // Inline variables that weren't instantiated from variable templates have
- // partially-ordered initialization within their translation unit.
- bool NonTemplateInline =
- D.isInline() &&
- !isTemplateInstantiation(D.getTemplateSpecializationKind());
-
- // We only need to use thread-safe statics for local non-TLS variables and
- // inline variables; other global initialization is always single-threaded
- // or (through lazy dynamic loading in multiple threads) unsequenced.
- bool threadsafe = getContext().getLangOpts().ThreadsafeStatics &&
- (D.isLocalVarDecl() || NonTemplateInline) &&
- !D.getTLSKind();
-
- // If we have a global variable with internal linkage and thread-safe statics
- // are disabled, we can just let the guard variable be of type i8.
- bool useInt8GuardVariable = !threadsafe && var->hasInternalLinkage();
-
- llvm::IntegerType *guardTy;
- CharUnits guardAlignment;
- if (useInt8GuardVariable) {
- guardTy = CGF.Int8Ty;
- guardAlignment = CharUnits::One();
- } else {
- // Guard variables are 64 bits in the generic ABI and size width on ARM
- // (i.e. 32-bit on AArch32, 64-bit on AArch64).
- if (UseARMGuardVarABI) {
- guardTy = CGF.SizeTy;
- guardAlignment = CGF.getSizeAlign();
- } else {
- guardTy = CGF.Int64Ty;
- guardAlignment = CharUnits::fromQuantity(
- CGM.getDataLayout().getABITypeAlignment(guardTy));
- }
- }
- llvm::PointerType *guardPtrTy = guardTy->getPointerTo();
-
- // Create the guard variable if we don't already have it (as we
- // might if we're double-emitting this function body).
- llvm::GlobalVariable *guard = CGM.getStaticLocalDeclGuardAddress(&D);
- if (!guard) {
- // Mangle the name for the guard.
- SmallString<256> guardName;
- {
- llvm::raw_svector_ostream out(guardName);
- getMangleContext().mangleStaticGuardVariable(&D, out);
- }
-
- // Create the guard variable with a zero-initializer.
- // Just absorb linkage and visibility from the guarded variable.
- guard = new llvm::GlobalVariable(CGM.getModule(), guardTy,
- false, var->getLinkage(),
- llvm::ConstantInt::get(guardTy, 0),
- guardName.str());
- guard->setDSOLocal(var->isDSOLocal());
- guard->setVisibility(var->getVisibility());
- // If the variable is thread-local, so is its guard variable.
- guard->setThreadLocalMode(var->getThreadLocalMode());
- guard->setAlignment(guardAlignment.getQuantity());
-
- // The ABI says: "It is suggested that it be emitted in the same COMDAT
- // group as the associated data object." In practice, this doesn't work for
- // non-ELF and non-Wasm object formats, so only do it for ELF and Wasm.
- llvm::Comdat *C = var->getComdat();
- if (!D.isLocalVarDecl() && C &&
- (CGM.getTarget().getTriple().isOSBinFormatELF() ||
- CGM.getTarget().getTriple().isOSBinFormatWasm())) {
- guard->setComdat(C);
- // An inline variable's guard function is run from the per-TU
- // initialization function, not via a dedicated global ctor function, so
- // we can't put it in a comdat.
- if (!NonTemplateInline)
- CGF.CurFn->setComdat(C);
- } else if (CGM.supportsCOMDAT() && guard->isWeakForLinker()) {
- guard->setComdat(CGM.getModule().getOrInsertComdat(guard->getName()));
- }
-
- CGM.setStaticLocalDeclGuardAddress(&D, guard);
- }
-
- Address guardAddr = Address(guard, guardAlignment);
-
- // Test whether the variable has completed initialization.
- //
- // Itanium C++ ABI 3.3.2:
- // The following is pseudo-code showing how these functions can be used:
- // if (obj_guard.first_byte == 0) {
- // if ( __cxa_guard_acquire (&obj_guard) ) {
- // try {
- // ... initialize the object ...;
- // } catch (...) {
- // __cxa_guard_abort (&obj_guard);
- // throw;
- // }
- // ... queue object destructor with __cxa_atexit() ...;
- // __cxa_guard_release (&obj_guard);
- // }
- // }
-
- // Load the first byte of the guard variable.
- llvm::LoadInst *LI =
- Builder.CreateLoad(Builder.CreateElementBitCast(guardAddr, CGM.Int8Ty));
-
- // Itanium ABI:
- // An implementation supporting thread-safety on multiprocessor
- // systems must also guarantee that references to the initialized
- // object do not occur before the load of the initialization flag.
- //
- // In LLVM, we do this by marking the load Acquire.
- if (threadsafe)
- LI->setAtomic(llvm::AtomicOrdering::Acquire);
-
- // For ARM, we should only check the first bit, rather than the entire byte:
- //
- // ARM C++ ABI 3.2.3.1:
- // To support the potential use of initialization guard variables
- // as semaphores that are the target of ARM SWP and LDREX/STREX
- // synchronizing instructions we define a static initialization
- // guard variable to be a 4-byte aligned, 4-byte word with the
- // following inline access protocol.
- // #define INITIALIZED 1
- // if ((obj_guard & INITIALIZED) != INITIALIZED) {
- // if (__cxa_guard_acquire(&obj_guard))
- // ...
- // }
- //
- // and similarly for ARM64:
- //
- // ARM64 C++ ABI 3.2.2:
- // This ABI instead only specifies the value bit 0 of the static guard
- // variable; all other bits are platform defined. Bit 0 shall be 0 when the
- // variable is not initialized and 1 when it is.
- llvm::Value *V =
- (UseARMGuardVarABI && !useInt8GuardVariable)
- ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1))
- : LI;
- llvm::Value *NeedsInit = Builder.CreateIsNull(V, "guard.uninitialized");
-
- llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
- llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
-
- // Check if the first byte of the guard variable is zero.
- CGF.EmitCXXGuardedInitBranch(NeedsInit, InitCheckBlock, EndBlock,
- CodeGenFunction::GuardKind::VariableGuard, &D);
-
- CGF.EmitBlock(InitCheckBlock);
-
- // Variables used when coping with thread-safe statics and exceptions.
- if (threadsafe) {
- // Call __cxa_guard_acquire.
- llvm::Value *V
- = CGF.EmitNounwindRuntimeCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
-
- llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
-
- Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
- InitBlock, EndBlock);
-
- // Call __cxa_guard_abort along the exceptional edge.
- CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, guard);
-
- CGF.EmitBlock(InitBlock);
- }
-
- // Emit the initializer and add a global destructor if appropriate.
- CGF.EmitCXXGlobalVarDeclInit(D, var, shouldPerformInit);
-
- if (threadsafe) {
- // Pop the guard-abort cleanup if we pushed one.
- CGF.PopCleanupBlock();
-
- // Call __cxa_guard_release. This cannot throw.
- CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy),
- guardAddr.getPointer());
- } else {
- Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guardAddr);
- }
-
- CGF.EmitBlock(EndBlock);
-}
-
-/// Register a global destructor using __cxa_atexit.
-static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
- llvm::Constant *dtor,
- llvm::Constant *addr,
- bool TLS) {
- const char *Name = "__cxa_atexit";
- if (TLS) {
- const llvm::Triple &T = CGF.getTarget().getTriple();
- Name = T.isOSDarwin() ? "_tlv_atexit" : "__cxa_thread_atexit";
- }
-
- // We're assuming that the destructor function is something we can
- // reasonably call with the default CC. Go ahead and cast it to the
- // right prototype.
- llvm::Type *dtorTy =
- llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, false)->getPointerTo();
-
- // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
- llvm::Type *paramTys[] = { dtorTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
- llvm::FunctionType *atexitTy =
- llvm::FunctionType::get(CGF.IntTy, paramTys, false);
-
- // Fetch the actual function.
- llvm::Constant *atexit = CGF.CGM.CreateRuntimeFunction(atexitTy, Name);
- if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit))
- fn->setDoesNotThrow();
-
- // Create a variable that binds the atexit to this shared object.
- llvm::Constant *handle =
- CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle");
- auto *GV = cast<llvm::GlobalValue>(handle->stripPointerCasts());
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
-
- if (!addr)
- // addr is null when we are trying to register a dtor annotated with
- // __attribute__((destructor)) in a constructor function. Using null here is
- // okay because this argument is just passed back to the destructor
- // function.
- addr = llvm::Constant::getNullValue(CGF.Int8PtrTy);
-
- llvm::Value *args[] = {
- llvm::ConstantExpr::getBitCast(dtor, dtorTy),
- llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy),
- handle
- };
- CGF.EmitNounwindRuntimeCall(atexit, args);
-}
-
-void CodeGenModule::registerGlobalDtorsWithAtExit() {
- for (const auto I : DtorsUsingAtExit) {
- int Priority = I.first;
- const llvm::TinyPtrVector<llvm::Function *> &Dtors = I.second;
-
- // Create a function that registers destructors that have the same priority.
- //
- // Since constructor functions are run in non-descending order of their
- // priorities, destructors are registered in non-descending order of their
- // priorities, and since destructor functions are run in the reverse order
- // of their registration, destructor functions are run in non-ascending
- // order of their priorities.
- CodeGenFunction CGF(*this);
- std::string GlobalInitFnName =
- std::string("__GLOBAL_init_") + llvm::to_string(Priority);
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- llvm::Function *GlobalInitFn = CreateGlobalInitOrDestructFunction(
- FTy, GlobalInitFnName, getTypes().arrangeNullaryFunction(),
- SourceLocation());
- ASTContext &Ctx = getContext();
- QualType ReturnTy = Ctx.VoidTy;
- QualType FunctionTy = Ctx.getFunctionType(ReturnTy, llvm::None, {});
- FunctionDecl *FD = FunctionDecl::Create(
- Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
- &Ctx.Idents.get(GlobalInitFnName), FunctionTy, nullptr, SC_Static,
- false, false);
- CGF.StartFunction(GlobalDecl(FD), ReturnTy, GlobalInitFn,
- getTypes().arrangeNullaryFunction(), FunctionArgList(),
- SourceLocation(), SourceLocation());
-
- for (auto *Dtor : Dtors) {
- // Register the destructor function calling __cxa_atexit if it is
- // available. Otherwise fall back on calling atexit.
- if (getCodeGenOpts().CXAAtExit)
- emitGlobalDtorWithCXAAtExit(CGF, Dtor, nullptr, false);
- else
- CGF.registerGlobalDtorWithAtExit(Dtor);
- }
-
- CGF.FinishFunction();
- AddGlobalCtor(GlobalInitFn, Priority, nullptr);
- }
-}
-
-/// Register a global destructor as best as we know how.
-void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
- const VarDecl &D,
- llvm::Constant *dtor,
- llvm::Constant *addr) {
- if (D.isNoDestroy(CGM.getContext()))
- return;
-
- // Use __cxa_atexit if available.
- if (CGM.getCodeGenOpts().CXAAtExit)
- return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind());
-
- if (D.getTLSKind())
- CGM.ErrorUnsupported(&D, "non-trivial TLS destruction");
-
- // In Apple kexts, we want to add a global destructor entry.
- // FIXME: shouldn't this be guarded by some variable?
- if (CGM.getLangOpts().AppleKext) {
- // Generate a global destructor entry.
- return CGM.AddCXXDtorEntry(dtor, addr);
- }
-
- CGF.registerGlobalDtorWithAtExit(D, dtor, addr);
-}
-
-static bool isThreadWrapperReplaceable(const VarDecl *VD,
- CodeGen::CodeGenModule &CGM) {
- assert(!VD->isStaticLocal() && "static local VarDecls don't need wrappers!");
- // Darwin prefers to have references to thread local variables to go through
- // the thread wrapper instead of directly referencing the backing variable.
- return VD->getTLSKind() == VarDecl::TLS_Dynamic &&
- CGM.getTarget().getTriple().isOSDarwin();
-}
-
-/// Get the appropriate linkage for the wrapper function. This is essentially
-/// the weak form of the variable's linkage; every translation unit which needs
-/// the wrapper emits a copy, and we want the linker to merge them.
-static llvm::GlobalValue::LinkageTypes
-getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {
- llvm::GlobalValue::LinkageTypes VarLinkage =
- CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false);
-
- // For internal linkage variables, we don't need an external or weak wrapper.
- if (llvm::GlobalValue::isLocalLinkage(VarLinkage))
- return VarLinkage;
-
- // If the thread wrapper is replaceable, give it appropriate linkage.
- if (isThreadWrapperReplaceable(VD, CGM))
- if (!llvm::GlobalVariable::isLinkOnceLinkage(VarLinkage) &&
- !llvm::GlobalVariable::isWeakODRLinkage(VarLinkage))
- return VarLinkage;
- return llvm::GlobalValue::WeakODRLinkage;
-}
-
-llvm::Function *
-ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
- llvm::Value *Val) {
- // Mangle the name for the thread_local wrapper function.
- SmallString<256> WrapperName;
- {
- llvm::raw_svector_ostream Out(WrapperName);
- getMangleContext().mangleItaniumThreadLocalWrapper(VD, Out);
- }
-
- // FIXME: If VD is a definition, we should regenerate the function attributes
- // before returning.
- if (llvm::Value *V = CGM.getModule().getNamedValue(WrapperName))
- return cast<llvm::Function>(V);
-
- QualType RetQT = VD->getType();
- if (RetQT->isReferenceType())
- RetQT = RetQT.getNonReferenceType();
-
- const CGFunctionInfo &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
- getContext().getPointerType(RetQT), FunctionArgList());
-
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *Wrapper =
- llvm::Function::Create(FnTy, getThreadLocalWrapperLinkage(VD, CGM),
- WrapperName.str(), &CGM.getModule());
-
- CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, Wrapper);
-
- if (VD->hasDefinition())
- CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Wrapper);
-
- // Always resolve references to the wrapper at link time.
- if (!Wrapper->hasLocalLinkage())
- if (!isThreadWrapperReplaceable(VD, CGM) ||
- llvm::GlobalVariable::isLinkOnceLinkage(Wrapper->getLinkage()) ||
- llvm::GlobalVariable::isWeakODRLinkage(Wrapper->getLinkage()) ||
- VD->getVisibility() == HiddenVisibility)
- Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
-
- if (isThreadWrapperReplaceable(VD, CGM)) {
- Wrapper->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
- Wrapper->addFnAttr(llvm::Attribute::NoUnwind);
- }
- return Wrapper;
-}
-
-void ItaniumCXXABI::EmitThreadLocalInitFuncs(
- CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
- ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {
- llvm::Function *InitFunc = nullptr;
-
- // Separate initializers into those with ordered (or partially-ordered)
- // initialization and those with unordered initialization.
- llvm::SmallVector<llvm::Function *, 8> OrderedInits;
- llvm::SmallDenseMap<const VarDecl *, llvm::Function *> UnorderedInits;
- for (unsigned I = 0; I != CXXThreadLocalInits.size(); ++I) {
- if (isTemplateInstantiation(
- CXXThreadLocalInitVars[I]->getTemplateSpecializationKind()))
- UnorderedInits[CXXThreadLocalInitVars[I]->getCanonicalDecl()] =
- CXXThreadLocalInits[I];
- else
- OrderedInits.push_back(CXXThreadLocalInits[I]);
- }
-
- if (!OrderedInits.empty()) {
- // Generate a guarded initialization function.
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
- const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
- InitFunc = CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init", FI,
- SourceLocation(),
- /*TLS=*/true);
- llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,
- llvm::GlobalVariable::InternalLinkage,
- llvm::ConstantInt::get(CGM.Int8Ty, 0), "__tls_guard");
- Guard->setThreadLocal(true);
-
- CharUnits GuardAlign = CharUnits::One();
- Guard->setAlignment(GuardAlign.getQuantity());
-
- CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(
- InitFunc, OrderedInits, ConstantAddress(Guard, GuardAlign));
- // On Darwin platforms, use CXX_FAST_TLS calling convention.
- if (CGM.getTarget().getTriple().isOSDarwin()) {
- InitFunc->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
- InitFunc->addFnAttr(llvm::Attribute::NoUnwind);
- }
- }
-
- // Emit thread wrappers.
- for (const VarDecl *VD : CXXThreadLocals) {
- llvm::GlobalVariable *Var =
- cast<llvm::GlobalVariable>(CGM.GetGlobalValue(CGM.getMangledName(VD)));
- llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var);
-
- // Some targets require that all access to thread local variables go through
- // the thread wrapper. This means that we cannot attempt to create a thread
- // wrapper or a thread helper.
- if (isThreadWrapperReplaceable(VD, CGM) && !VD->hasDefinition()) {
- Wrapper->setLinkage(llvm::Function::ExternalLinkage);
- continue;
- }
-
- // Mangle the name for the thread_local initialization function.
- SmallString<256> InitFnName;
- {
- llvm::raw_svector_ostream Out(InitFnName);
- getMangleContext().mangleItaniumThreadLocalInit(VD, Out);
- }
-
- // If we have a definition for the variable, emit the initialization
- // function as an alias to the global Init function (if any). Otherwise,
- // produce a declaration of the initialization function.
- llvm::GlobalValue *Init = nullptr;
- bool InitIsInitFunc = false;
- if (VD->hasDefinition()) {
- InitIsInitFunc = true;
- llvm::Function *InitFuncToUse = InitFunc;
- if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
- InitFuncToUse = UnorderedInits.lookup(VD->getCanonicalDecl());
- if (InitFuncToUse)
- Init = llvm::GlobalAlias::create(Var->getLinkage(), InitFnName.str(),
- InitFuncToUse);
- } else {
- // Emit a weak global function referring to the initialization function.
- // This function will not exist if the TU defining the thread_local
- // variable in question does not need any dynamic initialization for
- // its thread_local variables.
- llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, false);
- Init = llvm::Function::Create(FnTy,
- llvm::GlobalVariable::ExternalWeakLinkage,
- InitFnName.str(), &CGM.getModule());
- const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
- CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI,
- cast<llvm::Function>(Init));
- }
-
- if (Init) {
- Init->setVisibility(Var->getVisibility());
- Init->setDSOLocal(Var->isDSOLocal());
- }
-
- llvm::LLVMContext &Context = CGM.getModule().getContext();
- llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper);
- CGBuilderTy Builder(CGM, Entry);
- if (InitIsInitFunc) {
- if (Init) {
- llvm::CallInst *CallVal = Builder.CreateCall(Init);
- if (isThreadWrapperReplaceable(VD, CGM)) {
- CallVal->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
- llvm::Function *Fn =
- cast<llvm::Function>(cast<llvm::GlobalAlias>(Init)->getAliasee());
- Fn->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
- }
- }
- } else {
- // Don't know whether we have an init function. Call it if it exists.
- llvm::Value *Have = Builder.CreateIsNotNull(Init);
- llvm::BasicBlock *InitBB = llvm::BasicBlock::Create(Context, "", Wrapper);
- llvm::BasicBlock *ExitBB = llvm::BasicBlock::Create(Context, "", Wrapper);
- Builder.CreateCondBr(Have, InitBB, ExitBB);
-
- Builder.SetInsertPoint(InitBB);
- Builder.CreateCall(Init);
- Builder.CreateBr(ExitBB);
-
- Builder.SetInsertPoint(ExitBB);
- }
-
- // For a reference, the result of the wrapper function is a pointer to
- // the referenced object.
- llvm::Value *Val = Var;
- if (VD->getType()->isReferenceType()) {
- CharUnits Align = CGM.getContext().getDeclAlign(VD);
- Val = Builder.CreateAlignedLoad(Val, Align);
- }
- if (Val->getType() != Wrapper->getReturnType())
- Val = Builder.CreatePointerBitCastOrAddrSpaceCast(
- Val, Wrapper->getReturnType(), "");
- Builder.CreateRet(Val);
- }
-}
-
-LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
- const VarDecl *VD,
- QualType LValType) {
- llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD);
- llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val);
-
- llvm::CallInst *CallVal = CGF.Builder.CreateCall(Wrapper);
- CallVal->setCallingConv(Wrapper->getCallingConv());
-
- LValue LV;
- if (VD->getType()->isReferenceType())
- LV = CGF.MakeNaturalAlignAddrLValue(CallVal, LValType);
- else
- LV = CGF.MakeAddrLValue(CallVal, LValType,
- CGF.getContext().getDeclAlign(VD));
- // FIXME: need setObjCGCLValueClass?
- return LV;
-}
-
-/// Return whether the given global decl needs a VTT parameter, which it does
-/// if it's a base constructor or destructor with virtual bases.
-bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // We don't have any virtual bases, just return early.
- if (!MD->getParent()->getNumVBases())
- return false;
-
- // Check if we have a base constructor.
- if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
- return true;
-
- // Check if we have a base destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
- return true;
-
- return false;
-}
-
-namespace {
-class ItaniumRTTIBuilder {
- CodeGenModule &CGM; // Per-module state.
- llvm::LLVMContext &VMContext;
- const ItaniumCXXABI &CXXABI; // Per-module state.
-
- /// Fields - The fields of the RTTI descriptor currently being built.
- SmallVector<llvm::Constant *, 16> Fields;
-
- /// GetAddrOfTypeName - Returns the mangled type name of the given type.
- llvm::GlobalVariable *
- GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage);
-
- /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
- /// descriptor of the given type.
- llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
-
- /// BuildVTablePointer - Build the vtable pointer for the given type.
- void BuildVTablePointer(const Type *Ty);
-
- /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
- /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
- void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
-
- /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
- /// classes with bases that do not satisfy the abi::__si_class_type_info
- /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
- void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
-
- /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
- /// for pointer types.
- void BuildPointerTypeInfo(QualType PointeeTy);
-
- /// BuildObjCObjectTypeInfo - Build the appropriate kind of
- /// type_info for an object type.
- void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty);
-
- /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
- /// struct, used for member pointer types.
- void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);
-
-public:
- ItaniumRTTIBuilder(const ItaniumCXXABI &ABI)
- : CGM(ABI.CGM), VMContext(CGM.getModule().getContext()), CXXABI(ABI) {}
-
- // Pointer type info flags.
- enum {
- /// PTI_Const - Type has const qualifier.
- PTI_Const = 0x1,
-
- /// PTI_Volatile - Type has volatile qualifier.
- PTI_Volatile = 0x2,
-
- /// PTI_Restrict - Type has restrict qualifier.
- PTI_Restrict = 0x4,
-
- /// PTI_Incomplete - Type is incomplete.
- PTI_Incomplete = 0x8,
-
- /// PTI_ContainingClassIncomplete - Containing class is incomplete.
- /// (in pointer to member).
- PTI_ContainingClassIncomplete = 0x10,
-
- /// PTI_TransactionSafe - Pointee is transaction_safe function (C++ TM TS).
- //PTI_TransactionSafe = 0x20,
-
- /// PTI_Noexcept - Pointee is noexcept function (C++1z).
- PTI_Noexcept = 0x40,
- };
-
- // VMI type info flags.
- enum {
- /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
- VMI_NonDiamondRepeat = 0x1,
-
- /// VMI_DiamondShaped - Class is diamond shaped.
- VMI_DiamondShaped = 0x2
- };
-
- // Base class type info flags.
- enum {
- /// BCTI_Virtual - Base class is virtual.
- BCTI_Virtual = 0x1,
-
- /// BCTI_Public - Base class is public.
- BCTI_Public = 0x2
- };
-
- /// BuildTypeInfo - Build the RTTI type info struct for the given type, or
- /// link to an existing RTTI descriptor if one already exists.
- llvm::Constant *BuildTypeInfo(QualType Ty);
-
- /// BuildTypeInfo - Build the RTTI type info struct for the given type.
- llvm::Constant *BuildTypeInfo(
- QualType Ty,
- llvm::GlobalVariable::LinkageTypes Linkage,
- llvm::GlobalValue::VisibilityTypes Visibility,
- llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass);
-};
-}
-
-llvm::GlobalVariable *ItaniumRTTIBuilder::GetAddrOfTypeName(
- QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage) {
- SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
-
- // We know that the mangled name of the type starts at index 4 of the
- // mangled name of the typename, so we can just index into it in order to
- // get the mangled name of the type.
- llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext,
- Name.substr(4));
- auto Align = CGM.getContext().getTypeAlignInChars(CGM.getContext().CharTy);
-
- llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name, Init->getType(), Linkage, Align.getQuantity());
-
- GV->setInitializer(Init);
-
- return GV;
-}
-
-llvm::Constant *
-ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
- // Mangle the RTTI name.
- SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
-
- // Look for an existing global.
- llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
-
- if (!GV) {
- // Create a new global variable.
- // Note for the future: If we would ever like to do deferred emission of
- // RTTI, check if emitting vtables opportunistically need any adjustment.
-
- GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
- /*Constant=*/true,
- llvm::GlobalValue::ExternalLinkage, nullptr,
- Name);
- const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- CGM.setGVProperties(GV, RD);
- }
-
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-}
-
-/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
-/// info for that type is defined in the standard library.
-static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
- // Itanium C++ ABI 2.9.2:
- // Basic type information (e.g. for "int", "bool", etc.) will be kept in
- // the run-time support library. Specifically, the run-time support
- // library should contain type_info objects for the types X, X* and
- // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
- // unsigned char, signed char, short, unsigned short, int, unsigned int,
- // long, unsigned long, long long, unsigned long long, float, double,
- // long double, char16_t, char32_t, and the IEEE 754r decimal and
- // half-precision floating point types.
- //
- // GCC also emits RTTI for __int128.
- // FIXME: We do not emit RTTI information for decimal types here.
-
- // Types added here must also be added to EmitFundamentalRTTIDescriptors.
- switch (Ty->getKind()) {
- case BuiltinType::Void:
- case BuiltinType::NullPtr:
- case BuiltinType::Bool:
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- case BuiltinType::Char_U:
- case BuiltinType::Char_S:
- case BuiltinType::UChar:
- case BuiltinType::SChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::Int:
- case BuiltinType::UInt:
- case BuiltinType::Long:
- case BuiltinType::ULong:
- case BuiltinType::LongLong:
- case BuiltinType::ULongLong:
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
- case BuiltinType::Float16:
- case BuiltinType::Float128:
- case BuiltinType::Char8:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::Int128:
- case BuiltinType::UInt128:
- return true;
-
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id:
-#include "clang/Basic/OpenCLImageTypes.def"
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- case BuiltinType::Id:
-#include "clang/Basic/OpenCLExtensionTypes.def"
- case BuiltinType::OCLSampler:
- case BuiltinType::OCLEvent:
- case BuiltinType::OCLClkEvent:
- case BuiltinType::OCLQueue:
- case BuiltinType::OCLReserveID:
- case BuiltinType::ShortAccum:
- case BuiltinType::Accum:
- case BuiltinType::LongAccum:
- case BuiltinType::UShortAccum:
- case BuiltinType::UAccum:
- case BuiltinType::ULongAccum:
- case BuiltinType::ShortFract:
- case BuiltinType::Fract:
- case BuiltinType::LongFract:
- case BuiltinType::UShortFract:
- case BuiltinType::UFract:
- case BuiltinType::ULongFract:
- case BuiltinType::SatShortAccum:
- case BuiltinType::SatAccum:
- case BuiltinType::SatLongAccum:
- case BuiltinType::SatUShortAccum:
- case BuiltinType::SatUAccum:
- case BuiltinType::SatULongAccum:
- case BuiltinType::SatShortFract:
- case BuiltinType::SatFract:
- case BuiltinType::SatLongFract:
- case BuiltinType::SatUShortFract:
- case BuiltinType::SatUFract:
- case BuiltinType::SatULongFract:
- return false;
-
- case BuiltinType::Dependent:
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- llvm_unreachable("asking for RRTI for a placeholder type!");
-
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- llvm_unreachable("FIXME: Objective-C types are unsupported!");
- }
-
- llvm_unreachable("Invalid BuiltinType Kind!");
-}
-
-static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
- QualType PointeeTy = PointerTy->getPointeeType();
- const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy);
- if (!BuiltinTy)
- return false;
-
- // Check the qualifiers.
- Qualifiers Quals = PointeeTy.getQualifiers();
- Quals.removeConst();
-
- if (!Quals.empty())
- return false;
-
- return TypeInfoIsInStandardLibrary(BuiltinTy);
-}
-
-/// IsStandardLibraryRTTIDescriptor - Returns whether the type
-/// information for the given type exists in the standard library.
-static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
- // Type info for builtin types is defined in the standard library.
- if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
- return TypeInfoIsInStandardLibrary(BuiltinTy);
-
- // Type info for some pointer types to builtin types is defined in the
- // standard library.
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return TypeInfoIsInStandardLibrary(PointerTy);
-
- return false;
-}
-
-/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
-/// the given type exists somewhere else, and that we should not emit the type
-/// information in this translation unit. Assumes that it is not a
-/// standard-library type.
-static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
- QualType Ty) {
- ASTContext &Context = CGM.getContext();
-
- // If RTTI is disabled, assume it might be disabled in the
- // translation unit that defines any potential key function, too.
- if (!Context.getLangOpts().RTTI) return false;
-
- if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!RD->hasDefinition())
- return false;
-
- if (!RD->isDynamicClass())
- return false;
-
- // FIXME: this may need to be reconsidered if the key function
- // changes.
- // N.B. We must always emit the RTTI data ourselves if there exists a key
- // function.
- bool IsDLLImport = RD->hasAttr<DLLImportAttr>();
-
- // Don't import the RTTI but emit it locally.
- if (CGM.getTriple().isWindowsGNUEnvironment() && IsDLLImport)
- return false;
-
- if (CGM.getVTables().isVTableExternal(RD))
- return IsDLLImport && !CGM.getTriple().isWindowsItaniumEnvironment()
- ? false
- : true;
-
- if (IsDLLImport)
- return true;
- }
-
- return false;
-}
-
-/// IsIncompleteClassType - Returns whether the given record type is incomplete.
-static bool IsIncompleteClassType(const RecordType *RecordTy) {
- return !RecordTy->getDecl()->isCompleteDefinition();
-}
-
-/// ContainsIncompleteClassType - Returns whether the given type contains an
-/// incomplete class type. This is true if
-///
-/// * The given type is an incomplete class type.
-/// * The given type is a pointer type whose pointee type contains an
-/// incomplete class type.
-/// * The given type is a member pointer type whose class is an incomplete
-/// class type.
-/// * The given type is a member pointer type whoise pointee type contains an
-/// incomplete class type.
-/// is an indirect or direct pointer to an incomplete class type.
-static bool ContainsIncompleteClassType(QualType Ty) {
- if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- if (IsIncompleteClassType(RecordTy))
- return true;
- }
-
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return ContainsIncompleteClassType(PointerTy->getPointeeType());
-
- if (const MemberPointerType *MemberPointerTy =
- dyn_cast<MemberPointerType>(Ty)) {
- // Check if the class type is incomplete.
- const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
- if (IsIncompleteClassType(ClassType))
- return true;
-
- return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
- }
-
- return false;
-}
-
-// CanUseSingleInheritance - Return whether the given record decl has a "single,
-// public, non-virtual base at offset zero (i.e. the derived class is dynamic
-// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
-static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
- // Check the number of bases.
- if (RD->getNumBases() != 1)
- return false;
-
- // Get the base.
- CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin();
-
- // Check that the base is not virtual.
- if (Base->isVirtual())
- return false;
-
- // Check that the base is public.
- if (Base->getAccessSpecifier() != AS_public)
- return false;
-
- // Check that the class is dynamic iff the base is.
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseDecl->isEmpty() &&
- BaseDecl->isDynamicClass() != RD->isDynamicClass())
- return false;
-
- return true;
-}
-
-void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
- // abi::__class_type_info.
- static const char * const ClassTypeInfo =
- "_ZTVN10__cxxabiv117__class_type_infoE";
- // abi::__si_class_type_info.
- static const char * const SIClassTypeInfo =
- "_ZTVN10__cxxabiv120__si_class_type_infoE";
- // abi::__vmi_class_type_info.
- static const char * const VMIClassTypeInfo =
- "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
-
- const char *VTableName = nullptr;
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- llvm_unreachable("Undeduced type shouldn't get here");
-
- case Type::Pipe:
- llvm_unreachable("Pipe types shouldn't get here");
-
- case Type::Builtin:
- // GCC treats vector and complex types as fundamental types.
- case Type::Vector:
- case Type::ExtVector:
- case Type::Complex:
- case Type::Atomic:
- // FIXME: GCC treats block pointers as fundamental types?!
- case Type::BlockPointer:
- // abi::__fundamental_type_info.
- VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
- break;
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // abi::__array_type_info.
- VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // abi::__function_type_info.
- VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
- break;
-
- case Type::Enum:
- // abi::__enum_type_info.
- VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
-
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- VTableName = ClassTypeInfo;
- } else if (CanUseSingleInheritance(RD)) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = VMIClassTypeInfo;
- }
-
- break;
- }
-
- case Type::ObjCObject:
- // Ignore protocol qualifiers.
- Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
-
- // Handle id and Class.
- if (isa<BuiltinType>(Ty)) {
- VTableName = ClassTypeInfo;
- break;
- }
-
- assert(isa<ObjCInterfaceType>(Ty));
- LLVM_FALLTHROUGH;
-
- case Type::ObjCInterface:
- if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = ClassTypeInfo;
- }
- break;
-
- case Type::ObjCObjectPointer:
- case Type::Pointer:
- // abi::__pointer_type_info.
- VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
- break;
-
- case Type::MemberPointer:
- // abi::__pointer_to_member_type_info.
- VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
- break;
- }
-
- llvm::Constant *VTable =
- CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy);
- CGM.setDSOLocal(cast<llvm::GlobalValue>(VTable->stripPointerCasts()));
-
- llvm::Type *PtrDiffTy =
- CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
-
- // The vtable address point is 2.
- llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
- VTable =
- llvm::ConstantExpr::getInBoundsGetElementPtr(CGM.Int8PtrTy, VTable, Two);
- VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy);
-
- Fields.push_back(VTable);
-}
-
-/// Return the linkage that the type info and type info name constants
-/// should have for the given type.
-static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
- QualType Ty) {
- // Itanium C++ ABI 2.9.5p7:
- // In addition, it and all of the intermediate abi::__pointer_type_info
- // structs in the chain down to the abi::__class_type_info for the
- // incomplete class type must be prevented from resolving to the
- // corresponding type_info structs for the complete class type, possibly
- // by making them local static objects. Finally, a dummy class RTTI is
- // generated for the incomplete type that will not resolve to the final
- // complete class RTTI (because the latter need not exist), possibly by
- // making it a local static object.
- if (ContainsIncompleteClassType(Ty))
- return llvm::GlobalValue::InternalLinkage;
-
- switch (Ty->getLinkage()) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
- return llvm::GlobalValue::InternalLinkage;
-
- case VisibleNoLinkage:
- case ModuleInternalLinkage:
- case ModuleLinkage:
- case ExternalLinkage:
- // RTTI is not enabled, which means that this type info struct is going
- // to be used for exception handling. Give it linkonce_odr linkage.
- if (!CGM.getLangOpts().RTTI)
- return llvm::GlobalValue::LinkOnceODRLinkage;
-
- if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- if (RD->hasAttr<WeakAttr>())
- return llvm::GlobalValue::WeakODRLinkage;
- if (CGM.getTriple().isWindowsItaniumEnvironment())
- if (RD->hasAttr<DLLImportAttr>() &&
- ShouldUseExternalRTTIDescriptor(CGM, Ty))
- return llvm::GlobalValue::ExternalLinkage;
- // MinGW always uses LinkOnceODRLinkage for type info.
- if (RD->isDynamicClass() &&
- !CGM.getContext()
- .getTargetInfo()
- .getTriple()
- .isWindowsGNUEnvironment())
- return CGM.getVTableLinkage(RD);
- }
-
- return llvm::GlobalValue::LinkOnceODRLinkage;
- }
-
- llvm_unreachable("Invalid linkage!");
-}
-
-llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {
- // We want to operate on the canonical type.
- Ty = Ty.getCanonicalType();
-
- // Check if we've already emitted an RTTI descriptor for this type.
- SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
-
- llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
- if (OldGV && !OldGV->isDeclaration()) {
- assert(!OldGV->hasAvailableExternallyLinkage() &&
- "available_externally typeinfos not yet implemented");
-
- return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy);
- }
-
- // Check if there is already an external RTTI descriptor for this type.
- if (IsStandardLibraryRTTIDescriptor(Ty) ||
- ShouldUseExternalRTTIDescriptor(CGM, Ty))
- return GetAddrOfExternalRTTIDescriptor(Ty);
-
- // Emit the standard library with external linkage.
- llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty);
-
- // Give the type_info object and name the formal visibility of the
- // type itself.
- llvm::GlobalValue::VisibilityTypes llvmVisibility;
- if (llvm::GlobalValue::isLocalLinkage(Linkage))
- // If the linkage is local, only default visibility makes sense.
- llvmVisibility = llvm::GlobalValue::DefaultVisibility;
- else if (CXXABI.classifyRTTIUniqueness(Ty, Linkage) ==
- ItaniumCXXABI::RUK_NonUniqueHidden)
- llvmVisibility = llvm::GlobalValue::HiddenVisibility;
- else
- llvmVisibility = CodeGenModule::GetLLVMVisibility(Ty->getVisibility());
-
- llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass =
- llvm::GlobalValue::DefaultStorageClass;
- if (CGM.getTriple().isWindowsItaniumEnvironment()) {
- auto RD = Ty->getAsCXXRecordDecl();
- if (RD && RD->hasAttr<DLLExportAttr>())
- DLLStorageClass = llvm::GlobalValue::DLLExportStorageClass;
- }
-
- return BuildTypeInfo(Ty, Linkage, llvmVisibility, DLLStorageClass);
-}
-
-llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
- QualType Ty,
- llvm::GlobalVariable::LinkageTypes Linkage,
- llvm::GlobalValue::VisibilityTypes Visibility,
- llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {
- // Add the vtable pointer.
- BuildVTablePointer(cast<Type>(Ty));
-
- // And the name.
- llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
- llvm::Constant *TypeNameField;
-
- // If we're supposed to demote the visibility, be sure to set a flag
- // to use a string comparison for type_info comparisons.
- ItaniumCXXABI::RTTIUniquenessKind RTTIUniqueness =
- CXXABI.classifyRTTIUniqueness(Ty, Linkage);
- if (RTTIUniqueness != ItaniumCXXABI::RUK_Unique) {
- // The flag is the sign bit, which on ARM64 is defined to be clear
- // for global pointers. This is very ARM64-specific.
- TypeNameField = llvm::ConstantExpr::getPtrToInt(TypeName, CGM.Int64Ty);
- llvm::Constant *flag =
- llvm::ConstantInt::get(CGM.Int64Ty, ((uint64_t)1) << 63);
- TypeNameField = llvm::ConstantExpr::getAdd(TypeNameField, flag);
- TypeNameField =
- llvm::ConstantExpr::getIntToPtr(TypeNameField, CGM.Int8PtrTy);
- } else {
- TypeNameField = llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy);
- }
- Fields.push_back(TypeNameField);
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- // GCC treats vector types as fundamental types.
- case Type::Builtin:
- case Type::Vector:
- case Type::ExtVector:
- case Type::Complex:
- case Type::BlockPointer:
- // Itanium C++ ABI 2.9.5p4:
- // abi::__fundamental_type_info adds no data members to std::type_info.
- break;
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- llvm_unreachable("Undeduced type shouldn't get here");
-
- case Type::Pipe:
- llvm_unreachable("Pipe type shouldn't get here");
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__array_type_info adds no data members to std::type_info.
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__function_type_info adds no data members to std::type_info.
- break;
-
- case Type::Enum:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__enum_type_info adds no data members to std::type_info.
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- // We don't need to emit any fields.
- break;
- }
-
- if (CanUseSingleInheritance(RD))
- BuildSIClassTypeInfo(RD);
- else
- BuildVMIClassTypeInfo(RD);
-
- break;
- }
-
- case Type::ObjCObject:
- case Type::ObjCInterface:
- BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty));
- break;
-
- case Type::ObjCObjectPointer:
- BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
- break;
-
- case Type::Pointer:
- BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType());
- break;
-
- case Type::MemberPointer:
- BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
- break;
-
- case Type::Atomic:
- // No fields, at least for the moment.
- break;
- }
-
- llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
-
- SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
- llvm::Module &M = CGM.getModule();
- llvm::GlobalVariable *OldGV = M.getNamedGlobal(Name);
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(M, Init->getType(),
- /*Constant=*/true, Linkage, Init, Name);
-
- // If there's already an old global variable, replace it with the new one.
- if (OldGV) {
- GV->takeName(OldGV);
- llvm::Constant *NewPtr =
- llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
- OldGV->replaceAllUsesWith(NewPtr);
- OldGV->eraseFromParent();
- }
-
- if (CGM.supportsCOMDAT() && GV->isWeakForLinker())
- GV->setComdat(M.getOrInsertComdat(GV->getName()));
-
- CharUnits Align =
- CGM.getContext().toCharUnitsFromBits(CGM.getTarget().getPointerAlign(0));
- GV->setAlignment(Align.getQuantity());
-
- // The Itanium ABI specifies that type_info objects must be globally
- // unique, with one exception: if the type is an incomplete class
- // type or a (possibly indirect) pointer to one. That exception
- // affects the general case of comparing type_info objects produced
- // by the typeid operator, which is why the comparison operators on
- // std::type_info generally use the type_info name pointers instead
- // of the object addresses. However, the language's built-in uses
- // of RTTI generally require class types to be complete, even when
- // manipulating pointers to those class types. This allows the
- // implementation of dynamic_cast to rely on address equality tests,
- // which is much faster.
-
- // All of this is to say that it's important that both the type_info
- // object and the type_info name be uniqued when weakly emitted.
-
- TypeName->setVisibility(Visibility);
- CGM.setDSOLocal(TypeName);
-
- GV->setVisibility(Visibility);
- CGM.setDSOLocal(GV);
-
- TypeName->setDLLStorageClass(DLLStorageClass);
- GV->setDLLStorageClass(DLLStorageClass);
-
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-}
-
-/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
-/// for the given Objective-C object type.
-void ItaniumRTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
- // Drop qualifiers.
- const Type *T = OT->getBaseType().getTypePtr();
- assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T));
-
- // The builtin types are abi::__class_type_infos and don't require
- // extra fields.
- if (isa<BuiltinType>(T)) return;
-
- ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl();
- ObjCInterfaceDecl *Super = Class->getSuperClass();
-
- // Root classes are also __class_type_info.
- if (!Super) return;
-
- QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super);
-
- // Everything else is single inheritance.
- llvm::Constant *BaseTypeInfo =
- ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(SuperTy);
- Fields.push_back(BaseTypeInfo);
-}
-
-/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
-/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
-void ItaniumRTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
- // Itanium C++ ABI 2.9.5p6b:
- // It adds to abi::__class_type_info a single member pointing to the
- // type_info structure for the base type,
- llvm::Constant *BaseTypeInfo =
- ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(RD->bases_begin()->getType());
- Fields.push_back(BaseTypeInfo);
-}
-
-namespace {
- /// SeenBases - Contains virtual and non-virtual bases seen when traversing
- /// a class hierarchy.
- struct SeenBases {
- llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
- llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
- };
-}
-
-/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
-/// abi::__vmi_class_type_info.
-///
-static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
- SeenBases &Bases) {
-
- unsigned Flags = 0;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (Base->isVirtual()) {
- // Mark the virtual base as seen.
- if (!Bases.VirtualBases.insert(BaseDecl).second) {
- // If this virtual base has been seen before, then the class is diamond
- // shaped.
- Flags |= ItaniumRTTIBuilder::VMI_DiamondShaped;
- } else {
- if (Bases.NonVirtualBases.count(BaseDecl))
- Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
- }
- } else {
- // Mark the non-virtual base as seen.
- if (!Bases.NonVirtualBases.insert(BaseDecl).second) {
- // If this non-virtual base has been seen before, then the class has non-
- // diamond shaped repeated inheritance.
- Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
- } else {
- if (Bases.VirtualBases.count(BaseDecl))
- Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
- }
- }
-
- // Walk all bases.
- for (const auto &I : BaseDecl->bases())
- Flags |= ComputeVMIClassTypeInfoFlags(&I, Bases);
-
- return Flags;
-}
-
-static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
- unsigned Flags = 0;
- SeenBases Bases;
-
- // Walk all bases.
- for (const auto &I : RD->bases())
- Flags |= ComputeVMIClassTypeInfoFlags(&I, Bases);
-
- return Flags;
-}
-
-/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
-/// classes with bases that do not satisfy the abi::__si_class_type_info
-/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
-void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
-
- // Itanium C++ ABI 2.9.5p6c:
- // __flags is a word with flags describing details about the class
- // structure, which may be referenced by using the __flags_masks
- // enumeration. These flags refer to both direct and indirect bases.
- unsigned Flags = ComputeVMIClassTypeInfoFlags(RD);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p6c:
- // __base_count is a word with the number of direct proper base class
- // descriptions that follow.
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases()));
-
- if (!RD->getNumBases())
- return;
-
- // Now add the base class descriptions.
-
- // Itanium C++ ABI 2.9.5p6c:
- // __base_info[] is an array of base class descriptions -- one for every
- // direct proper base. Each description is of the type:
- //
- // struct abi::__base_class_type_info {
- // public:
- // const __class_type_info *__base_type;
- // long __offset_flags;
- //
- // enum __offset_flags_masks {
- // __virtual_mask = 0x1,
- // __public_mask = 0x2,
- // __offset_shift = 8
- // };
- // };
-
- // If we're in mingw and 'long' isn't wide enough for a pointer, use 'long
- // long' instead of 'long' for __offset_flags. libstdc++abi uses long long on
- // LLP64 platforms.
- // FIXME: Consider updating libc++abi to match, and extend this logic to all
- // LLP64 platforms.
- QualType OffsetFlagsTy = CGM.getContext().LongTy;
- const TargetInfo &TI = CGM.getContext().getTargetInfo();
- if (TI.getTriple().isOSCygMing() && TI.getPointerWidth(0) > TI.getLongWidth())
- OffsetFlagsTy = CGM.getContext().LongLongTy;
- llvm::Type *OffsetFlagsLTy =
- CGM.getTypes().ConvertType(OffsetFlagsTy);
-
- for (const auto &Base : RD->bases()) {
- // The __base_type member points to the RTTI for the base type.
- Fields.push_back(ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(Base.getType()));
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
-
- int64_t OffsetFlags = 0;
-
- // All but the lower 8 bits of __offset_flags are a signed offset.
- // For a non-virtual base, this is the offset in the object of the base
- // subobject. For a virtual base, this is the offset in the virtual table of
- // the virtual base offset for the virtual base referenced (negative).
- CharUnits Offset;
- if (Base.isVirtual())
- Offset =
- CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
- else {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- Offset = Layout.getBaseClassOffset(BaseDecl);
- };
-
- OffsetFlags = uint64_t(Offset.getQuantity()) << 8;
-
- // The low-order byte of __offset_flags contains flags, as given by the
- // masks from the enumeration __offset_flags_masks.
- if (Base.isVirtual())
- OffsetFlags |= BCTI_Virtual;
- if (Base.getAccessSpecifier() == AS_public)
- OffsetFlags |= BCTI_Public;
-
- Fields.push_back(llvm::ConstantInt::get(OffsetFlagsLTy, OffsetFlags));
- }
-}
-
-/// Compute the flags for a __pbase_type_info, and remove the corresponding
-/// pieces from \p Type.
-static unsigned extractPBaseFlags(ASTContext &Ctx, QualType &Type) {
- unsigned Flags = 0;
-
- if (Type.isConstQualified())
- Flags |= ItaniumRTTIBuilder::PTI_Const;
- if (Type.isVolatileQualified())
- Flags |= ItaniumRTTIBuilder::PTI_Volatile;
- if (Type.isRestrictQualified())
- Flags |= ItaniumRTTIBuilder::PTI_Restrict;
- Type = Type.getUnqualifiedType();
-
- // Itanium C++ ABI 2.9.5p7:
- // When the abi::__pbase_type_info is for a direct or indirect pointer to an
- // incomplete class type, the incomplete target type flag is set.
- if (ContainsIncompleteClassType(Type))
- Flags |= ItaniumRTTIBuilder::PTI_Incomplete;
-
- if (auto *Proto = Type->getAs<FunctionProtoType>()) {
- if (Proto->isNothrow()) {
- Flags |= ItaniumRTTIBuilder::PTI_Noexcept;
- Type = Ctx.getFunctionTypeWithExceptionSpec(Type, EST_None);
- }
- }
-
- return Flags;
-}
-
-/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
-/// used for pointer types.
-void ItaniumRTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
- // Itanium C++ ABI 2.9.5p7:
- // __flags is a flag word describing the cv-qualification and other
- // attributes of the type pointed to
- unsigned Flags = extractPBaseFlags(CGM.getContext(), PointeeTy);
-
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p7:
- // __pointee is a pointer to the std::type_info derivation for the
- // unqualified type being pointed to.
- llvm::Constant *PointeeTypeInfo =
- ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(PointeeTy);
- Fields.push_back(PointeeTypeInfo);
-}
-
-/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
-/// struct, used for member pointer types.
-void
-ItaniumRTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
- QualType PointeeTy = Ty->getPointeeType();
-
- // Itanium C++ ABI 2.9.5p7:
- // __flags is a flag word describing the cv-qualification and other
- // attributes of the type pointed to.
- unsigned Flags = extractPBaseFlags(CGM.getContext(), PointeeTy);
-
- const RecordType *ClassType = cast<RecordType>(Ty->getClass());
- if (IsIncompleteClassType(ClassType))
- Flags |= PTI_ContainingClassIncomplete;
-
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p7:
- // __pointee is a pointer to the std::type_info derivation for the
- // unqualified type being pointed to.
- llvm::Constant *PointeeTypeInfo =
- ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(PointeeTy);
- Fields.push_back(PointeeTypeInfo);
-
- // Itanium C++ ABI 2.9.5p9:
- // __context is a pointer to an abi::__class_type_info corresponding to the
- // class type containing the member pointed to
- // (e.g., the "A" in "int A::*").
- Fields.push_back(
- ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(QualType(ClassType, 0)));
-}
-
-llvm::Constant *ItaniumCXXABI::getAddrOfRTTIDescriptor(QualType Ty) {
- return ItaniumRTTIBuilder(*this).BuildTypeInfo(Ty);
-}
-
-void ItaniumCXXABI::EmitFundamentalRTTIDescriptors(const CXXRecordDecl *RD) {
- // Types added here must also be added to TypeInfoIsInStandardLibrary.
- QualType FundamentalTypes[] = {
- getContext().VoidTy, getContext().NullPtrTy,
- getContext().BoolTy, getContext().WCharTy,
- getContext().CharTy, getContext().UnsignedCharTy,
- getContext().SignedCharTy, getContext().ShortTy,
- getContext().UnsignedShortTy, getContext().IntTy,
- getContext().UnsignedIntTy, getContext().LongTy,
- getContext().UnsignedLongTy, getContext().LongLongTy,
- getContext().UnsignedLongLongTy, getContext().Int128Ty,
- getContext().UnsignedInt128Ty, getContext().HalfTy,
- getContext().FloatTy, getContext().DoubleTy,
- getContext().LongDoubleTy, getContext().Float128Ty,
- getContext().Char8Ty, getContext().Char16Ty,
- getContext().Char32Ty
- };
- llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass =
- RD->hasAttr<DLLExportAttr>()
- ? llvm::GlobalValue::DLLExportStorageClass
- : llvm::GlobalValue::DefaultStorageClass;
- llvm::GlobalValue::VisibilityTypes Visibility =
- CodeGenModule::GetLLVMVisibility(RD->getVisibility());
- for (const QualType &FundamentalType : FundamentalTypes) {
- QualType PointerType = getContext().getPointerType(FundamentalType);
- QualType PointerTypeConst = getContext().getPointerType(
- FundamentalType.withConst());
- for (QualType Type : {FundamentalType, PointerType, PointerTypeConst})
- ItaniumRTTIBuilder(*this).BuildTypeInfo(
- Type, llvm::GlobalValue::ExternalLinkage,
- Visibility, DLLStorageClass);
- }
-}
-
-/// What sort of uniqueness rules should we use for the RTTI for the
-/// given type?
-ItaniumCXXABI::RTTIUniquenessKind ItaniumCXXABI::classifyRTTIUniqueness(
- QualType CanTy, llvm::GlobalValue::LinkageTypes Linkage) const {
- if (shouldRTTIBeUnique())
- return RUK_Unique;
-
- // It's only necessary for linkonce_odr or weak_odr linkage.
- if (Linkage != llvm::GlobalValue::LinkOnceODRLinkage &&
- Linkage != llvm::GlobalValue::WeakODRLinkage)
- return RUK_Unique;
-
- // It's only necessary with default visibility.
- if (CanTy->getVisibility() != DefaultVisibility)
- return RUK_Unique;
-
- // If we're not required to publish this symbol, hide it.
- if (Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
- return RUK_NonUniqueHidden;
-
- // If we're required to publish this symbol, as we might be under an
- // explicit instantiation, leave it with default visibility but
- // enable string-comparisons.
- assert(Linkage == llvm::GlobalValue::WeakODRLinkage);
- return RUK_NonUniqueVisible;
-}
-
-// Find out how to codegen the complete destructor and constructor
-namespace {
-enum class StructorCodegen { Emit, RAUW, Alias, COMDAT };
-}
-static StructorCodegen getCodegenToUse(CodeGenModule &CGM,
- const CXXMethodDecl *MD) {
- if (!CGM.getCodeGenOpts().CXXCtorDtorAliases)
- return StructorCodegen::Emit;
-
- // The complete and base structors are not equivalent if there are any virtual
- // bases, so emit separate functions.
- if (MD->getParent()->getNumVBases())
- return StructorCodegen::Emit;
-
- GlobalDecl AliasDecl;
- if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- AliasDecl = GlobalDecl(DD, Dtor_Complete);
- } else {
- const auto *CD = cast<CXXConstructorDecl>(MD);
- AliasDecl = GlobalDecl(CD, Ctor_Complete);
- }
- llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(AliasDecl);
-
- if (llvm::GlobalValue::isDiscardableIfUnused(Linkage))
- return StructorCodegen::RAUW;
-
- // FIXME: Should we allow available_externally aliases?
- if (!llvm::GlobalAlias::isValidLinkage(Linkage))
- return StructorCodegen::RAUW;
-
- if (llvm::GlobalValue::isWeakForLinker(Linkage)) {
- // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).
- if (CGM.getTarget().getTriple().isOSBinFormatELF() ||
- CGM.getTarget().getTriple().isOSBinFormatWasm())
- return StructorCodegen::COMDAT;
- return StructorCodegen::Emit;
- }
-
- return StructorCodegen::Alias;
-}
-
-static void emitConstructorDestructorAlias(CodeGenModule &CGM,
- GlobalDecl AliasDecl,
- GlobalDecl TargetDecl) {
- llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(AliasDecl);
-
- StringRef MangledName = CGM.getMangledName(AliasDecl);
- llvm::GlobalValue *Entry = CGM.GetGlobalValue(MangledName);
- if (Entry && !Entry->isDeclaration())
- return;
-
- auto *Aliasee = cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(TargetDecl));
-
- // Create the alias with no name.
- auto *Alias = llvm::GlobalAlias::create(Linkage, "", Aliasee);
-
- // Constructors and destructors are always unnamed_addr.
- Alias->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- // Switch any previous uses to the alias.
- if (Entry) {
- assert(Entry->getType() == Aliasee->getType() &&
- "declaration exists with different type");
- Alias->takeName(Entry);
- Entry->replaceAllUsesWith(Alias);
- Entry->eraseFromParent();
- } else {
- Alias->setName(MangledName);
- }
-
- // Finally, set up the alias with its proper name and attributes.
- CGM.SetCommonAttributes(AliasDecl, Alias);
-}
-
-void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
- StructorType Type) {
- auto *CD = dyn_cast<CXXConstructorDecl>(MD);
- const CXXDestructorDecl *DD = CD ? nullptr : cast<CXXDestructorDecl>(MD);
-
- StructorCodegen CGType = getCodegenToUse(CGM, MD);
-
- if (Type == StructorType::Complete) {
- GlobalDecl CompleteDecl;
- GlobalDecl BaseDecl;
- if (CD) {
- CompleteDecl = GlobalDecl(CD, Ctor_Complete);
- BaseDecl = GlobalDecl(CD, Ctor_Base);
- } else {
- CompleteDecl = GlobalDecl(DD, Dtor_Complete);
- BaseDecl = GlobalDecl(DD, Dtor_Base);
- }
-
- if (CGType == StructorCodegen::Alias || CGType == StructorCodegen::COMDAT) {
- emitConstructorDestructorAlias(CGM, CompleteDecl, BaseDecl);
- return;
- }
-
- if (CGType == StructorCodegen::RAUW) {
- StringRef MangledName = CGM.getMangledName(CompleteDecl);
- auto *Aliasee = CGM.GetAddrOfGlobal(BaseDecl);
- CGM.addReplacement(MangledName, Aliasee);
- return;
- }
- }
-
- // The base destructor is equivalent to the base destructor of its
- // base class if there is exactly one non-virtual base class with a
- // non-trivial destructor, there are no fields with a non-trivial
- // destructor, and the body of the destructor is trivial.
- if (DD && Type == StructorType::Base && CGType != StructorCodegen::COMDAT &&
- !CGM.TryEmitBaseDestructorAsAlias(DD))
- return;
-
- // FIXME: The deleting destructor is equivalent to the selected operator
- // delete if:
- // * either the delete is a destroying operator delete or the destructor
- // would be trivial if it weren't virtual,
- // * the conversion from the 'this' parameter to the first parameter of the
- // destructor is equivalent to a bitcast,
- // * the destructor does not have an implicit "this" return, and
- // * the operator delete has the same calling convention and IR function type
- // as the destructor.
- // In such cases we should try to emit the deleting dtor as an alias to the
- // selected 'operator delete'.
-
- llvm::Function *Fn = CGM.codegenCXXStructor(MD, Type);
-
- if (CGType == StructorCodegen::COMDAT) {
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- if (DD)
- getMangleContext().mangleCXXDtorComdat(DD, Out);
- else
- getMangleContext().mangleCXXCtorComdat(CD, Out);
- llvm::Comdat *C = CGM.getModule().getOrInsertComdat(Out.str());
- Fn->setComdat(C);
- } else {
- CGM.maybeSetTrivialComdat(*MD, *Fn);
- }
-}
-
-static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {
- // void *__cxa_begin_catch(void*);
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
-}
-
-static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
- // void __cxa_end_catch();
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
-}
-
-static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
- // void *__cxa_get_exception_ptr(void*);
- llvm::FunctionType *FTy = llvm::FunctionType::get(
- CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
-}
-
-namespace {
- /// A cleanup to call __cxa_end_catch. In many cases, the caught
- /// exception type lets us state definitively that the thrown exception
- /// type does not have a destructor. In particular:
- /// - Catch-alls tell us nothing, so we have to conservatively
- /// assume that the thrown exception might have a destructor.
- /// - Catches by reference behave according to their base types.
- /// - Catches of non-record types will only trigger for exceptions
- /// of non-record types, which never have destructors.
- /// - Catches of record types can trigger for arbitrary subclasses
- /// of the caught type, so we have to assume the actual thrown
- /// exception type might have a throwing destructor, even if the
- /// caught type's destructor is trivial or nothrow.
- struct CallEndCatch final : EHScopeStack::Cleanup {
- CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
- bool MightThrow;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- if (!MightThrow) {
- CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
- return;
- }
-
- CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
- }
- };
-}
-
-/// Emits a call to __cxa_begin_catch and enters a cleanup to call
-/// __cxa_end_catch.
-///
-/// \param EndMightThrow - true if __cxa_end_catch might throw
-static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
- llvm::Value *Exn,
- bool EndMightThrow) {
- llvm::CallInst *call =
- CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
-
- CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
-
- return call;
-}
-
-/// A "special initializer" callback for initializing a catch
-/// parameter during catch initialization.
-static void InitCatchParam(CodeGenFunction &CGF,
- const VarDecl &CatchParam,
- Address ParamAddr,
- SourceLocation Loc) {
- // Load the exception from where the landing pad saved it.
- llvm::Value *Exn = CGF.getExceptionFromSlot();
-
- CanQualType CatchType =
- CGF.CGM.getContext().getCanonicalType(CatchParam.getType());
- llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);
-
- // If we're catching by reference, we can just cast the object
- // pointer to the appropriate pointer.
- if (isa<ReferenceType>(CatchType)) {
- QualType CaughtType = cast<ReferenceType>(CatchType)->getPointeeType();
- bool EndCatchMightThrow = CaughtType->isRecordType();
-
- // __cxa_begin_catch returns the adjusted object pointer.
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);
-
- // We have no way to tell the personality function that we're
- // catching by reference, so if we're catching a pointer,
- // __cxa_begin_catch will actually return that pointer by value.
- if (const PointerType *PT = dyn_cast<PointerType>(CaughtType)) {
- QualType PointeeType = PT->getPointeeType();
-
- // When catching by reference, generally we should just ignore
- // this by-value pointer and use the exception object instead.
- if (!PointeeType->isRecordType()) {
-
- // Exn points to the struct _Unwind_Exception header, which
- // we have to skip past in order to reach the exception data.
- unsigned HeaderSize =
- CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();
- AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);
-
- // However, if we're catching a pointer-to-record type that won't
- // work, because the personality function might have adjusted
- // the pointer. There's actually no way for us to fully satisfy
- // the language/ABI contract here: we can't use Exn because it
- // might have the wrong adjustment, but we can't use the by-value
- // pointer because it's off by a level of abstraction.
- //
- // The current solution is to dump the adjusted pointer into an
- // alloca, which breaks language semantics (because changing the
- // pointer doesn't change the exception) but at least works.
- // The better solution would be to filter out non-exact matches
- // and rethrow them, but this is tricky because the rethrow
- // really needs to be catchable by other sites at this landing
- // pad. The best solution is to fix the personality function.
- } else {
- // Pull the pointer for the reference type off.
- llvm::Type *PtrTy =
- cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
-
- // Create the temporary and write the adjusted pointer into it.
- Address ExnPtrTmp =
- CGF.CreateTempAlloca(PtrTy, CGF.getPointerAlign(), "exn.byref.tmp");
- llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
- CGF.Builder.CreateStore(Casted, ExnPtrTmp);
-
- // Bind the reference to the temporary.
- AdjustedExn = ExnPtrTmp.getPointer();
- }
- }
-
- llvm::Value *ExnCast =
- CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
- CGF.Builder.CreateStore(ExnCast, ParamAddr);
- return;
- }
-
- // Scalars and complexes.
- TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
- if (TEK != TEK_Aggregate) {
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
-
- // If the catch type is a pointer type, __cxa_begin_catch returns
- // the pointer by value.
- if (CatchType->hasPointerRepresentation()) {
- llvm::Value *CastExn =
- CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");
-
- switch (CatchType.getQualifiers().getObjCLifetime()) {
- case Qualifiers::OCL_Strong:
- CastExn = CGF.EmitARCRetainNonBlock(CastExn);
- LLVM_FALLTHROUGH;
-
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- CGF.Builder.CreateStore(CastExn, ParamAddr);
- return;
-
- case Qualifiers::OCL_Weak:
- CGF.EmitARCInitWeak(ParamAddr, CastExn);
- return;
- }
- llvm_unreachable("bad ownership qualifier!");
- }
-
- // Otherwise, it returns a pointer into the exception object.
-
- llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
- llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
-
- LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
- LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType);
- switch (TEK) {
- case TEK_Complex:
- CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,
- /*init*/ true);
- return;
- case TEK_Scalar: {
- llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);
- CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
- return;
- }
- case TEK_Aggregate:
- llvm_unreachable("evaluation kind filtered out!");
- }
- llvm_unreachable("bad evaluation kind");
- }
-
- assert(isa<RecordType>(CatchType) && "unexpected catch type!");
- auto catchRD = CatchType->getAsCXXRecordDecl();
- CharUnits caughtExnAlignment = CGF.CGM.getClassPointerAlignment(catchRD);
-
- llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
-
- // Check for a copy expression. If we don't have a copy expression,
- // that means a trivial copy is okay.
- const Expr *copyExpr = CatchParam.getInit();
- if (!copyExpr) {
- llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);
- Address adjustedExn(CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy),
- caughtExnAlignment);
- LValue Dest = CGF.MakeAddrLValue(ParamAddr, CatchType);
- LValue Src = CGF.MakeAddrLValue(adjustedExn, CatchType);
- CGF.EmitAggregateCopy(Dest, Src, CatchType, AggValueSlot::DoesNotOverlap);
- return;
- }
-
- // We have to call __cxa_get_exception_ptr to get the adjusted
- // pointer before copying.
- llvm::CallInst *rawAdjustedExn =
- CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
-
- // Cast that to the appropriate type.
- Address adjustedExn(CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy),
- caughtExnAlignment);
-
- // The copy expression is defined in terms of an OpaqueValueExpr.
- // Find it and map it to the adjusted expression.
- CodeGenFunction::OpaqueValueMapping
- opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),
- CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));
-
- // Call the copy ctor in a terminate scope.
- CGF.EHStack.pushTerminate();
-
- // Perform the copy construction.
- CGF.EmitAggExpr(copyExpr,
- AggValueSlot::forAddr(ParamAddr, Qualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap));
-
- // Leave the terminate scope.
- CGF.EHStack.popTerminate();
-
- // Undo the opaque value mapping.
- opaque.pop();
-
- // Finally we can call __cxa_begin_catch.
- CallBeginCatch(CGF, Exn, true);
-}
-
-/// Begins a catch statement by initializing the catch variable and
-/// calling __cxa_begin_catch.
-void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,
- const CXXCatchStmt *S) {
- // We have to be very careful with the ordering of cleanups here:
- // C++ [except.throw]p4:
- // The destruction [of the exception temporary] occurs
- // immediately after the destruction of the object declared in
- // the exception-declaration in the handler.
- //
- // So the precise ordering is:
- // 1. Construct catch variable.
- // 2. __cxa_begin_catch
- // 3. Enter __cxa_end_catch cleanup
- // 4. Enter dtor cleanup
- //
- // We do this by using a slightly abnormal initialization process.
- // Delegation sequence:
- // - ExitCXXTryStmt opens a RunCleanupsScope
- // - EmitAutoVarAlloca creates the variable and debug info
- // - InitCatchParam initializes the variable from the exception
- // - CallBeginCatch calls __cxa_begin_catch
- // - CallBeginCatch enters the __cxa_end_catch cleanup
- // - EmitAutoVarCleanups enters the variable destructor cleanup
- // - EmitCXXTryStmt emits the code for the catch body
- // - EmitCXXTryStmt close the RunCleanupsScope
-
- VarDecl *CatchParam = S->getExceptionDecl();
- if (!CatchParam) {
- llvm::Value *Exn = CGF.getExceptionFromSlot();
- CallBeginCatch(CGF, Exn, true);
- return;
- }
-
- // Emit the local.
- CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
- InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF), S->getBeginLoc());
- CGF.EmitAutoVarCleanups(var);
-}
-
-/// Get or define the following function:
-/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
-/// This code is used only in C++.
-static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
- llvm::FunctionType *fnTy =
- llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- llvm::Constant *fnRef = CGM.CreateRuntimeFunction(
- fnTy, "__clang_call_terminate", llvm::AttributeList(), /*Local=*/true);
-
- llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
- if (fn && fn->empty()) {
- fn->setDoesNotThrow();
- fn->setDoesNotReturn();
-
- // What we really want is to massively penalize inlining without
- // forbidding it completely. The difference between that and
- // 'noinline' is negligible.
- fn->addFnAttr(llvm::Attribute::NoInline);
-
- // Allow this function to be shared across translation units, but
- // we don't want it to turn into an exported symbol.
- fn->setLinkage(llvm::Function::LinkOnceODRLinkage);
- fn->setVisibility(llvm::Function::HiddenVisibility);
- if (CGM.supportsCOMDAT())
- fn->setComdat(CGM.getModule().getOrInsertComdat(fn->getName()));
-
- // Set up the function.
- llvm::BasicBlock *entry =
- llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);
- CGBuilderTy builder(CGM, entry);
-
- // Pull the exception pointer out of the parameter list.
- llvm::Value *exn = &*fn->arg_begin();
-
- // Call __cxa_begin_catch(exn).
- llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);
- catchCall->setDoesNotThrow();
- catchCall->setCallingConv(CGM.getRuntimeCC());
-
- // Call std::terminate().
- llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn());
- termCall->setDoesNotThrow();
- termCall->setDoesNotReturn();
- termCall->setCallingConv(CGM.getRuntimeCC());
-
- // std::terminate cannot return.
- builder.CreateUnreachable();
- }
-
- return fnRef;
-}
-
-llvm::CallInst *
-ItaniumCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
- llvm::Value *Exn) {
- // In C++, we want to call __cxa_begin_catch() before terminating.
- if (Exn) {
- assert(CGF.CGM.getLangOpts().CPlusPlus);
- return CGF.EmitNounwindRuntimeCall(getClangCallTerminateFn(CGF.CGM), Exn);
- }
- return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());
-}
-
-std::pair<llvm::Value *, const CXXRecordDecl *>
-ItaniumCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This,
- const CXXRecordDecl *RD) {
- return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD};
-}
-
-void WebAssemblyCXXABI::emitBeginCatch(CodeGenFunction &CGF,
- const CXXCatchStmt *C) {
- if (CGF.getTarget().hasFeature("exception-handling"))
- CGF.EHStack.pushCleanup<CatchRetScope>(
- NormalCleanup, cast<llvm::CatchPadInst>(CGF.CurrentFuncletPad));
- ItaniumCXXABI::emitBeginCatch(CGF, C);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp b/gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp
deleted file mode 100644
index 013ca15e239..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-//===--- MacroPPCallbacks.cpp ---------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains implementation for the macro preprocessors callbacks.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MacroPPCallbacks.h"
-#include "CGDebugInfo.h"
-#include "clang/CodeGen/ModuleBuilder.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/Preprocessor.h"
-
-using namespace clang;
-
-void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
- const MacroInfo &MI,
- Preprocessor &PP, raw_ostream &Name,
- raw_ostream &Value) {
- Name << II.getName();
-
- if (MI.isFunctionLike()) {
- Name << '(';
- if (!MI.param_empty()) {
- MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
- for (; AI + 1 != E; ++AI) {
- Name << (*AI)->getName();
- Name << ',';
- }
-
- // Last argument.
- if ((*AI)->getName() == "__VA_ARGS__")
- Name << "...";
- else
- Name << (*AI)->getName();
- }
-
- if (MI.isGNUVarargs())
- // #define foo(x...)
- Name << "...";
-
- Name << ')';
- }
-
- SmallString<128> SpellingBuffer;
- bool First = true;
- for (const auto &T : MI.tokens()) {
- if (!First && T.hasLeadingSpace())
- Value << ' ';
-
- Value << PP.getSpelling(T, SpellingBuffer);
- First = false;
- }
-}
-
-MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
- : Gen(Gen), PP(PP), Status(NoScope) {}
-
-// This is the expected flow of enter/exit compiler and user files:
-// - Main File Enter
-// - <built-in> file enter
-// {Compiler macro definitions} - (Line=0, no scope)
-// - (Optional) <command line> file enter
-// {Command line macro definitions} - (Line=0, no scope)
-// - (Optional) <command line> file exit
-// {Command line file includes} - (Line=0, Main file scope)
-// {macro definitions and file includes} - (Line!=0, Parent scope)
-// - <built-in> file exit
-// {User code macro definitions and file includes} - (Line!=0, Parent scope)
-
-llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
- if (Status == MainFileScope || Status == CommandLineIncludeScope)
- return Scopes.back();
- return nullptr;
-}
-
-SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
- if (Status == MainFileScope || EnteredCommandLineIncludeFiles)
- return Loc;
-
- // While parsing skipped files, location of macros is invalid.
- // Invalid location represents line zero.
- return SourceLocation();
-}
-
-void MacroPPCallbacks::updateStatusToNextScope() {
- switch (Status) {
- case NoScope:
- Status = InitializedScope;
- break;
- case InitializedScope:
- Status = BuiltinScope;
- break;
- case BuiltinScope:
- Status = CommandLineIncludeScope;
- break;
- case CommandLineIncludeScope:
- Status = MainFileScope;
- break;
- case MainFileScope:
- llvm_unreachable("There is no next scope, already in the final scope");
- }
-}
-
-void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
- SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
- switch (Status) {
- case NoScope:
- updateStatusToNextScope();
- break;
- case InitializedScope:
- updateStatusToNextScope();
- return;
- case BuiltinScope:
- if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
- return;
- updateStatusToNextScope();
- LLVM_FALLTHROUGH;
- case CommandLineIncludeScope:
- EnteredCommandLineIncludeFiles++;
- break;
- case MainFileScope:
- break;
- }
-
- Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
- LineLoc, Loc));
-}
-
-void MacroPPCallbacks::FileExited(SourceLocation Loc) {
- switch (Status) {
- default:
- llvm_unreachable("Do not expect to exit a file from current scope");
- case BuiltinScope:
- if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc))
- // Skip next scope and change status to MainFileScope.
- Status = MainFileScope;
- return;
- case CommandLineIncludeScope:
- if (!EnteredCommandLineIncludeFiles) {
- updateStatusToNextScope();
- return;
- }
- EnteredCommandLineIncludeFiles--;
- break;
- case MainFileScope:
- break;
- }
-
- Scopes.pop_back();
-}
-
-void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID) {
- // Only care about enter file or exit file changes.
- if (Reason == EnterFile)
- FileEntered(Loc);
- else if (Reason == ExitFile)
- FileExited(Loc);
-}
-
-void MacroPPCallbacks::InclusionDirective(
- SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
- bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
- StringRef SearchPath, StringRef RelativePath, const Module *Imported,
- SrcMgr::CharacteristicKind FileType) {
-
- // Record the line location of the current included file.
- LastHashLoc = HashLoc;
-}
-
-void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
- const MacroDirective *MD) {
- IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
- SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
- std::string NameBuffer, ValueBuffer;
- llvm::raw_string_ostream Name(NameBuffer);
- llvm::raw_string_ostream Value(ValueBuffer);
- writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
- Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
- llvm::dwarf::DW_MACINFO_define, location,
- Name.str(), Value.str());
-}
-
-void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD,
- const MacroDirective *Undef) {
- IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
- SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
- Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
- llvm::dwarf::DW_MACINFO_undef, location,
- Id->getName(), "");
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h b/gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h
deleted file mode 100644
index b87a4005d48..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h
+++ /dev/null
@@ -1,123 +0,0 @@
-//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines implementation for the macro preprocessors callbacks.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_MACROPPCALLBACKS_H
-#define LLVM_CLANG_LIB_CODEGEN_MACROPPCALLBACKS_H
-
-#include "clang/Lex/PPCallbacks.h"
-
-namespace llvm {
-class DIMacroFile;
-class DIMacroNode;
-}
-namespace clang {
-class Preprocessor;
-class MacroInfo;
-class CodeGenerator;
-
-class MacroPPCallbacks : public PPCallbacks {
- /// A pointer to code generator, where debug info generator can be found.
- CodeGenerator *Gen;
-
- /// Preprocessor.
- Preprocessor &PP;
-
- /// Location of recent included file, used for line number.
- SourceLocation LastHashLoc;
-
- /// Counts current number of command line included files, which were entered
- /// and were not exited yet.
- int EnteredCommandLineIncludeFiles = 0;
-
- enum FileScopeStatus {
- NoScope = 0, // Scope is not initialized yet.
- InitializedScope, // Main file scope is initialized but not set yet.
- BuiltinScope, // <built-in> and <command line> file scopes.
- CommandLineIncludeScope, // Included file, from <command line> file, scope.
- MainFileScope // Main file scope.
- };
- FileScopeStatus Status;
-
- /// Parent contains all entered files that were not exited yet according to
- /// the inclusion order.
- llvm::SmallVector<llvm::DIMacroFile *, 4> Scopes;
-
- /// Get current DIMacroFile scope.
- /// \return current DIMacroFile scope or nullptr if there is no such scope.
- llvm::DIMacroFile *getCurrentScope();
-
- /// Get current line location or invalid location.
- /// \param Loc current line location.
- /// \return current line location \p `Loc`, or invalid location if it's in a
- /// skipped file scope.
- SourceLocation getCorrectLocation(SourceLocation Loc);
-
- /// Use the passed preprocessor to write the macro name and value from the
- /// given macro info and identifier info into the given \p `Name` and \p
- /// `Value` output streams.
- ///
- /// \param II Identifier info, used to get the Macro name.
- /// \param MI Macro info, used to get the Macro argumets and values.
- /// \param PP Preprocessor.
- /// \param [out] Name Place holder for returned macro name and arguments.
- /// \param [out] Value Place holder for returned macro value.
- static void writeMacroDefinition(const IdentifierInfo &II,
- const MacroInfo &MI, Preprocessor &PP,
- raw_ostream &Name, raw_ostream &Value);
-
- /// Update current file scope status to next file scope.
- void updateStatusToNextScope();
-
- /// Handle the case when entering a file.
- ///
- /// \param Loc Indicates the new location.
- void FileEntered(SourceLocation Loc);
-
- /// Handle the case when exiting a file.
- ///
- /// \param Loc Indicates the new location.
- void FileExited(SourceLocation Loc);
-
-public:
- MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP);
-
- /// Callback invoked whenever a source file is entered or exited.
- ///
- /// \param Loc Indicates the new location.
- /// \param PrevFID the file that was exited if \p Reason is ExitFile.
- void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID = FileID()) override;
-
- /// Callback invoked whenever a directive (#xxx) is processed.
- void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
- StringRef FileName, bool IsAngled,
- CharSourceRange FilenameRange, const FileEntry *File,
- StringRef SearchPath, StringRef RelativePath,
- const Module *Imported,
- SrcMgr::CharacteristicKind FileType) override;
-
- /// Hook called whenever a macro definition is seen.
- void MacroDefined(const Token &MacroNameTok,
- const MacroDirective *MD) override;
-
- /// Hook called whenever a macro \#undef is seen.
- ///
- /// MD is released immediately following this callback.
- void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
- const MacroDirective *Undef) override;
-};
-
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/gnu/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp
deleted file mode 100644
index 5545bc6647e..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ /dev/null
@@ -1,4273 +0,0 @@
-//===--- MicrosoftCXXABI.cpp - Emit LLVM Code from ASTs for a Module ------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides C++ code generation targeting the Microsoft Visual C++ ABI.
-// The class in this file generates structures that follow the Microsoft
-// Visual C++ ABI, which is actually not very well documented at all outside
-// of Microsoft.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGCXXABI.h"
-#include "CGCleanup.h"
-#include "CGVTables.h"
-#include "CodeGenModule.h"
-#include "CodeGenTypes.h"
-#include "TargetInfo.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/VTableBuilder.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/Intrinsics.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-
-/// Holds all the vbtable globals for a given class.
-struct VBTableGlobals {
- const VPtrInfoVector *VBTables;
- SmallVector<llvm::GlobalVariable *, 2> Globals;
-};
-
-class MicrosoftCXXABI : public CGCXXABI {
-public:
- MicrosoftCXXABI(CodeGenModule &CGM)
- : CGCXXABI(CGM), BaseClassDescriptorType(nullptr),
- ClassHierarchyDescriptorType(nullptr),
- CompleteObjectLocatorType(nullptr), CatchableTypeType(nullptr),
- ThrowInfoType(nullptr) {}
-
- bool HasThisReturn(GlobalDecl GD) const override;
- bool hasMostDerivedReturn(GlobalDecl GD) const override;
-
- bool classifyReturnType(CGFunctionInfo &FI) const override;
-
- RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override;
-
- bool isSRetParameterAfterThis() const override { return true; }
-
- bool isThisCompleteObject(GlobalDecl GD) const override {
- // The Microsoft ABI doesn't use separate complete-object vs.
- // base-object variants of constructors, but it does of destructors.
- if (isa<CXXDestructorDecl>(GD.getDecl())) {
- switch (GD.getDtorType()) {
- case Dtor_Complete:
- case Dtor_Deleting:
- return true;
-
- case Dtor_Base:
- return false;
-
- case Dtor_Comdat: llvm_unreachable("emitting dtor comdat as function?");
- }
- llvm_unreachable("bad dtor kind");
- }
-
- // No other kinds.
- return false;
- }
-
- size_t getSrcArgforCopyCtor(const CXXConstructorDecl *CD,
- FunctionArgList &Args) const override {
- assert(Args.size() >= 2 &&
- "expected the arglist to have at least two args!");
- // The 'most_derived' parameter goes second if the ctor is variadic and
- // has v-bases.
- if (CD->getParent()->getNumVBases() > 0 &&
- CD->getType()->castAs<FunctionProtoType>()->isVariadic())
- return 2;
- return 1;
- }
-
- std::vector<CharUnits> getVBPtrOffsets(const CXXRecordDecl *RD) override {
- std::vector<CharUnits> VBPtrOffsets;
- const ASTContext &Context = getContext();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- const VBTableGlobals &VBGlobals = enumerateVBTables(RD);
- for (const std::unique_ptr<VPtrInfo> &VBT : *VBGlobals.VBTables) {
- const ASTRecordLayout &SubobjectLayout =
- Context.getASTRecordLayout(VBT->IntroducingObject);
- CharUnits Offs = VBT->NonVirtualOffset;
- Offs += SubobjectLayout.getVBPtrOffset();
- if (VBT->getVBaseWithVPtr())
- Offs += Layout.getVBaseClassOffset(VBT->getVBaseWithVPtr());
- VBPtrOffsets.push_back(Offs);
- }
- llvm::array_pod_sort(VBPtrOffsets.begin(), VBPtrOffsets.end());
- return VBPtrOffsets;
- }
-
- StringRef GetPureVirtualCallName() override { return "_purecall"; }
- StringRef GetDeletedVirtualCallName() override { return "_purecall"; }
-
- void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE,
- Address Ptr, QualType ElementType,
- const CXXDestructorDecl *Dtor) override;
-
- void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
- void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override;
-
- void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override;
-
- llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
- const VPtrInfo &Info);
-
- llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
- CatchTypeInfo
- getAddrOfCXXCatchHandlerType(QualType Ty, QualType CatchHandlerType) override;
-
- /// MSVC needs an extra flag to indicate a catchall.
- CatchTypeInfo getCatchAllTypeInfo() override {
- return CatchTypeInfo{nullptr, 0x40};
- }
-
- bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
- void EmitBadTypeidCall(CodeGenFunction &CGF) override;
- llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
- Address ThisPtr,
- llvm::Type *StdTypeInfoPtrTy) override;
-
- bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
- QualType SrcRecordTy) override;
-
- llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy, QualType DestTy,
- QualType DestRecordTy,
- llvm::BasicBlock *CastEnd) override;
-
- llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy,
- QualType DestTy) override;
-
- bool EmitBadCastCall(CodeGenFunction &CGF) override;
- bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override {
- return false;
- }
-
- llvm::Value *
- GetVirtualBaseClassOffset(CodeGenFunction &CGF, Address This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) override;
-
- llvm::BasicBlock *
- EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
- const CXXRecordDecl *RD) override;
-
- llvm::BasicBlock *
- EmitDtorCompleteObjectHandler(CodeGenFunction &CGF);
-
- void initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
- const CXXRecordDecl *RD) override;
-
- void EmitCXXConstructors(const CXXConstructorDecl *D) override;
-
- // Background on MSVC destructors
- // ==============================
- //
- // Both Itanium and MSVC ABIs have destructor variants. The variant names
- // roughly correspond in the following way:
- // Itanium Microsoft
- // Base -> no name, just ~Class
- // Complete -> vbase destructor
- // Deleting -> scalar deleting destructor
- // vector deleting destructor
- //
- // The base and complete destructors are the same as in Itanium, although the
- // complete destructor does not accept a VTT parameter when there are virtual
- // bases. A separate mechanism involving vtordisps is used to ensure that
- // virtual methods of destroyed subobjects are not called.
- //
- // The deleting destructors accept an i32 bitfield as a second parameter. Bit
- // 1 indicates if the memory should be deleted. Bit 2 indicates if the this
- // pointer points to an array. The scalar deleting destructor assumes that
- // bit 2 is zero, and therefore does not contain a loop.
- //
- // For virtual destructors, only one entry is reserved in the vftable, and it
- // always points to the vector deleting destructor. The vector deleting
- // destructor is the most general, so it can be used to destroy objects in
- // place, delete single heap objects, or delete arrays.
- //
- // A TU defining a non-inline destructor is only guaranteed to emit a base
- // destructor, and all of the other variants are emitted on an as-needed basis
- // in COMDATs. Because a non-base destructor can be emitted in a TU that
- // lacks a definition for the destructor, non-base destructors must always
- // delegate to or alias the base destructor.
-
- AddedStructorArgs
- buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) override;
-
- /// Non-base dtors should be emitted as delegating thunks in this ABI.
- bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const override {
- return DT != Dtor_Base;
- }
-
- void setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const override;
-
- llvm::GlobalValue::LinkageTypes
- getCXXDestructorLinkage(GVALinkage Linkage, const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const override;
-
- void EmitCXXDestructors(const CXXDestructorDecl *D) override;
-
- const CXXRecordDecl *
- getThisArgumentTypeForMethod(const CXXMethodDecl *MD) override {
- if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD)) {
- MethodVFTableLocation ML =
- CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
- // The vbases might be ordered differently in the final overrider object
- // and the complete object, so the "this" argument may sometimes point to
- // memory that has no particular type (e.g. past the complete object).
- // In this case, we just use a generic pointer type.
- // FIXME: might want to have a more precise type in the non-virtual
- // multiple inheritance case.
- if (ML.VBase || !ML.VFPtrOffset.isZero())
- return nullptr;
- }
- return MD->getParent();
- }
-
- Address
- adjustThisArgumentForVirtualFunctionCall(CodeGenFunction &CGF, GlobalDecl GD,
- Address This,
- bool VirtualCall) override;
-
- void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy,
- FunctionArgList &Params) override;
-
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
-
- AddedStructorArgs
- addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating, CallArgList &Args) override;
-
- void EmitDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *DD,
- CXXDtorType Type, bool ForVirtualBase,
- bool Delegating, Address This) override;
-
- void emitVTableTypeMetadata(const VPtrInfo &Info, const CXXRecordDecl *RD,
- llvm::GlobalVariable *VTable);
-
- void emitVTableDefinitions(CodeGenVTables &CGVT,
- const CXXRecordDecl *RD) override;
-
- bool isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF,
- CodeGenFunction::VPtr Vptr) override;
-
- /// Don't initialize vptrs if dynamic class
- /// is marked with with the 'novtable' attribute.
- bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) override {
- return !VTableClass->hasAttr<MSNoVTableAttr>();
- }
-
- llvm::Constant *
- getVTableAddressPoint(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) override;
-
- llvm::Value *getVTableAddressPointInStructor(
- CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
- BaseSubobject Base, const CXXRecordDecl *NearestVBase) override;
-
- llvm::Constant *
- getVTableAddressPointForConstExpr(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) override;
-
- llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
- CharUnits VPtrOffset) override;
-
- CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
- Address This, llvm::Type *Ty,
- SourceLocation Loc) override;
-
- llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- Address This,
- const CXXMemberCallExpr *CE) override;
-
- void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD,
- CallArgList &CallArgs) override {
- assert(GD.getDtorType() == Dtor_Deleting &&
- "Only deleting destructor thunks are available in this ABI");
- CallArgs.add(RValue::get(getStructorImplicitParamValue(CGF)),
- getContext().IntTy);
- }
-
- void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
-
- llvm::GlobalVariable *
- getAddrOfVBTable(const VPtrInfo &VBT, const CXXRecordDecl *RD,
- llvm::GlobalVariable::LinkageTypes Linkage);
-
- llvm::GlobalVariable *
- getAddrOfVirtualDisplacementMap(const CXXRecordDecl *SrcRD,
- const CXXRecordDecl *DstRD) {
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- getMangleContext().mangleCXXVirtualDisplacementMap(SrcRD, DstRD, Out);
- StringRef MangledName = OutName.str();
-
- if (auto *VDispMap = CGM.getModule().getNamedGlobal(MangledName))
- return VDispMap;
-
- MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext();
- unsigned NumEntries = 1 + SrcRD->getNumVBases();
- SmallVector<llvm::Constant *, 4> Map(NumEntries,
- llvm::UndefValue::get(CGM.IntTy));
- Map[0] = llvm::ConstantInt::get(CGM.IntTy, 0);
- bool AnyDifferent = false;
- for (const auto &I : SrcRD->vbases()) {
- const CXXRecordDecl *VBase = I.getType()->getAsCXXRecordDecl();
- if (!DstRD->isVirtuallyDerivedFrom(VBase))
- continue;
-
- unsigned SrcVBIndex = VTContext.getVBTableIndex(SrcRD, VBase);
- unsigned DstVBIndex = VTContext.getVBTableIndex(DstRD, VBase);
- Map[SrcVBIndex] = llvm::ConstantInt::get(CGM.IntTy, DstVBIndex * 4);
- AnyDifferent |= SrcVBIndex != DstVBIndex;
- }
- // This map would be useless, don't use it.
- if (!AnyDifferent)
- return nullptr;
-
- llvm::ArrayType *VDispMapTy = llvm::ArrayType::get(CGM.IntTy, Map.size());
- llvm::Constant *Init = llvm::ConstantArray::get(VDispMapTy, Map);
- llvm::GlobalValue::LinkageTypes Linkage =
- SrcRD->isExternallyVisible() && DstRD->isExternallyVisible()
- ? llvm::GlobalValue::LinkOnceODRLinkage
- : llvm::GlobalValue::InternalLinkage;
- auto *VDispMap = new llvm::GlobalVariable(
- CGM.getModule(), VDispMapTy, /*Constant=*/true, Linkage,
- /*Initializer=*/Init, MangledName);
- return VDispMap;
- }
-
- void emitVBTableDefinition(const VPtrInfo &VBT, const CXXRecordDecl *RD,
- llvm::GlobalVariable *GV) const;
-
- void setThunkLinkage(llvm::Function *Thunk, bool ForVTable,
- GlobalDecl GD, bool ReturnAdjustment) override {
- GVALinkage Linkage =
- getContext().GetGVALinkageForFunction(cast<FunctionDecl>(GD.getDecl()));
-
- if (Linkage == GVA_Internal)
- Thunk->setLinkage(llvm::GlobalValue::InternalLinkage);
- else if (ReturnAdjustment)
- Thunk->setLinkage(llvm::GlobalValue::WeakODRLinkage);
- else
- Thunk->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
- }
-
- bool exportThunk() override { return false; }
-
- llvm::Value *performThisAdjustment(CodeGenFunction &CGF, Address This,
- const ThisAdjustment &TA) override;
-
- llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, Address Ret,
- const ReturnAdjustment &RA) override;
-
- void EmitThreadLocalInitFuncs(
- CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
- ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
-
- bool usesThreadWrapperFunction() const override { return false; }
- LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
- QualType LValType) override;
-
- void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr,
- bool PerformInit) override;
- void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *Dtor, llvm::Constant *Addr) override;
-
- // ==== Notes on array cookies =========
- //
- // MSVC seems to only use cookies when the class has a destructor; a
- // two-argument usual array deallocation function isn't sufficient.
- //
- // For example, this code prints "100" and "1":
- // struct A {
- // char x;
- // void *operator new[](size_t sz) {
- // printf("%u\n", sz);
- // return malloc(sz);
- // }
- // void operator delete[](void *p, size_t sz) {
- // printf("%u\n", sz);
- // free(p);
- // }
- // };
- // int main() {
- // A *p = new A[100];
- // delete[] p;
- // }
- // Whereas it prints "104" and "104" if you give A a destructor.
-
- bool requiresArrayCookie(const CXXDeleteExpr *expr,
- QualType elementType) override;
- bool requiresArrayCookie(const CXXNewExpr *expr) override;
- CharUnits getArrayCookieSizeImpl(QualType type) override;
- Address InitializeArrayCookie(CodeGenFunction &CGF,
- Address NewPtr,
- llvm::Value *NumElements,
- const CXXNewExpr *expr,
- QualType ElementType) override;
- llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
- Address allocPtr,
- CharUnits cookieSize) override;
-
- friend struct MSRTTIBuilder;
-
- bool isImageRelative() const {
- return CGM.getTarget().getPointerWidth(/*AddressSpace=*/0) == 64;
- }
-
- // 5 routines for constructing the llvm types for MS RTTI structs.
- llvm::StructType *getTypeDescriptorType(StringRef TypeInfoString) {
- llvm::SmallString<32> TDTypeName("rtti.TypeDescriptor");
- TDTypeName += llvm::utostr(TypeInfoString.size());
- llvm::StructType *&TypeDescriptorType =
- TypeDescriptorTypeMap[TypeInfoString.size()];
- if (TypeDescriptorType)
- return TypeDescriptorType;
- llvm::Type *FieldTypes[] = {
- CGM.Int8PtrPtrTy,
- CGM.Int8PtrTy,
- llvm::ArrayType::get(CGM.Int8Ty, TypeInfoString.size() + 1)};
- TypeDescriptorType =
- llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, TDTypeName);
- return TypeDescriptorType;
- }
-
- llvm::Type *getImageRelativeType(llvm::Type *PtrType) {
- if (!isImageRelative())
- return PtrType;
- return CGM.IntTy;
- }
-
- llvm::StructType *getBaseClassDescriptorType() {
- if (BaseClassDescriptorType)
- return BaseClassDescriptorType;
- llvm::Type *FieldTypes[] = {
- getImageRelativeType(CGM.Int8PtrTy),
- CGM.IntTy,
- CGM.IntTy,
- CGM.IntTy,
- CGM.IntTy,
- CGM.IntTy,
- getImageRelativeType(getClassHierarchyDescriptorType()->getPointerTo()),
- };
- BaseClassDescriptorType = llvm::StructType::create(
- CGM.getLLVMContext(), FieldTypes, "rtti.BaseClassDescriptor");
- return BaseClassDescriptorType;
- }
-
- llvm::StructType *getClassHierarchyDescriptorType() {
- if (ClassHierarchyDescriptorType)
- return ClassHierarchyDescriptorType;
- // Forward-declare RTTIClassHierarchyDescriptor to break a cycle.
- ClassHierarchyDescriptorType = llvm::StructType::create(
- CGM.getLLVMContext(), "rtti.ClassHierarchyDescriptor");
- llvm::Type *FieldTypes[] = {
- CGM.IntTy,
- CGM.IntTy,
- CGM.IntTy,
- getImageRelativeType(
- getBaseClassDescriptorType()->getPointerTo()->getPointerTo()),
- };
- ClassHierarchyDescriptorType->setBody(FieldTypes);
- return ClassHierarchyDescriptorType;
- }
-
- llvm::StructType *getCompleteObjectLocatorType() {
- if (CompleteObjectLocatorType)
- return CompleteObjectLocatorType;
- CompleteObjectLocatorType = llvm::StructType::create(
- CGM.getLLVMContext(), "rtti.CompleteObjectLocator");
- llvm::Type *FieldTypes[] = {
- CGM.IntTy,
- CGM.IntTy,
- CGM.IntTy,
- getImageRelativeType(CGM.Int8PtrTy),
- getImageRelativeType(getClassHierarchyDescriptorType()->getPointerTo()),
- getImageRelativeType(CompleteObjectLocatorType),
- };
- llvm::ArrayRef<llvm::Type *> FieldTypesRef(FieldTypes);
- if (!isImageRelative())
- FieldTypesRef = FieldTypesRef.drop_back();
- CompleteObjectLocatorType->setBody(FieldTypesRef);
- return CompleteObjectLocatorType;
- }
-
- llvm::GlobalVariable *getImageBase() {
- StringRef Name = "__ImageBase";
- if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name))
- return GV;
-
- auto *GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty,
- /*isConstant=*/true,
- llvm::GlobalValue::ExternalLinkage,
- /*Initializer=*/nullptr, Name);
- CGM.setDSOLocal(GV);
- return GV;
- }
-
- llvm::Constant *getImageRelativeConstant(llvm::Constant *PtrVal) {
- if (!isImageRelative())
- return PtrVal;
-
- if (PtrVal->isNullValue())
- return llvm::Constant::getNullValue(CGM.IntTy);
-
- llvm::Constant *ImageBaseAsInt =
- llvm::ConstantExpr::getPtrToInt(getImageBase(), CGM.IntPtrTy);
- llvm::Constant *PtrValAsInt =
- llvm::ConstantExpr::getPtrToInt(PtrVal, CGM.IntPtrTy);
- llvm::Constant *Diff =
- llvm::ConstantExpr::getSub(PtrValAsInt, ImageBaseAsInt,
- /*HasNUW=*/true, /*HasNSW=*/true);
- return llvm::ConstantExpr::getTrunc(Diff, CGM.IntTy);
- }
-
-private:
- MicrosoftMangleContext &getMangleContext() {
- return cast<MicrosoftMangleContext>(CodeGen::CGCXXABI::getMangleContext());
- }
-
- llvm::Constant *getZeroInt() {
- return llvm::ConstantInt::get(CGM.IntTy, 0);
- }
-
- llvm::Constant *getAllOnesInt() {
- return llvm::Constant::getAllOnesValue(CGM.IntTy);
- }
-
- CharUnits getVirtualFunctionPrologueThisAdjustment(GlobalDecl GD) override;
-
- void
- GetNullMemberPointerFields(const MemberPointerType *MPT,
- llvm::SmallVectorImpl<llvm::Constant *> &fields);
-
- /// Shared code for virtual base adjustment. Returns the offset from
- /// the vbptr to the virtual base. Optionally returns the address of the
- /// vbptr itself.
- llvm::Value *GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
- Address Base,
- llvm::Value *VBPtrOffset,
- llvm::Value *VBTableOffset,
- llvm::Value **VBPtr = nullptr);
-
- llvm::Value *GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
- Address Base,
- int32_t VBPtrOffset,
- int32_t VBTableOffset,
- llvm::Value **VBPtr = nullptr) {
- assert(VBTableOffset % 4 == 0 && "should be byte offset into table of i32s");
- llvm::Value *VBPOffset = llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
- *VBTOffset = llvm::ConstantInt::get(CGM.IntTy, VBTableOffset);
- return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr);
- }
-
- std::tuple<Address, llvm::Value *, const CXXRecordDecl *>
- performBaseAdjustment(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy);
-
- /// Performs a full virtual base adjustment. Used to dereference
- /// pointers to members of virtual bases.
- llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const Expr *E,
- const CXXRecordDecl *RD, Address Base,
- llvm::Value *VirtualBaseAdjustmentOffset,
- llvm::Value *VBPtrOffset /* optional */);
-
- /// Emits a full member pointer with the fields common to data and
- /// function member pointers.
- llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField,
- bool IsMemberFunction,
- const CXXRecordDecl *RD,
- CharUnits NonVirtualBaseAdjustment,
- unsigned VBTableIndex);
-
- bool MemberPointerConstantIsNull(const MemberPointerType *MPT,
- llvm::Constant *MP);
-
- /// - Initialize all vbptrs of 'this' with RD as the complete type.
- void EmitVBPtrStores(CodeGenFunction &CGF, const CXXRecordDecl *RD);
-
- /// Caching wrapper around VBTableBuilder::enumerateVBTables().
- const VBTableGlobals &enumerateVBTables(const CXXRecordDecl *RD);
-
- /// Generate a thunk for calling a virtual member function MD.
- llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
- const MethodVFTableLocation &ML);
-
-public:
- llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
-
- bool isZeroInitializable(const MemberPointerType *MPT) override;
-
- bool isMemberPointerConvertible(const MemberPointerType *MPT) const override {
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- return RD->hasAttr<MSInheritanceAttr>();
- }
-
- llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT) override;
-
- llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset) override;
- llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD) override;
- llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT) override;
-
- llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L,
- llvm::Value *R,
- const MemberPointerType *MPT,
- bool Inequality) override;
-
- llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) override;
-
- llvm::Value *
- EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
- Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) override;
-
- llvm::Value *EmitNonNullMemberPointerConversion(
- const MemberPointerType *SrcTy, const MemberPointerType *DstTy,
- CastKind CK, CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd, llvm::Value *Src,
- CGBuilderTy &Builder);
-
- llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
- const CastExpr *E,
- llvm::Value *Src) override;
-
- llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *Src) override;
-
- llvm::Constant *EmitMemberPointerConversion(
- const MemberPointerType *SrcTy, const MemberPointerType *DstTy,
- CastKind CK, CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd, llvm::Constant *Src);
-
- CGCallee
- EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, const Expr *E,
- Address This, llvm::Value *&ThisPtrForCall,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) override;
-
- void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
-
- llvm::StructType *getCatchableTypeType() {
- if (CatchableTypeType)
- return CatchableTypeType;
- llvm::Type *FieldTypes[] = {
- CGM.IntTy, // Flags
- getImageRelativeType(CGM.Int8PtrTy), // TypeDescriptor
- CGM.IntTy, // NonVirtualAdjustment
- CGM.IntTy, // OffsetToVBPtr
- CGM.IntTy, // VBTableIndex
- CGM.IntTy, // Size
- getImageRelativeType(CGM.Int8PtrTy) // CopyCtor
- };
- CatchableTypeType = llvm::StructType::create(
- CGM.getLLVMContext(), FieldTypes, "eh.CatchableType");
- return CatchableTypeType;
- }
-
- llvm::StructType *getCatchableTypeArrayType(uint32_t NumEntries) {
- llvm::StructType *&CatchableTypeArrayType =
- CatchableTypeArrayTypeMap[NumEntries];
- if (CatchableTypeArrayType)
- return CatchableTypeArrayType;
-
- llvm::SmallString<23> CTATypeName("eh.CatchableTypeArray.");
- CTATypeName += llvm::utostr(NumEntries);
- llvm::Type *CTType =
- getImageRelativeType(getCatchableTypeType()->getPointerTo());
- llvm::Type *FieldTypes[] = {
- CGM.IntTy, // NumEntries
- llvm::ArrayType::get(CTType, NumEntries) // CatchableTypes
- };
- CatchableTypeArrayType =
- llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, CTATypeName);
- return CatchableTypeArrayType;
- }
-
- llvm::StructType *getThrowInfoType() {
- if (ThrowInfoType)
- return ThrowInfoType;
- llvm::Type *FieldTypes[] = {
- CGM.IntTy, // Flags
- getImageRelativeType(CGM.Int8PtrTy), // CleanupFn
- getImageRelativeType(CGM.Int8PtrTy), // ForwardCompat
- getImageRelativeType(CGM.Int8PtrTy) // CatchableTypeArray
- };
- ThrowInfoType = llvm::StructType::create(CGM.getLLVMContext(), FieldTypes,
- "eh.ThrowInfo");
- return ThrowInfoType;
- }
-
- llvm::Constant *getThrowFn() {
- // _CxxThrowException is passed an exception object and a ThrowInfo object
- // which describes the exception.
- llvm::Type *Args[] = {CGM.Int8PtrTy, getThrowInfoType()->getPointerTo()};
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
- auto *Fn = cast<llvm::Function>(
- CGM.CreateRuntimeFunction(FTy, "_CxxThrowException"));
- // _CxxThrowException is stdcall on 32-bit x86 platforms.
- if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86)
- Fn->setCallingConv(llvm::CallingConv::X86_StdCall);
- return Fn;
- }
-
- llvm::Function *getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
- CXXCtorType CT);
-
- llvm::Constant *getCatchableType(QualType T,
- uint32_t NVOffset = 0,
- int32_t VBPtrOffset = -1,
- uint32_t VBIndex = 0);
-
- llvm::GlobalVariable *getCatchableTypeArray(QualType T);
-
- llvm::GlobalVariable *getThrowInfo(QualType T) override;
-
- std::pair<llvm::Value *, const CXXRecordDecl *>
- LoadVTablePtr(CodeGenFunction &CGF, Address This,
- const CXXRecordDecl *RD) override;
-
-private:
- typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
- typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy;
- typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalValue *> VFTablesMapTy;
- /// All the vftables that have been referenced.
- VFTablesMapTy VFTablesMap;
- VTablesMapTy VTablesMap;
-
- /// This set holds the record decls we've deferred vtable emission for.
- llvm::SmallPtrSet<const CXXRecordDecl *, 4> DeferredVFTables;
-
-
- /// All the vbtables which have been referenced.
- llvm::DenseMap<const CXXRecordDecl *, VBTableGlobals> VBTablesMap;
-
- /// Info on the global variable used to guard initialization of static locals.
- /// The BitIndex field is only used for externally invisible declarations.
- struct GuardInfo {
- GuardInfo() : Guard(nullptr), BitIndex(0) {}
- llvm::GlobalVariable *Guard;
- unsigned BitIndex;
- };
-
- /// Map from DeclContext to the current guard variable. We assume that the
- /// AST is visited in source code order.
- llvm::DenseMap<const DeclContext *, GuardInfo> GuardVariableMap;
- llvm::DenseMap<const DeclContext *, GuardInfo> ThreadLocalGuardVariableMap;
- llvm::DenseMap<const DeclContext *, unsigned> ThreadSafeGuardNumMap;
-
- llvm::DenseMap<size_t, llvm::StructType *> TypeDescriptorTypeMap;
- llvm::StructType *BaseClassDescriptorType;
- llvm::StructType *ClassHierarchyDescriptorType;
- llvm::StructType *CompleteObjectLocatorType;
-
- llvm::DenseMap<QualType, llvm::GlobalVariable *> CatchableTypeArrays;
-
- llvm::StructType *CatchableTypeType;
- llvm::DenseMap<uint32_t, llvm::StructType *> CatchableTypeArrayTypeMap;
- llvm::StructType *ThrowInfoType;
-};
-
-}
-
-CGCXXABI::RecordArgABI
-MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
- switch (CGM.getTarget().getTriple().getArch()) {
- default:
- // FIXME: Implement for other architectures.
- return RAA_Default;
-
- case llvm::Triple::thumb:
- // Use the simple Itanium rules for now.
- // FIXME: This is incompatible with MSVC for arguments with a dtor and no
- // copy ctor.
- return !canCopyArgument(RD) ? RAA_Indirect : RAA_Default;
-
- case llvm::Triple::x86:
- // All record arguments are passed in memory on x86. Decide whether to
- // construct the object directly in argument memory, or to construct the
- // argument elsewhere and copy the bytes during the call.
-
- // If C++ prohibits us from making a copy, construct the arguments directly
- // into argument memory.
- if (!canCopyArgument(RD))
- return RAA_DirectInMemory;
-
- // Otherwise, construct the argument into a temporary and copy the bytes
- // into the outgoing argument memory.
- return RAA_Default;
-
- case llvm::Triple::x86_64:
- case llvm::Triple::aarch64:
- return !canCopyArgument(RD) ? RAA_Indirect : RAA_Default;
- }
-
- llvm_unreachable("invalid enum");
-}
-
-void MicrosoftCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- Address Ptr,
- QualType ElementType,
- const CXXDestructorDecl *Dtor) {
- // FIXME: Provide a source location here even though there's no
- // CXXMemberCallExpr for dtor call.
- bool UseGlobalDelete = DE->isGlobalDelete();
- CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
- llvm::Value *MDThis =
- EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, /*CE=*/nullptr);
- if (UseGlobalDelete)
- CGF.EmitDeleteCall(DE->getOperatorDelete(), MDThis, ElementType);
-}
-
-void MicrosoftCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
- llvm::Value *Args[] = {
- llvm::ConstantPointerNull::get(CGM.Int8PtrTy),
- llvm::ConstantPointerNull::get(getThrowInfoType()->getPointerTo())};
- auto *Fn = getThrowFn();
- if (isNoReturn)
- CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, Args);
- else
- CGF.EmitRuntimeCallOrInvoke(Fn, Args);
-}
-
-void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF,
- const CXXCatchStmt *S) {
- // In the MS ABI, the runtime handles the copy, and the catch handler is
- // responsible for destruction.
- VarDecl *CatchParam = S->getExceptionDecl();
- llvm::BasicBlock *CatchPadBB = CGF.Builder.GetInsertBlock();
- llvm::CatchPadInst *CPI =
- cast<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI());
- CGF.CurrentFuncletPad = CPI;
-
- // If this is a catch-all or the catch parameter is unnamed, we don't need to
- // emit an alloca to the object.
- if (!CatchParam || !CatchParam->getDeclName()) {
- CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
- return;
- }
-
- CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
- CPI->setArgOperand(2, var.getObjectAddress(CGF).getPointer());
- CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
- CGF.EmitAutoVarCleanups(var);
-}
-
-/// We need to perform a generic polymorphic operation (like a typeid
-/// or a cast), which requires an object with a vfptr. Adjust the
-/// address to point to an object with a vfptr.
-std::tuple<Address, llvm::Value *, const CXXRecordDecl *>
-MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy) {
- Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy);
- const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
- const ASTContext &Context = getContext();
-
- // If the class itself has a vfptr, great. This check implicitly
- // covers non-virtual base subobjects: a class with its own virtual
- // functions would be a candidate to be a primary base.
- if (Context.getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
- return std::make_tuple(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0),
- SrcDecl);
-
- // Okay, one of the vbases must have a vfptr, or else this isn't
- // actually a polymorphic class.
- const CXXRecordDecl *PolymorphicBase = nullptr;
- for (auto &Base : SrcDecl->vbases()) {
- const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (Context.getASTRecordLayout(BaseDecl).hasExtendableVFPtr()) {
- PolymorphicBase = BaseDecl;
- break;
- }
- }
- assert(PolymorphicBase && "polymorphic class has no apparent vfptr?");
-
- llvm::Value *Offset =
- GetVirtualBaseClassOffset(CGF, Value, SrcDecl, PolymorphicBase);
- llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP(Value.getPointer(), Offset);
- CharUnits VBaseAlign =
- CGF.CGM.getVBaseAlignment(Value.getAlignment(), SrcDecl, PolymorphicBase);
- return std::make_tuple(Address(Ptr, VBaseAlign), Offset, PolymorphicBase);
-}
-
-bool MicrosoftCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
- QualType SrcRecordTy) {
- const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
- return IsDeref &&
- !getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
-}
-
-static llvm::CallSite emitRTtypeidCall(CodeGenFunction &CGF,
- llvm::Value *Argument) {
- llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false);
- llvm::Value *Args[] = {Argument};
- llvm::Constant *Fn = CGF.CGM.CreateRuntimeFunction(FTy, "__RTtypeid");
- return CGF.EmitRuntimeCallOrInvoke(Fn, Args);
-}
-
-void MicrosoftCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
- llvm::CallSite Call =
- emitRTtypeidCall(CGF, llvm::Constant::getNullValue(CGM.VoidPtrTy));
- Call.setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
-}
-
-llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF,
- QualType SrcRecordTy,
- Address ThisPtr,
- llvm::Type *StdTypeInfoPtrTy) {
- std::tie(ThisPtr, std::ignore, std::ignore) =
- performBaseAdjustment(CGF, ThisPtr, SrcRecordTy);
- auto Typeid = emitRTtypeidCall(CGF, ThisPtr.getPointer()).getInstruction();
- return CGF.Builder.CreateBitCast(Typeid, StdTypeInfoPtrTy);
-}
-
-bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
- QualType SrcRecordTy) {
- const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
- return SrcIsPtr &&
- !getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
-}
-
-llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall(
- CodeGenFunction &CGF, Address This, QualType SrcRecordTy,
- QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
- llvm::Type *DestLTy = CGF.ConvertType(DestTy);
-
- llvm::Value *SrcRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
- llvm::Value *DestRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
-
- llvm::Value *Offset;
- std::tie(This, Offset, std::ignore) =
- performBaseAdjustment(CGF, This, SrcRecordTy);
- llvm::Value *ThisPtr = This.getPointer();
- Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty);
-
- // PVOID __RTDynamicCast(
- // PVOID inptr,
- // LONG VfDelta,
- // PVOID SrcType,
- // PVOID TargetType,
- // BOOL isReference)
- llvm::Type *ArgTypes[] = {CGF.Int8PtrTy, CGF.Int32Ty, CGF.Int8PtrTy,
- CGF.Int8PtrTy, CGF.Int32Ty};
- llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
- "__RTDynamicCast");
- llvm::Value *Args[] = {
- ThisPtr, Offset, SrcRTTI, DestRTTI,
- llvm::ConstantInt::get(CGF.Int32Ty, DestTy->isReferenceType())};
- ThisPtr = CGF.EmitRuntimeCallOrInvoke(Function, Args).getInstruction();
- return CGF.Builder.CreateBitCast(ThisPtr, DestLTy);
-}
-
-llvm::Value *
-MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, Address Value,
- QualType SrcRecordTy,
- QualType DestTy) {
- std::tie(Value, std::ignore, std::ignore) =
- performBaseAdjustment(CGF, Value, SrcRecordTy);
-
- // PVOID __RTCastToVoid(
- // PVOID inptr)
- llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
- llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
- "__RTCastToVoid");
- llvm::Value *Args[] = {Value.getPointer()};
- return CGF.EmitRuntimeCall(Function, Args);
-}
-
-bool MicrosoftCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
- return false;
-}
-
-llvm::Value *MicrosoftCXXABI::GetVirtualBaseClassOffset(
- CodeGenFunction &CGF, Address This, const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- const ASTContext &Context = getContext();
- int64_t VBPtrChars =
- Context.getASTRecordLayout(ClassDecl).getVBPtrOffset().getQuantity();
- llvm::Value *VBPtrOffset = llvm::ConstantInt::get(CGM.PtrDiffTy, VBPtrChars);
- CharUnits IntSize = Context.getTypeSizeInChars(Context.IntTy);
- CharUnits VBTableChars =
- IntSize *
- CGM.getMicrosoftVTableContext().getVBTableIndex(ClassDecl, BaseClassDecl);
- llvm::Value *VBTableOffset =
- llvm::ConstantInt::get(CGM.IntTy, VBTableChars.getQuantity());
-
- llvm::Value *VBPtrToNewBase =
- GetVBaseOffsetFromVBPtr(CGF, This, VBPtrOffset, VBTableOffset);
- VBPtrToNewBase =
- CGF.Builder.CreateSExtOrBitCast(VBPtrToNewBase, CGM.PtrDiffTy);
- return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
-}
-
-bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {
- return isa<CXXConstructorDecl>(GD.getDecl());
-}
-
-static bool isDeletingDtor(GlobalDecl GD) {
- return isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() == Dtor_Deleting;
-}
-
-bool MicrosoftCXXABI::hasMostDerivedReturn(GlobalDecl GD) const {
- return isDeletingDtor(GD);
-}
-
-bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
- const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl();
- if (!RD)
- return false;
-
- CharUnits Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType());
- if (FI.isInstanceMethod()) {
- // If it's an instance method, aggregates are always returned indirectly via
- // the second parameter.
- FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
- FI.getReturnInfo().setSRetAfterThis(FI.isInstanceMethod());
-
- // aarch64-windows requires that instance methods use X1 for the return
- // address. So for aarch64-windows we do not mark the
- // return as SRet.
- FI.getReturnInfo().setSuppressSRet(CGM.getTarget().getTriple().getArch() ==
- llvm::Triple::aarch64);
- return true;
- } else if (!RD->isPOD()) {
- // If it's a free function, non-POD types are returned indirectly.
- FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
-
- // aarch64-windows requires that non-POD, non-instance returns use X0 for
- // the return address. So for aarch64-windows we do not mark the return as
- // SRet.
- FI.getReturnInfo().setSuppressSRet(CGM.getTarget().getTriple().getArch() ==
- llvm::Triple::aarch64);
- return true;
- }
-
- // Otherwise, use the C ABI rules.
- return false;
-}
-
-llvm::BasicBlock *
-MicrosoftCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
- const CXXRecordDecl *RD) {
- llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF);
- assert(IsMostDerivedClass &&
- "ctor for a class with virtual bases must have an implicit parameter");
- llvm::Value *IsCompleteObject =
- CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
-
- llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases");
- llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases");
- CGF.Builder.CreateCondBr(IsCompleteObject,
- CallVbaseCtorsBB, SkipVbaseCtorsBB);
-
- CGF.EmitBlock(CallVbaseCtorsBB);
-
- // Fill in the vbtable pointers here.
- EmitVBPtrStores(CGF, RD);
-
- // CGF will put the base ctor calls in this basic block for us later.
-
- return SkipVbaseCtorsBB;
-}
-
-llvm::BasicBlock *
-MicrosoftCXXABI::EmitDtorCompleteObjectHandler(CodeGenFunction &CGF) {
- llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF);
- assert(IsMostDerivedClass &&
- "ctor for a class with virtual bases must have an implicit parameter");
- llvm::Value *IsCompleteObject =
- CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
-
- llvm::BasicBlock *CallVbaseDtorsBB = CGF.createBasicBlock("Dtor.dtor_vbases");
- llvm::BasicBlock *SkipVbaseDtorsBB = CGF.createBasicBlock("Dtor.skip_vbases");
- CGF.Builder.CreateCondBr(IsCompleteObject,
- CallVbaseDtorsBB, SkipVbaseDtorsBB);
-
- CGF.EmitBlock(CallVbaseDtorsBB);
- // CGF will put the base dtor calls in this basic block for us later.
-
- return SkipVbaseDtorsBB;
-}
-
-void MicrosoftCXXABI::initializeHiddenVirtualInheritanceMembers(
- CodeGenFunction &CGF, const CXXRecordDecl *RD) {
- // In most cases, an override for a vbase virtual method can adjust
- // the "this" parameter by applying a constant offset.
- // However, this is not enough while a constructor or a destructor of some
- // class X is being executed if all the following conditions are met:
- // - X has virtual bases, (1)
- // - X overrides a virtual method M of a vbase Y, (2)
- // - X itself is a vbase of the most derived class.
- //
- // If (1) and (2) are true, the vtorDisp for vbase Y is a hidden member of X
- // which holds the extra amount of "this" adjustment we must do when we use
- // the X vftables (i.e. during X ctor or dtor).
- // Outside the ctors and dtors, the values of vtorDisps are zero.
-
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
- typedef ASTRecordLayout::VBaseOffsetsMapTy VBOffsets;
- const VBOffsets &VBaseMap = Layout.getVBaseOffsetsMap();
- CGBuilderTy &Builder = CGF.Builder;
-
- unsigned AS = getThisAddress(CGF).getAddressSpace();
- llvm::Value *Int8This = nullptr; // Initialize lazily.
-
- for (const CXXBaseSpecifier &S : RD->vbases()) {
- const CXXRecordDecl *VBase = S.getType()->getAsCXXRecordDecl();
- auto I = VBaseMap.find(VBase);
- assert(I != VBaseMap.end());
- if (!I->second.hasVtorDisp())
- continue;
-
- llvm::Value *VBaseOffset =
- GetVirtualBaseClassOffset(CGF, getThisAddress(CGF), RD, VBase);
- uint64_t ConstantVBaseOffset = I->second.VBaseOffset.getQuantity();
-
- // vtorDisp_for_vbase = vbptr[vbase_idx] - offsetof(RD, vbase).
- llvm::Value *VtorDispValue = Builder.CreateSub(
- VBaseOffset, llvm::ConstantInt::get(CGM.PtrDiffTy, ConstantVBaseOffset),
- "vtordisp.value");
- VtorDispValue = Builder.CreateTruncOrBitCast(VtorDispValue, CGF.Int32Ty);
-
- if (!Int8This)
- Int8This = Builder.CreateBitCast(getThisValue(CGF),
- CGF.Int8Ty->getPointerTo(AS));
- llvm::Value *VtorDispPtr = Builder.CreateInBoundsGEP(Int8This, VBaseOffset);
- // vtorDisp is always the 32-bits before the vbase in the class layout.
- VtorDispPtr = Builder.CreateConstGEP1_32(VtorDispPtr, -4);
- VtorDispPtr = Builder.CreateBitCast(
- VtorDispPtr, CGF.Int32Ty->getPointerTo(AS), "vtordisp.ptr");
-
- Builder.CreateAlignedStore(VtorDispValue, VtorDispPtr,
- CharUnits::fromQuantity(4));
- }
-}
-
-static bool hasDefaultCXXMethodCC(ASTContext &Context,
- const CXXMethodDecl *MD) {
- CallingConv ExpectedCallingConv = Context.getDefaultCallingConvention(
- /*IsVariadic=*/false, /*IsCXXMethod=*/true);
- CallingConv ActualCallingConv =
- MD->getType()->getAs<FunctionProtoType>()->getCallConv();
- return ExpectedCallingConv == ActualCallingConv;
-}
-
-void MicrosoftCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
- // There's only one constructor type in this ABI.
- CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
-
- // Exported default constructors either have a simple call-site where they use
- // the typical calling convention and have a single 'this' pointer for an
- // argument -or- they get a wrapper function which appropriately thunks to the
- // real default constructor. This thunk is the default constructor closure.
- if (D->hasAttr<DLLExportAttr>() && D->isDefaultConstructor())
- if (!hasDefaultCXXMethodCC(getContext(), D) || D->getNumParams() != 0) {
- llvm::Function *Fn = getAddrOfCXXCtorClosure(D, Ctor_DefaultClosure);
- Fn->setLinkage(llvm::GlobalValue::WeakODRLinkage);
- CGM.setGVProperties(Fn, D);
- }
-}
-
-void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF,
- const CXXRecordDecl *RD) {
- Address This = getThisAddress(CGF);
- This = CGF.Builder.CreateElementBitCast(This, CGM.Int8Ty, "this.int8");
- const ASTContext &Context = getContext();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- const VBTableGlobals &VBGlobals = enumerateVBTables(RD);
- for (unsigned I = 0, E = VBGlobals.VBTables->size(); I != E; ++I) {
- const std::unique_ptr<VPtrInfo> &VBT = (*VBGlobals.VBTables)[I];
- llvm::GlobalVariable *GV = VBGlobals.Globals[I];
- const ASTRecordLayout &SubobjectLayout =
- Context.getASTRecordLayout(VBT->IntroducingObject);
- CharUnits Offs = VBT->NonVirtualOffset;
- Offs += SubobjectLayout.getVBPtrOffset();
- if (VBT->getVBaseWithVPtr())
- Offs += Layout.getVBaseClassOffset(VBT->getVBaseWithVPtr());
- Address VBPtr = CGF.Builder.CreateConstInBoundsByteGEP(This, Offs);
- llvm::Value *GVPtr =
- CGF.Builder.CreateConstInBoundsGEP2_32(GV->getValueType(), GV, 0, 0);
- VBPtr = CGF.Builder.CreateElementBitCast(VBPtr, GVPtr->getType(),
- "vbptr." + VBT->ObjectWithVPtr->getName());
- CGF.Builder.CreateStore(GVPtr, VBPtr);
- }
-}
-
-CGCXXABI::AddedStructorArgs
-MicrosoftCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) {
- AddedStructorArgs Added;
- // TODO: 'for base' flag
- if (T == StructorType::Deleting) {
- // The scalar deleting destructor takes an implicit int parameter.
- ArgTys.push_back(getContext().IntTy);
- ++Added.Suffix;
- }
- auto *CD = dyn_cast<CXXConstructorDecl>(MD);
- if (!CD)
- return Added;
-
- // All parameters are already in place except is_most_derived, which goes
- // after 'this' if it's variadic and last if it's not.
-
- const CXXRecordDecl *Class = CD->getParent();
- const FunctionProtoType *FPT = CD->getType()->castAs<FunctionProtoType>();
- if (Class->getNumVBases()) {
- if (FPT->isVariadic()) {
- ArgTys.insert(ArgTys.begin() + 1, getContext().IntTy);
- ++Added.Prefix;
- } else {
- ArgTys.push_back(getContext().IntTy);
- ++Added.Suffix;
- }
- }
-
- return Added;
-}
-
-void MicrosoftCXXABI::setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const {
- // Deleting destructor variants are never imported or exported. Give them the
- // default storage class.
- if (DT == Dtor_Deleting) {
- GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
- } else {
- const NamedDecl *ND = Dtor;
- CGM.setDLLImportDLLExport(GV, ND);
- }
-}
-
-llvm::GlobalValue::LinkageTypes MicrosoftCXXABI::getCXXDestructorLinkage(
- GVALinkage Linkage, const CXXDestructorDecl *Dtor, CXXDtorType DT) const {
- // Internal things are always internal, regardless of attributes. After this,
- // we know the thunk is externally visible.
- if (Linkage == GVA_Internal)
- return llvm::GlobalValue::InternalLinkage;
-
- switch (DT) {
- case Dtor_Base:
- // The base destructor most closely tracks the user-declared constructor, so
- // we delegate back to the normal declarator case.
- return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage,
- /*isConstantVariable=*/false);
- case Dtor_Complete:
- // The complete destructor is like an inline function, but it may be
- // imported and therefore must be exported as well. This requires changing
- // the linkage if a DLL attribute is present.
- if (Dtor->hasAttr<DLLExportAttr>())
- return llvm::GlobalValue::WeakODRLinkage;
- if (Dtor->hasAttr<DLLImportAttr>())
- return llvm::GlobalValue::AvailableExternallyLinkage;
- return llvm::GlobalValue::LinkOnceODRLinkage;
- case Dtor_Deleting:
- // Deleting destructors are like inline functions. They have vague linkage
- // and are emitted everywhere they are used. They are internal if the class
- // is internal.
- return llvm::GlobalValue::LinkOnceODRLinkage;
- case Dtor_Comdat:
- llvm_unreachable("MS C++ ABI does not support comdat dtors");
- }
- llvm_unreachable("invalid dtor type");
-}
-
-void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
- // The TU defining a dtor is only guaranteed to emit a base destructor. All
- // other destructor variants are delegating thunks.
- CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
-}
-
-CharUnits
-MicrosoftCXXABI::getVirtualFunctionPrologueThisAdjustment(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // Complete destructors take a pointer to the complete object as a
- // parameter, thus don't need this adjustment.
- if (GD.getDtorType() == Dtor_Complete)
- return CharUnits();
-
- // There's no Dtor_Base in vftable but it shares the this adjustment with
- // the deleting one, so look it up instead.
- GD = GlobalDecl(DD, Dtor_Deleting);
- }
-
- MethodVFTableLocation ML =
- CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
- CharUnits Adjustment = ML.VFPtrOffset;
-
- // Normal virtual instance methods need to adjust from the vfptr that first
- // defined the virtual method to the virtual base subobject, but destructors
- // do not. The vector deleting destructor thunk applies this adjustment for
- // us if necessary.
- if (isa<CXXDestructorDecl>(MD))
- Adjustment = CharUnits::Zero();
-
- if (ML.VBase) {
- const ASTRecordLayout &DerivedLayout =
- getContext().getASTRecordLayout(MD->getParent());
- Adjustment += DerivedLayout.getVBaseClassOffset(ML.VBase);
- }
-
- return Adjustment;
-}
-
-Address MicrosoftCXXABI::adjustThisArgumentForVirtualFunctionCall(
- CodeGenFunction &CGF, GlobalDecl GD, Address This,
- bool VirtualCall) {
- if (!VirtualCall) {
- // If the call of a virtual function is not virtual, we just have to
- // compensate for the adjustment the virtual function does in its prologue.
- CharUnits Adjustment = getVirtualFunctionPrologueThisAdjustment(GD);
- if (Adjustment.isZero())
- return This;
-
- This = CGF.Builder.CreateElementBitCast(This, CGF.Int8Ty);
- assert(Adjustment.isPositive());
- return CGF.Builder.CreateConstByteGEP(This, Adjustment);
- }
-
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- GlobalDecl LookupGD = GD;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // Complete dtors take a pointer to the complete object,
- // thus don't need adjustment.
- if (GD.getDtorType() == Dtor_Complete)
- return This;
-
- // There's only Dtor_Deleting in vftable but it shares the this adjustment
- // with the base one, so look up the deleting one instead.
- LookupGD = GlobalDecl(DD, Dtor_Deleting);
- }
- MethodVFTableLocation ML =
- CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD);
-
- CharUnits StaticOffset = ML.VFPtrOffset;
-
- // Base destructors expect 'this' to point to the beginning of the base
- // subobject, not the first vfptr that happens to contain the virtual dtor.
- // However, we still need to apply the virtual base adjustment.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
- StaticOffset = CharUnits::Zero();
-
- Address Result = This;
- if (ML.VBase) {
- Result = CGF.Builder.CreateElementBitCast(Result, CGF.Int8Ty);
-
- const CXXRecordDecl *Derived = MD->getParent();
- const CXXRecordDecl *VBase = ML.VBase;
- llvm::Value *VBaseOffset =
- GetVirtualBaseClassOffset(CGF, Result, Derived, VBase);
- llvm::Value *VBasePtr =
- CGF.Builder.CreateInBoundsGEP(Result.getPointer(), VBaseOffset);
- CharUnits VBaseAlign =
- CGF.CGM.getVBaseAlignment(Result.getAlignment(), Derived, VBase);
- Result = Address(VBasePtr, VBaseAlign);
- }
- if (!StaticOffset.isZero()) {
- assert(StaticOffset.isPositive());
- Result = CGF.Builder.CreateElementBitCast(Result, CGF.Int8Ty);
- if (ML.VBase) {
- // Non-virtual adjustment might result in a pointer outside the allocated
- // object, e.g. if the final overrider class is laid out after the virtual
- // base that declares a method in the most derived class.
- // FIXME: Update the code that emits this adjustment in thunks prologues.
- Result = CGF.Builder.CreateConstByteGEP(Result, StaticOffset);
- } else {
- Result = CGF.Builder.CreateConstInBoundsByteGEP(Result, StaticOffset);
- }
- }
- return Result;
-}
-
-void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params) {
- ASTContext &Context = getContext();
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
- assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
- if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
- auto *IsMostDerived = ImplicitParamDecl::Create(
- Context, /*DC=*/nullptr, CGF.CurGD.getDecl()->getLocation(),
- &Context.Idents.get("is_most_derived"), Context.IntTy,
- ImplicitParamDecl::Other);
- // The 'most_derived' parameter goes second if the ctor is variadic and last
- // if it's not. Dtors can't be variadic.
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- if (FPT->isVariadic())
- Params.insert(Params.begin() + 1, IsMostDerived);
- else
- Params.push_back(IsMostDerived);
- getStructorImplicitParamDecl(CGF) = IsMostDerived;
- } else if (isDeletingDtor(CGF.CurGD)) {
- auto *ShouldDelete = ImplicitParamDecl::Create(
- Context, /*DC=*/nullptr, CGF.CurGD.getDecl()->getLocation(),
- &Context.Idents.get("should_call_delete"), Context.IntTy,
- ImplicitParamDecl::Other);
- Params.push_back(ShouldDelete);
- getStructorImplicitParamDecl(CGF) = ShouldDelete;
- }
-}
-
-void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
- // Naked functions have no prolog.
- if (CGF.CurFuncDecl && CGF.CurFuncDecl->hasAttr<NakedAttr>())
- return;
-
- // Overridden virtual methods of non-primary bases need to adjust the incoming
- // 'this' pointer in the prologue. In this hierarchy, C::b will subtract
- // sizeof(void*) to adjust from B* to C*:
- // struct A { virtual void a(); };
- // struct B { virtual void b(); };
- // struct C : A, B { virtual void b(); };
- //
- // Leave the value stored in the 'this' alloca unadjusted, so that the
- // debugger sees the unadjusted value. Microsoft debuggers require this, and
- // will apply the ThisAdjustment in the method type information.
- // FIXME: Do something better for DWARF debuggers, which won't expect this,
- // without making our codegen depend on debug info settings.
- llvm::Value *This = loadIncomingCXXThis(CGF);
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
- if (!CGF.CurFuncIsThunk && MD->isVirtual()) {
- CharUnits Adjustment = getVirtualFunctionPrologueThisAdjustment(CGF.CurGD);
- if (!Adjustment.isZero()) {
- unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
- llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS),
- *thisTy = This->getType();
- This = CGF.Builder.CreateBitCast(This, charPtrTy);
- assert(Adjustment.isPositive());
- This = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, This,
- -Adjustment.getQuantity());
- This = CGF.Builder.CreateBitCast(This, thisTy, "this.adjusted");
- }
- }
- setCXXABIThisValue(CGF, This);
-
- // If this is a function that the ABI specifies returns 'this', initialize
- // the return slot to 'this' at the start of the function.
- //
- // Unlike the setting of return types, this is done within the ABI
- // implementation instead of by clients of CGCXXABI because:
- // 1) getThisValue is currently protected
- // 2) in theory, an ABI could implement 'this' returns some other way;
- // HasThisReturn only specifies a contract, not the implementation
- if (HasThisReturn(CGF.CurGD))
- CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
- else if (hasMostDerivedReturn(CGF.CurGD))
- CGF.Builder.CreateStore(CGF.EmitCastToVoidPtr(getThisValue(CGF)),
- CGF.ReturnValue);
-
- if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
- assert(getStructorImplicitParamDecl(CGF) &&
- "no implicit parameter for a constructor with virtual bases?");
- getStructorImplicitParamValue(CGF)
- = CGF.Builder.CreateLoad(
- CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
- "is_most_derived");
- }
-
- if (isDeletingDtor(CGF.CurGD)) {
- assert(getStructorImplicitParamDecl(CGF) &&
- "no implicit parameter for a deleting destructor?");
- getStructorImplicitParamValue(CGF)
- = CGF.Builder.CreateLoad(
- CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
- "should_call_delete");
- }
-}
-
-CGCXXABI::AddedStructorArgs MicrosoftCXXABI::addImplicitConstructorArgs(
- CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, bool Delegating, CallArgList &Args) {
- assert(Type == Ctor_Complete || Type == Ctor_Base);
-
- // Check if we need a 'most_derived' parameter.
- if (!D->getParent()->getNumVBases())
- return AddedStructorArgs{};
-
- // Add the 'most_derived' argument second if we are variadic or last if not.
- const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
- llvm::Value *MostDerivedArg;
- if (Delegating) {
- MostDerivedArg = getStructorImplicitParamValue(CGF);
- } else {
- MostDerivedArg = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete);
- }
- RValue RV = RValue::get(MostDerivedArg);
- if (FPT->isVariadic()) {
- Args.insert(Args.begin() + 1, CallArg(RV, getContext().IntTy));
- return AddedStructorArgs::prefix(1);
- }
- Args.add(RV, getContext().IntTy);
- return AddedStructorArgs::suffix(1);
-}
-
-void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *DD,
- CXXDtorType Type, bool ForVirtualBase,
- bool Delegating, Address This) {
- // Use the base destructor variant in place of the complete destructor variant
- // if the class has no virtual bases. This effectively implements some of the
- // -mconstructor-aliases optimization, but as part of the MS C++ ABI.
- if (Type == Dtor_Complete && DD->getParent()->getNumVBases() == 0)
- Type = Dtor_Base;
-
- CGCallee Callee =
- CGCallee::forDirect(CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type)),
- GlobalDecl(DD, Type));
-
- if (DD->isVirtual()) {
- assert(Type != CXXDtorType::Dtor_Deleting &&
- "The deleting destructor should only be called via a virtual call");
- This = adjustThisArgumentForVirtualFunctionCall(CGF, GlobalDecl(DD, Type),
- This, false);
- }
-
- llvm::BasicBlock *BaseDtorEndBB = nullptr;
- if (ForVirtualBase && isa<CXXConstructorDecl>(CGF.CurCodeDecl)) {
- BaseDtorEndBB = EmitDtorCompleteObjectHandler(CGF);
- }
-
- CGF.EmitCXXDestructorCall(DD, Callee, This.getPointer(),
- /*ImplicitParam=*/nullptr,
- /*ImplicitParamTy=*/QualType(), nullptr,
- getFromDtorType(Type));
- if (BaseDtorEndBB) {
- // Complete object handler should continue to be the remaining
- CGF.Builder.CreateBr(BaseDtorEndBB);
- CGF.EmitBlock(BaseDtorEndBB);
- }
-}
-
-void MicrosoftCXXABI::emitVTableTypeMetadata(const VPtrInfo &Info,
- const CXXRecordDecl *RD,
- llvm::GlobalVariable *VTable) {
- if (!CGM.getCodeGenOpts().LTOUnit)
- return;
-
- // The location of the first virtual function pointer in the virtual table,
- // aka the "address point" on Itanium. This is at offset 0 if RTTI is
- // disabled, or sizeof(void*) if RTTI is enabled.
- CharUnits AddressPoint =
- getContext().getLangOpts().RTTIData
- ? getContext().toCharUnitsFromBits(
- getContext().getTargetInfo().getPointerWidth(0))
- : CharUnits::Zero();
-
- if (Info.PathToIntroducingObject.empty()) {
- CGM.AddVTableTypeMetadata(VTable, AddressPoint, RD);
- return;
- }
-
- // Add a bitset entry for the least derived base belonging to this vftable.
- CGM.AddVTableTypeMetadata(VTable, AddressPoint,
- Info.PathToIntroducingObject.back());
-
- // Add a bitset entry for each derived class that is laid out at the same
- // offset as the least derived base.
- for (unsigned I = Info.PathToIntroducingObject.size() - 1; I != 0; --I) {
- const CXXRecordDecl *DerivedRD = Info.PathToIntroducingObject[I - 1];
- const CXXRecordDecl *BaseRD = Info.PathToIntroducingObject[I];
-
- const ASTRecordLayout &Layout =
- getContext().getASTRecordLayout(DerivedRD);
- CharUnits Offset;
- auto VBI = Layout.getVBaseOffsetsMap().find(BaseRD);
- if (VBI == Layout.getVBaseOffsetsMap().end())
- Offset = Layout.getBaseClassOffset(BaseRD);
- else
- Offset = VBI->second.VBaseOffset;
- if (!Offset.isZero())
- return;
- CGM.AddVTableTypeMetadata(VTable, AddressPoint, DerivedRD);
- }
-
- // Finally do the same for the most derived class.
- if (Info.FullOffsetInMDC.isZero())
- CGM.AddVTableTypeMetadata(VTable, AddressPoint, RD);
-}
-
-void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
- const CXXRecordDecl *RD) {
- MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
- const VPtrInfoVector &VFPtrs = VFTContext.getVFPtrOffsets(RD);
-
- for (const std::unique_ptr<VPtrInfo>& Info : VFPtrs) {
- llvm::GlobalVariable *VTable = getAddrOfVTable(RD, Info->FullOffsetInMDC);
- if (VTable->hasInitializer())
- continue;
-
- const VTableLayout &VTLayout =
- VFTContext.getVFTableLayout(RD, Info->FullOffsetInMDC);
-
- llvm::Constant *RTTI = nullptr;
- if (any_of(VTLayout.vtable_components(),
- [](const VTableComponent &VTC) { return VTC.isRTTIKind(); }))
- RTTI = getMSCompleteObjectLocator(RD, *Info);
-
- ConstantInitBuilder Builder(CGM);
- auto Components = Builder.beginStruct();
- CGVT.createVTableInitializer(Components, VTLayout, RTTI);
- Components.finishAndSetAsInitializer(VTable);
-
- emitVTableTypeMetadata(*Info, RD, VTable);
- }
-}
-
-bool MicrosoftCXXABI::isVirtualOffsetNeededForVTableField(
- CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) {
- return Vptr.NearestVBase != nullptr;
-}
-
-llvm::Value *MicrosoftCXXABI::getVTableAddressPointInStructor(
- CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
- const CXXRecordDecl *NearestVBase) {
- llvm::Constant *VTableAddressPoint = getVTableAddressPoint(Base, VTableClass);
- if (!VTableAddressPoint) {
- assert(Base.getBase()->getNumVBases() &&
- !getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
- }
- return VTableAddressPoint;
-}
-
-static void mangleVFTableName(MicrosoftMangleContext &MangleContext,
- const CXXRecordDecl *RD, const VPtrInfo &VFPtr,
- SmallString<256> &Name) {
- llvm::raw_svector_ostream Out(Name);
- MangleContext.mangleCXXVFTable(RD, VFPtr.MangledPath, Out);
-}
-
-llvm::Constant *
-MicrosoftCXXABI::getVTableAddressPoint(BaseSubobject Base,
- const CXXRecordDecl *VTableClass) {
- (void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
- VFTableIdTy ID(VTableClass, Base.getBaseOffset());
- return VFTablesMap[ID];
-}
-
-llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
- BaseSubobject Base, const CXXRecordDecl *VTableClass) {
- llvm::Constant *VFTable = getVTableAddressPoint(Base, VTableClass);
- assert(VFTable && "Couldn't find a vftable for the given base?");
- return VFTable;
-}
-
-llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
- CharUnits VPtrOffset) {
- // getAddrOfVTable may return 0 if asked to get an address of a vtable which
- // shouldn't be used in the given record type. We want to cache this result in
- // VFTablesMap, thus a simple zero check is not sufficient.
-
- VFTableIdTy ID(RD, VPtrOffset);
- VTablesMapTy::iterator I;
- bool Inserted;
- std::tie(I, Inserted) = VTablesMap.insert(std::make_pair(ID, nullptr));
- if (!Inserted)
- return I->second;
-
- llvm::GlobalVariable *&VTable = I->second;
-
- MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext();
- const VPtrInfoVector &VFPtrs = VTContext.getVFPtrOffsets(RD);
-
- if (DeferredVFTables.insert(RD).second) {
- // We haven't processed this record type before.
- // Queue up this vtable for possible deferred emission.
- CGM.addDeferredVTable(RD);
-
-#ifndef NDEBUG
- // Create all the vftables at once in order to make sure each vftable has
- // a unique mangled name.
- llvm::StringSet<> ObservedMangledNames;
- for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
- SmallString<256> Name;
- mangleVFTableName(getMangleContext(), RD, *VFPtrs[J], Name);
- if (!ObservedMangledNames.insert(Name.str()).second)
- llvm_unreachable("Already saw this mangling before?");
- }
-#endif
- }
-
- const std::unique_ptr<VPtrInfo> *VFPtrI = std::find_if(
- VFPtrs.begin(), VFPtrs.end(), [&](const std::unique_ptr<VPtrInfo>& VPI) {
- return VPI->FullOffsetInMDC == VPtrOffset;
- });
- if (VFPtrI == VFPtrs.end()) {
- VFTablesMap[ID] = nullptr;
- return nullptr;
- }
- const std::unique_ptr<VPtrInfo> &VFPtr = *VFPtrI;
-
- SmallString<256> VFTableName;
- mangleVFTableName(getMangleContext(), RD, *VFPtr, VFTableName);
-
- // Classes marked __declspec(dllimport) need vftables generated on the
- // import-side in order to support features like constexpr. No other
- // translation unit relies on the emission of the local vftable, translation
- // units are expected to generate them as needed.
- //
- // Because of this unique behavior, we maintain this logic here instead of
- // getVTableLinkage.
- llvm::GlobalValue::LinkageTypes VFTableLinkage =
- RD->hasAttr<DLLImportAttr>() ? llvm::GlobalValue::LinkOnceODRLinkage
- : CGM.getVTableLinkage(RD);
- bool VFTableComesFromAnotherTU =
- llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage) ||
- llvm::GlobalValue::isExternalLinkage(VFTableLinkage);
- bool VTableAliasIsRequred =
- !VFTableComesFromAnotherTU && getContext().getLangOpts().RTTIData;
-
- if (llvm::GlobalValue *VFTable =
- CGM.getModule().getNamedGlobal(VFTableName)) {
- VFTablesMap[ID] = VFTable;
- VTable = VTableAliasIsRequred
- ? cast<llvm::GlobalVariable>(
- cast<llvm::GlobalAlias>(VFTable)->getBaseObject())
- : cast<llvm::GlobalVariable>(VFTable);
- return VTable;
- }
-
- const VTableLayout &VTLayout =
- VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC);
- llvm::GlobalValue::LinkageTypes VTableLinkage =
- VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage;
-
- StringRef VTableName = VTableAliasIsRequred ? StringRef() : VFTableName.str();
-
- llvm::Type *VTableType = CGM.getVTables().getVTableType(VTLayout);
-
- // Create a backing variable for the contents of VTable. The VTable may
- // or may not include space for a pointer to RTTI data.
- llvm::GlobalValue *VFTable;
- VTable = new llvm::GlobalVariable(CGM.getModule(), VTableType,
- /*isConstant=*/true, VTableLinkage,
- /*Initializer=*/nullptr, VTableName);
- VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- llvm::Comdat *C = nullptr;
- if (!VFTableComesFromAnotherTU &&
- (llvm::GlobalValue::isWeakForLinker(VFTableLinkage) ||
- (llvm::GlobalValue::isLocalLinkage(VFTableLinkage) &&
- VTableAliasIsRequred)))
- C = CGM.getModule().getOrInsertComdat(VFTableName.str());
-
- // Only insert a pointer into the VFTable for RTTI data if we are not
- // importing it. We never reference the RTTI data directly so there is no
- // need to make room for it.
- if (VTableAliasIsRequred) {
- llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.Int32Ty, 0),
- llvm::ConstantInt::get(CGM.Int32Ty, 0),
- llvm::ConstantInt::get(CGM.Int32Ty, 1)};
- // Create a GEP which points just after the first entry in the VFTable,
- // this should be the location of the first virtual method.
- llvm::Constant *VTableGEP = llvm::ConstantExpr::getInBoundsGetElementPtr(
- VTable->getValueType(), VTable, GEPIndices);
- if (llvm::GlobalValue::isWeakForLinker(VFTableLinkage)) {
- VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
- if (C)
- C->setSelectionKind(llvm::Comdat::Largest);
- }
- VFTable = llvm::GlobalAlias::create(CGM.Int8PtrTy,
- /*AddressSpace=*/0, VFTableLinkage,
- VFTableName.str(), VTableGEP,
- &CGM.getModule());
- VFTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- } else {
- // We don't need a GlobalAlias to be a symbol for the VTable if we won't
- // be referencing any RTTI data.
- // The GlobalVariable will end up being an appropriate definition of the
- // VFTable.
- VFTable = VTable;
- }
- if (C)
- VTable->setComdat(C);
-
- if (RD->hasAttr<DLLExportAttr>())
- VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
-
- VFTablesMap[ID] = VFTable;
- return VTable;
-}
-
-CGCallee MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
- GlobalDecl GD,
- Address This,
- llvm::Type *Ty,
- SourceLocation Loc) {
- CGBuilderTy &Builder = CGF.Builder;
-
- Ty = Ty->getPointerTo()->getPointerTo();
- Address VPtr =
- adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
-
- auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
- llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty, MethodDecl->getParent());
-
- MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
- MethodVFTableLocation ML = VFTContext.getMethodVFTableLocation(GD);
-
- // Compute the identity of the most derived class whose virtual table is
- // located at the MethodVFTableLocation ML.
- auto getObjectWithVPtr = [&] {
- return llvm::find_if(VFTContext.getVFPtrOffsets(
- ML.VBase ? ML.VBase : MethodDecl->getParent()),
- [&](const std::unique_ptr<VPtrInfo> &Info) {
- return Info->FullOffsetInMDC == ML.VFPtrOffset;
- })
- ->get()
- ->ObjectWithVPtr;
- };
-
- llvm::Value *VFunc;
- if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) {
- VFunc = CGF.EmitVTableTypeCheckedLoad(
- getObjectWithVPtr(), VTable,
- ML.Index * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8);
- } else {
- if (CGM.getCodeGenOpts().PrepareForLTO)
- CGF.EmitTypeMetadataCodeForVCall(getObjectWithVPtr(), VTable, Loc);
-
- llvm::Value *VFuncPtr =
- Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
- VFunc = Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
- }
-
- CGCallee Callee(GD, VFunc);
- return Callee;
-}
-
-llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
- CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
- Address This, const CXXMemberCallExpr *CE) {
- assert(CE == nullptr || CE->arg_begin() == CE->arg_end());
- assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
-
- // We have only one destructor in the vftable but can get both behaviors
- // by passing an implicit int parameter.
- GlobalDecl GD(Dtor, Dtor_Deleting);
- const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
- Dtor, StructorType::Deleting);
- llvm::FunctionType *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- CGCallee Callee = CGCallee::forVirtual(CE, GD, This, Ty);
-
- ASTContext &Context = getContext();
- llvm::Value *ImplicitParam = llvm::ConstantInt::get(
- llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
- DtorType == Dtor_Deleting);
-
- This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
- RValue RV =
- CGF.EmitCXXDestructorCall(Dtor, Callee, This.getPointer(), ImplicitParam,
- Context.IntTy, CE, StructorType::Deleting);
- return RV.getScalarVal();
-}
-
-const VBTableGlobals &
-MicrosoftCXXABI::enumerateVBTables(const CXXRecordDecl *RD) {
- // At this layer, we can key the cache off of a single class, which is much
- // easier than caching each vbtable individually.
- llvm::DenseMap<const CXXRecordDecl*, VBTableGlobals>::iterator Entry;
- bool Added;
- std::tie(Entry, Added) =
- VBTablesMap.insert(std::make_pair(RD, VBTableGlobals()));
- VBTableGlobals &VBGlobals = Entry->second;
- if (!Added)
- return VBGlobals;
-
- MicrosoftVTableContext &Context = CGM.getMicrosoftVTableContext();
- VBGlobals.VBTables = &Context.enumerateVBTables(RD);
-
- // Cache the globals for all vbtables so we don't have to recompute the
- // mangled names.
- llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
- for (VPtrInfoVector::const_iterator I = VBGlobals.VBTables->begin(),
- E = VBGlobals.VBTables->end();
- I != E; ++I) {
- VBGlobals.Globals.push_back(getAddrOfVBTable(**I, RD, Linkage));
- }
-
- return VBGlobals;
-}
-
-llvm::Function *
-MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
- const MethodVFTableLocation &ML) {
- assert(!isa<CXXConstructorDecl>(MD) && !isa<CXXDestructorDecl>(MD) &&
- "can't form pointers to ctors or virtual dtors");
-
- // Calculate the mangled name.
- SmallString<256> ThunkName;
- llvm::raw_svector_ostream Out(ThunkName);
- getMangleContext().mangleVirtualMemPtrThunk(MD, ML, Out);
-
- // If the thunk has been generated previously, just return it.
- if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
- return cast<llvm::Function>(GV);
-
- // Create the llvm::Function.
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeUnprototypedMustTailThunk(MD);
- llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
- llvm::Function *ThunkFn =
- llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage,
- ThunkName.str(), &CGM.getModule());
- assert(ThunkFn->getName() == ThunkName && "name was uniqued!");
-
- ThunkFn->setLinkage(MD->isExternallyVisible()
- ? llvm::GlobalValue::LinkOnceODRLinkage
- : llvm::GlobalValue::InternalLinkage);
- if (MD->isExternallyVisible())
- ThunkFn->setComdat(CGM.getModule().getOrInsertComdat(ThunkFn->getName()));
-
- CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
- CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);
-
- // Add the "thunk" attribute so that LLVM knows that the return type is
- // meaningless. These thunks can be used to call functions with differing
- // return types, and the caller is required to cast the prototype
- // appropriately to extract the correct value.
- ThunkFn->addFnAttr("thunk");
-
- // These thunks can be compared, so they are not unnamed.
- ThunkFn->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
-
- // Start codegen.
- CodeGenFunction CGF(CGM);
- CGF.CurGD = GlobalDecl(MD);
- CGF.CurFuncIsThunk = true;
-
- // Build FunctionArgs, but only include the implicit 'this' parameter
- // declaration.
- FunctionArgList FunctionArgs;
- buildThisParam(CGF, FunctionArgs);
-
- // Start defining the function.
- CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
- FunctionArgs, MD->getLocation(), SourceLocation());
- setCXXABIThisValue(CGF, loadIncomingCXXThis(CGF));
-
- // Load the vfptr and then callee from the vftable. The callee should have
- // adjusted 'this' so that the vfptr is at offset zero.
- llvm::Value *VTable = CGF.GetVTablePtr(
- getThisAddress(CGF), ThunkTy->getPointerTo()->getPointerTo(), MD->getParent());
-
- llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
- llvm::Value *Callee =
- CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
-
- CGF.EmitMustTailThunk(MD, getThisValue(CGF), Callee);
-
- return ThunkFn;
-}
-
-void MicrosoftCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
- const VBTableGlobals &VBGlobals = enumerateVBTables(RD);
- for (unsigned I = 0, E = VBGlobals.VBTables->size(); I != E; ++I) {
- const std::unique_ptr<VPtrInfo>& VBT = (*VBGlobals.VBTables)[I];
- llvm::GlobalVariable *GV = VBGlobals.Globals[I];
- if (GV->isDeclaration())
- emitVBTableDefinition(*VBT, RD, GV);
- }
-}
-
-llvm::GlobalVariable *
-MicrosoftCXXABI::getAddrOfVBTable(const VPtrInfo &VBT, const CXXRecordDecl *RD,
- llvm::GlobalVariable::LinkageTypes Linkage) {
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- getMangleContext().mangleCXXVBTable(RD, VBT.MangledPath, Out);
- StringRef Name = OutName.str();
-
- llvm::ArrayType *VBTableType =
- llvm::ArrayType::get(CGM.IntTy, 1 + VBT.ObjectWithVPtr->getNumVBases());
-
- assert(!CGM.getModule().getNamedGlobal(Name) &&
- "vbtable with this name already exists: mangling bug?");
- CharUnits Alignment =
- CGM.getContext().getTypeAlignInChars(CGM.getContext().IntTy);
- llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name, VBTableType, Linkage, Alignment.getQuantity());
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- if (RD->hasAttr<DLLImportAttr>())
- GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- else if (RD->hasAttr<DLLExportAttr>())
- GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
-
- if (!GV->hasExternalLinkage())
- emitVBTableDefinition(VBT, RD, GV);
-
- return GV;
-}
-
-void MicrosoftCXXABI::emitVBTableDefinition(const VPtrInfo &VBT,
- const CXXRecordDecl *RD,
- llvm::GlobalVariable *GV) const {
- const CXXRecordDecl *ObjectWithVPtr = VBT.ObjectWithVPtr;
-
- assert(RD->getNumVBases() && ObjectWithVPtr->getNumVBases() &&
- "should only emit vbtables for classes with vbtables");
-
- const ASTRecordLayout &BaseLayout =
- getContext().getASTRecordLayout(VBT.IntroducingObject);
- const ASTRecordLayout &DerivedLayout = getContext().getASTRecordLayout(RD);
-
- SmallVector<llvm::Constant *, 4> Offsets(1 + ObjectWithVPtr->getNumVBases(),
- nullptr);
-
- // The offset from ObjectWithVPtr's vbptr to itself always leads.
- CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset();
- Offsets[0] = llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity());
-
- MicrosoftVTableContext &Context = CGM.getMicrosoftVTableContext();
- for (const auto &I : ObjectWithVPtr->vbases()) {
- const CXXRecordDecl *VBase = I.getType()->getAsCXXRecordDecl();
- CharUnits Offset = DerivedLayout.getVBaseClassOffset(VBase);
- assert(!Offset.isNegative());
-
- // Make it relative to the subobject vbptr.
- CharUnits CompleteVBPtrOffset = VBT.NonVirtualOffset + VBPtrOffset;
- if (VBT.getVBaseWithVPtr())
- CompleteVBPtrOffset +=
- DerivedLayout.getVBaseClassOffset(VBT.getVBaseWithVPtr());
- Offset -= CompleteVBPtrOffset;
-
- unsigned VBIndex = Context.getVBTableIndex(ObjectWithVPtr, VBase);
- assert(Offsets[VBIndex] == nullptr && "The same vbindex seen twice?");
- Offsets[VBIndex] = llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity());
- }
-
- assert(Offsets.size() ==
- cast<llvm::ArrayType>(cast<llvm::PointerType>(GV->getType())
- ->getElementType())->getNumElements());
- llvm::ArrayType *VBTableType =
- llvm::ArrayType::get(CGM.IntTy, Offsets.size());
- llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
- GV->setInitializer(Init);
-
- if (RD->hasAttr<DLLImportAttr>())
- GV->setLinkage(llvm::GlobalVariable::AvailableExternallyLinkage);
-}
-
-llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,
- Address This,
- const ThisAdjustment &TA) {
- if (TA.isEmpty())
- return This.getPointer();
-
- This = CGF.Builder.CreateElementBitCast(This, CGF.Int8Ty);
-
- llvm::Value *V;
- if (TA.Virtual.isEmpty()) {
- V = This.getPointer();
- } else {
- assert(TA.Virtual.Microsoft.VtordispOffset < 0);
- // Adjust the this argument based on the vtordisp value.
- Address VtorDispPtr =
- CGF.Builder.CreateConstInBoundsByteGEP(This,
- CharUnits::fromQuantity(TA.Virtual.Microsoft.VtordispOffset));
- VtorDispPtr = CGF.Builder.CreateElementBitCast(VtorDispPtr, CGF.Int32Ty);
- llvm::Value *VtorDisp = CGF.Builder.CreateLoad(VtorDispPtr, "vtordisp");
- V = CGF.Builder.CreateGEP(This.getPointer(),
- CGF.Builder.CreateNeg(VtorDisp));
-
- // Unfortunately, having applied the vtordisp means that we no
- // longer really have a known alignment for the vbptr step.
- // We'll assume the vbptr is pointer-aligned.
-
- if (TA.Virtual.Microsoft.VBPtrOffset) {
- // If the final overrider is defined in a virtual base other than the one
- // that holds the vfptr, we have to use a vtordispex thunk which looks up
- // the vbtable of the derived class.
- assert(TA.Virtual.Microsoft.VBPtrOffset > 0);
- assert(TA.Virtual.Microsoft.VBOffsetOffset >= 0);
- llvm::Value *VBPtr;
- llvm::Value *VBaseOffset =
- GetVBaseOffsetFromVBPtr(CGF, Address(V, CGF.getPointerAlign()),
- -TA.Virtual.Microsoft.VBPtrOffset,
- TA.Virtual.Microsoft.VBOffsetOffset, &VBPtr);
- V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset);
- }
- }
-
- if (TA.NonVirtual) {
- // Non-virtual adjustment might result in a pointer outside the allocated
- // object, e.g. if the final overrider class is laid out after the virtual
- // base that declares a method in the most derived class.
- V = CGF.Builder.CreateConstGEP1_32(V, TA.NonVirtual);
- }
-
- // Don't need to bitcast back, the call CodeGen will handle this.
- return V;
-}
-
-llvm::Value *
-MicrosoftCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret,
- const ReturnAdjustment &RA) {
- if (RA.isEmpty())
- return Ret.getPointer();
-
- auto OrigTy = Ret.getType();
- Ret = CGF.Builder.CreateElementBitCast(Ret, CGF.Int8Ty);
-
- llvm::Value *V = Ret.getPointer();
- if (RA.Virtual.Microsoft.VBIndex) {
- assert(RA.Virtual.Microsoft.VBIndex > 0);
- int32_t IntSize = CGF.getIntSize().getQuantity();
- llvm::Value *VBPtr;
- llvm::Value *VBaseOffset =
- GetVBaseOffsetFromVBPtr(CGF, Ret, RA.Virtual.Microsoft.VBPtrOffset,
- IntSize * RA.Virtual.Microsoft.VBIndex, &VBPtr);
- V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset);
- }
-
- if (RA.NonVirtual)
- V = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, V, RA.NonVirtual);
-
- // Cast back to the original type.
- return CGF.Builder.CreateBitCast(V, OrigTy);
-}
-
-bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
- QualType elementType) {
- // Microsoft seems to completely ignore the possibility of a
- // two-argument usual deallocation function.
- return elementType.isDestructedType();
-}
-
-bool MicrosoftCXXABI::requiresArrayCookie(const CXXNewExpr *expr) {
- // Microsoft seems to completely ignore the possibility of a
- // two-argument usual deallocation function.
- return expr->getAllocatedType().isDestructedType();
-}
-
-CharUnits MicrosoftCXXABI::getArrayCookieSizeImpl(QualType type) {
- // The array cookie is always a size_t; we then pad that out to the
- // alignment of the element type.
- ASTContext &Ctx = getContext();
- return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
- Ctx.getTypeAlignInChars(type));
-}
-
-llvm::Value *MicrosoftCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
- Address allocPtr,
- CharUnits cookieSize) {
- Address numElementsPtr =
- CGF.Builder.CreateElementBitCast(allocPtr, CGF.SizeTy);
- return CGF.Builder.CreateLoad(numElementsPtr);
-}
-
-Address MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
- Address newPtr,
- llvm::Value *numElements,
- const CXXNewExpr *expr,
- QualType elementType) {
- assert(requiresArrayCookie(expr));
-
- // The size of the cookie.
- CharUnits cookieSize = getArrayCookieSizeImpl(elementType);
-
- // Compute an offset to the cookie.
- Address cookiePtr = newPtr;
-
- // Write the number of elements into the appropriate slot.
- Address numElementsPtr
- = CGF.Builder.CreateElementBitCast(cookiePtr, CGF.SizeTy);
- CGF.Builder.CreateStore(numElements, numElementsPtr);
-
- // Finally, compute a pointer to the actual data buffer by skipping
- // over the cookie completely.
- return CGF.Builder.CreateConstInBoundsByteGEP(newPtr, cookieSize);
-}
-
-static void emitGlobalDtorWithTLRegDtor(CodeGenFunction &CGF, const VarDecl &VD,
- llvm::Constant *Dtor,
- llvm::Constant *Addr) {
- // Create a function which calls the destructor.
- llvm::Constant *DtorStub = CGF.createAtExitStub(VD, Dtor, Addr);
-
- // extern "C" int __tlregdtor(void (*f)(void));
- llvm::FunctionType *TLRegDtorTy = llvm::FunctionType::get(
- CGF.IntTy, DtorStub->getType(), /*IsVarArg=*/false);
-
- llvm::Constant *TLRegDtor = CGF.CGM.CreateRuntimeFunction(
- TLRegDtorTy, "__tlregdtor", llvm::AttributeList(), /*Local=*/true);
- if (llvm::Function *TLRegDtorFn = dyn_cast<llvm::Function>(TLRegDtor))
- TLRegDtorFn->setDoesNotThrow();
-
- CGF.EmitNounwindRuntimeCall(TLRegDtor, DtorStub);
-}
-
-void MicrosoftCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *Dtor,
- llvm::Constant *Addr) {
- if (D.isNoDestroy(CGM.getContext()))
- return;
-
- if (D.getTLSKind())
- return emitGlobalDtorWithTLRegDtor(CGF, D, Dtor, Addr);
-
- // The default behavior is to use atexit.
- CGF.registerGlobalDtorWithAtExit(D, Dtor, Addr);
-}
-
-void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
- CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
- ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {
- if (CXXThreadLocalInits.empty())
- return;
-
- CGM.AppendLinkerOptions(CGM.getTarget().getTriple().getArch() ==
- llvm::Triple::x86
- ? "/include:___dyn_tls_init@12"
- : "/include:__dyn_tls_init");
-
- // This will create a GV in the .CRT$XDU section. It will point to our
- // initialization function. The CRT will call all of these function
- // pointers at start-up time and, eventually, at thread-creation time.
- auto AddToXDU = [&CGM](llvm::Function *InitFunc) {
- llvm::GlobalVariable *InitFuncPtr = new llvm::GlobalVariable(
- CGM.getModule(), InitFunc->getType(), /*IsConstant=*/true,
- llvm::GlobalVariable::InternalLinkage, InitFunc,
- Twine(InitFunc->getName(), "$initializer$"));
- InitFuncPtr->setSection(".CRT$XDU");
- // This variable has discardable linkage, we have to add it to @llvm.used to
- // ensure it won't get discarded.
- CGM.addUsedGlobal(InitFuncPtr);
- return InitFuncPtr;
- };
-
- std::vector<llvm::Function *> NonComdatInits;
- for (size_t I = 0, E = CXXThreadLocalInitVars.size(); I != E; ++I) {
- llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(
- CGM.GetGlobalValue(CGM.getMangledName(CXXThreadLocalInitVars[I])));
- llvm::Function *F = CXXThreadLocalInits[I];
-
- // If the GV is already in a comdat group, then we have to join it.
- if (llvm::Comdat *C = GV->getComdat())
- AddToXDU(F)->setComdat(C);
- else
- NonComdatInits.push_back(F);
- }
-
- if (!NonComdatInits.empty()) {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
- llvm::Function *InitFunc = CGM.CreateGlobalInitOrDestructFunction(
- FTy, "__tls_init", CGM.getTypes().arrangeNullaryFunction(),
- SourceLocation(), /*TLS=*/true);
- CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(InitFunc, NonComdatInits);
-
- AddToXDU(InitFunc);
- }
-}
-
-LValue MicrosoftCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
- const VarDecl *VD,
- QualType LValType) {
- CGF.CGM.ErrorUnsupported(VD, "thread wrappers");
- return LValue();
-}
-
-static ConstantAddress getInitThreadEpochPtr(CodeGenModule &CGM) {
- StringRef VarName("_Init_thread_epoch");
- CharUnits Align = CGM.getIntAlign();
- if (auto *GV = CGM.getModule().getNamedGlobal(VarName))
- return ConstantAddress(GV, Align);
- auto *GV = new llvm::GlobalVariable(
- CGM.getModule(), CGM.IntTy,
- /*Constant=*/false, llvm::GlobalVariable::ExternalLinkage,
- /*Initializer=*/nullptr, VarName,
- /*InsertBefore=*/nullptr, llvm::GlobalVariable::GeneralDynamicTLSModel);
- GV->setAlignment(Align.getQuantity());
- return ConstantAddress(GV, Align);
-}
-
-static llvm::Constant *getInitThreadHeaderFn(CodeGenModule &CGM) {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(
- FTy, "_Init_thread_header",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind),
- /*Local=*/true);
-}
-
-static llvm::Constant *getInitThreadFooterFn(CodeGenModule &CGM) {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(
- FTy, "_Init_thread_footer",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind),
- /*Local=*/true);
-}
-
-static llvm::Constant *getInitThreadAbortFn(CodeGenModule &CGM) {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(
- FTy, "_Init_thread_abort",
- llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind),
- /*Local=*/true);
-}
-
-namespace {
-struct ResetGuardBit final : EHScopeStack::Cleanup {
- Address Guard;
- unsigned GuardNum;
- ResetGuardBit(Address Guard, unsigned GuardNum)
- : Guard(Guard), GuardNum(GuardNum) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Reset the bit in the mask so that the static variable may be
- // reinitialized.
- CGBuilderTy &Builder = CGF.Builder;
- llvm::LoadInst *LI = Builder.CreateLoad(Guard);
- llvm::ConstantInt *Mask =
- llvm::ConstantInt::get(CGF.IntTy, ~(1ULL << GuardNum));
- Builder.CreateStore(Builder.CreateAnd(LI, Mask), Guard);
- }
-};
-
-struct CallInitThreadAbort final : EHScopeStack::Cleanup {
- llvm::Value *Guard;
- CallInitThreadAbort(Address Guard) : Guard(Guard.getPointer()) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- // Calling _Init_thread_abort will reset the guard's state.
- CGF.EmitNounwindRuntimeCall(getInitThreadAbortFn(CGF.CGM), Guard);
- }
-};
-}
-
-void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *GV,
- bool PerformInit) {
- // MSVC only uses guards for static locals.
- if (!D.isStaticLocal()) {
- assert(GV->hasWeakLinkage() || GV->hasLinkOnceLinkage());
- // GlobalOpt is allowed to discard the initializer, so use linkonce_odr.
- llvm::Function *F = CGF.CurFn;
- F->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
- F->setComdat(CGM.getModule().getOrInsertComdat(F->getName()));
- CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
- return;
- }
-
- bool ThreadlocalStatic = D.getTLSKind();
- bool ThreadsafeStatic = getContext().getLangOpts().ThreadsafeStatics;
-
- // Thread-safe static variables which aren't thread-specific have a
- // per-variable guard.
- bool HasPerVariableGuard = ThreadsafeStatic && !ThreadlocalStatic;
-
- CGBuilderTy &Builder = CGF.Builder;
- llvm::IntegerType *GuardTy = CGF.Int32Ty;
- llvm::ConstantInt *Zero = llvm::ConstantInt::get(GuardTy, 0);
- CharUnits GuardAlign = CharUnits::fromQuantity(4);
-
- // Get the guard variable for this function if we have one already.
- GuardInfo *GI = nullptr;
- if (ThreadlocalStatic)
- GI = &ThreadLocalGuardVariableMap[D.getDeclContext()];
- else if (!ThreadsafeStatic)
- GI = &GuardVariableMap[D.getDeclContext()];
-
- llvm::GlobalVariable *GuardVar = GI ? GI->Guard : nullptr;
- unsigned GuardNum;
- if (D.isExternallyVisible()) {
- // Externally visible variables have to be numbered in Sema to properly
- // handle unreachable VarDecls.
- GuardNum = getContext().getStaticLocalNumber(&D);
- assert(GuardNum > 0);
- GuardNum--;
- } else if (HasPerVariableGuard) {
- GuardNum = ThreadSafeGuardNumMap[D.getDeclContext()]++;
- } else {
- // Non-externally visible variables are numbered here in CodeGen.
- GuardNum = GI->BitIndex++;
- }
-
- if (!HasPerVariableGuard && GuardNum >= 32) {
- if (D.isExternallyVisible())
- ErrorUnsupportedABI(CGF, "more than 32 guarded initializations");
- GuardNum %= 32;
- GuardVar = nullptr;
- }
-
- if (!GuardVar) {
- // Mangle the name for the guard.
- SmallString<256> GuardName;
- {
- llvm::raw_svector_ostream Out(GuardName);
- if (HasPerVariableGuard)
- getMangleContext().mangleThreadSafeStaticGuardVariable(&D, GuardNum,
- Out);
- else
- getMangleContext().mangleStaticGuardVariable(&D, Out);
- }
-
- // Create the guard variable with a zero-initializer. Just absorb linkage,
- // visibility and dll storage class from the guarded variable.
- GuardVar =
- new llvm::GlobalVariable(CGM.getModule(), GuardTy, /*isConstant=*/false,
- GV->getLinkage(), Zero, GuardName.str());
- GuardVar->setVisibility(GV->getVisibility());
- GuardVar->setDLLStorageClass(GV->getDLLStorageClass());
- GuardVar->setAlignment(GuardAlign.getQuantity());
- if (GuardVar->isWeakForLinker())
- GuardVar->setComdat(
- CGM.getModule().getOrInsertComdat(GuardVar->getName()));
- if (D.getTLSKind())
- GuardVar->setThreadLocal(true);
- if (GI && !HasPerVariableGuard)
- GI->Guard = GuardVar;
- }
-
- ConstantAddress GuardAddr(GuardVar, GuardAlign);
-
- assert(GuardVar->getLinkage() == GV->getLinkage() &&
- "static local from the same function had different linkage");
-
- if (!HasPerVariableGuard) {
- // Pseudo code for the test:
- // if (!(GuardVar & MyGuardBit)) {
- // GuardVar |= MyGuardBit;
- // ... initialize the object ...;
- // }
-
- // Test our bit from the guard variable.
- llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1ULL << GuardNum);
- llvm::LoadInst *LI = Builder.CreateLoad(GuardAddr);
- llvm::Value *NeedsInit =
- Builder.CreateICmpEQ(Builder.CreateAnd(LI, Bit), Zero);
- llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
- llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
- CGF.EmitCXXGuardedInitBranch(NeedsInit, InitBlock, EndBlock,
- CodeGenFunction::GuardKind::VariableGuard, &D);
-
- // Set our bit in the guard variable and emit the initializer and add a global
- // destructor if appropriate.
- CGF.EmitBlock(InitBlock);
- Builder.CreateStore(Builder.CreateOr(LI, Bit), GuardAddr);
- CGF.EHStack.pushCleanup<ResetGuardBit>(EHCleanup, GuardAddr, GuardNum);
- CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
- CGF.PopCleanupBlock();
- Builder.CreateBr(EndBlock);
-
- // Continue.
- CGF.EmitBlock(EndBlock);
- } else {
- // Pseudo code for the test:
- // if (TSS > _Init_thread_epoch) {
- // _Init_thread_header(&TSS);
- // if (TSS == -1) {
- // ... initialize the object ...;
- // _Init_thread_footer(&TSS);
- // }
- // }
- //
- // The algorithm is almost identical to what can be found in the appendix
- // found in N2325.
-
- // This BasicBLock determines whether or not we have any work to do.
- llvm::LoadInst *FirstGuardLoad = Builder.CreateLoad(GuardAddr);
- FirstGuardLoad->setOrdering(llvm::AtomicOrdering::Unordered);
- llvm::LoadInst *InitThreadEpoch =
- Builder.CreateLoad(getInitThreadEpochPtr(CGM));
- llvm::Value *IsUninitialized =
- Builder.CreateICmpSGT(FirstGuardLoad, InitThreadEpoch);
- llvm::BasicBlock *AttemptInitBlock = CGF.createBasicBlock("init.attempt");
- llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
- CGF.EmitCXXGuardedInitBranch(IsUninitialized, AttemptInitBlock, EndBlock,
- CodeGenFunction::GuardKind::VariableGuard, &D);
-
- // This BasicBlock attempts to determine whether or not this thread is
- // responsible for doing the initialization.
- CGF.EmitBlock(AttemptInitBlock);
- CGF.EmitNounwindRuntimeCall(getInitThreadHeaderFn(CGM),
- GuardAddr.getPointer());
- llvm::LoadInst *SecondGuardLoad = Builder.CreateLoad(GuardAddr);
- SecondGuardLoad->setOrdering(llvm::AtomicOrdering::Unordered);
- llvm::Value *ShouldDoInit =
- Builder.CreateICmpEQ(SecondGuardLoad, getAllOnesInt());
- llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
- Builder.CreateCondBr(ShouldDoInit, InitBlock, EndBlock);
-
- // Ok, we ended up getting selected as the initializing thread.
- CGF.EmitBlock(InitBlock);
- CGF.EHStack.pushCleanup<CallInitThreadAbort>(EHCleanup, GuardAddr);
- CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
- CGF.PopCleanupBlock();
- CGF.EmitNounwindRuntimeCall(getInitThreadFooterFn(CGM),
- GuardAddr.getPointer());
- Builder.CreateBr(EndBlock);
-
- CGF.EmitBlock(EndBlock);
- }
-}
-
-bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
- // Null-ness for function memptrs only depends on the first field, which is
- // the function pointer. The rest don't matter, so we can zero initialize.
- if (MPT->isMemberFunctionPointer())
- return true;
-
- // The virtual base adjustment field is always -1 for null, so if we have one
- // we can't zero initialize. The field offset is sometimes also -1 if 0 is a
- // valid field offset.
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
- return (!MSInheritanceAttr::hasVBTableOffsetField(Inheritance) &&
- RD->nullFieldOffsetIsZero());
-}
-
-llvm::Type *
-MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
- llvm::SmallVector<llvm::Type *, 4> fields;
- if (MPT->isMemberFunctionPointer())
- fields.push_back(CGM.VoidPtrTy); // FunctionPointerOrVirtualThunk
- else
- fields.push_back(CGM.IntTy); // FieldOffset
-
- if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
- Inheritance))
- fields.push_back(CGM.IntTy);
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
- fields.push_back(CGM.IntTy);
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
- fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset
-
- if (fields.size() == 1)
- return fields[0];
- return llvm::StructType::get(CGM.getLLVMContext(), fields);
-}
-
-void MicrosoftCXXABI::
-GetNullMemberPointerFields(const MemberPointerType *MPT,
- llvm::SmallVectorImpl<llvm::Constant *> &fields) {
- assert(fields.empty());
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
- if (MPT->isMemberFunctionPointer()) {
- // FunctionPointerOrVirtualThunk
- fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
- } else {
- if (RD->nullFieldOffsetIsZero())
- fields.push_back(getZeroInt()); // FieldOffset
- else
- fields.push_back(getAllOnesInt()); // FieldOffset
- }
-
- if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
- Inheritance))
- fields.push_back(getZeroInt());
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
- fields.push_back(getZeroInt());
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
- fields.push_back(getAllOnesInt());
-}
-
-llvm::Constant *
-MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- llvm::SmallVector<llvm::Constant *, 4> fields;
- GetNullMemberPointerFields(MPT, fields);
- if (fields.size() == 1)
- return fields[0];
- llvm::Constant *Res = llvm::ConstantStruct::getAnon(fields);
- assert(Res->getType() == ConvertMemberPointerType(MPT));
- return Res;
-}
-
-llvm::Constant *
-MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
- bool IsMemberFunction,
- const CXXRecordDecl *RD,
- CharUnits NonVirtualBaseAdjustment,
- unsigned VBTableIndex) {
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
-
- // Single inheritance class member pointer are represented as scalars instead
- // of aggregates.
- if (MSInheritanceAttr::hasOnlyOneField(IsMemberFunction, Inheritance))
- return FirstField;
-
- llvm::SmallVector<llvm::Constant *, 4> fields;
- fields.push_back(FirstField);
-
- if (MSInheritanceAttr::hasNVOffsetField(IsMemberFunction, Inheritance))
- fields.push_back(llvm::ConstantInt::get(
- CGM.IntTy, NonVirtualBaseAdjustment.getQuantity()));
-
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) {
- CharUnits Offs = CharUnits::Zero();
- if (VBTableIndex)
- Offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
- fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Offs.getQuantity()));
- }
-
- // The rest of the fields are adjusted by conversions to a more derived class.
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
- fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBTableIndex));
-
- return llvm::ConstantStruct::getAnon(fields);
-}
-
-llvm::Constant *
-MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset) {
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- if (RD->getMSInheritanceModel() ==
- MSInheritanceAttr::Keyword_virtual_inheritance)
- offset -= getContext().getOffsetOfBaseWithVBPtr(RD);
- llvm::Constant *FirstField =
- llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
- return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD,
- CharUnits::Zero(), /*VBTableIndex=*/0);
-}
-
-llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
- QualType MPType) {
- const MemberPointerType *DstTy = MPType->castAs<MemberPointerType>();
- const ValueDecl *MPD = MP.getMemberPointerDecl();
- if (!MPD)
- return EmitNullMemberPointer(DstTy);
-
- ASTContext &Ctx = getContext();
- ArrayRef<const CXXRecordDecl *> MemberPointerPath = MP.getMemberPointerPath();
-
- llvm::Constant *C;
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
- C = EmitMemberFunctionPointer(MD);
- } else {
- CharUnits FieldOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MPD));
- C = EmitMemberDataPointer(DstTy, FieldOffset);
- }
-
- if (!MemberPointerPath.empty()) {
- const CXXRecordDecl *SrcRD = cast<CXXRecordDecl>(MPD->getDeclContext());
- const Type *SrcRecTy = Ctx.getTypeDeclType(SrcRD).getTypePtr();
- const MemberPointerType *SrcTy =
- Ctx.getMemberPointerType(DstTy->getPointeeType(), SrcRecTy)
- ->castAs<MemberPointerType>();
-
- bool DerivedMember = MP.isMemberPointerToDerivedMember();
- SmallVector<const CXXBaseSpecifier *, 4> DerivedToBasePath;
- const CXXRecordDecl *PrevRD = SrcRD;
- for (const CXXRecordDecl *PathElem : MemberPointerPath) {
- const CXXRecordDecl *Base = nullptr;
- const CXXRecordDecl *Derived = nullptr;
- if (DerivedMember) {
- Base = PathElem;
- Derived = PrevRD;
- } else {
- Base = PrevRD;
- Derived = PathElem;
- }
- for (const CXXBaseSpecifier &BS : Derived->bases())
- if (BS.getType()->getAsCXXRecordDecl()->getCanonicalDecl() ==
- Base->getCanonicalDecl())
- DerivedToBasePath.push_back(&BS);
- PrevRD = PathElem;
- }
- assert(DerivedToBasePath.size() == MemberPointerPath.size());
-
- CastKind CK = DerivedMember ? CK_DerivedToBaseMemberPointer
- : CK_BaseToDerivedMemberPointer;
- C = EmitMemberPointerConversion(SrcTy, DstTy, CK, DerivedToBasePath.begin(),
- DerivedToBasePath.end(), C);
- }
- return C;
-}
-
-llvm::Constant *
-MicrosoftCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
- assert(MD->isInstance() && "Member function must not be static!");
-
- CharUnits NonVirtualBaseAdjustment = CharUnits::Zero();
- const CXXRecordDecl *RD = MD->getParent()->getMostRecentNonInjectedDecl();
- CodeGenTypes &Types = CGM.getTypes();
-
- unsigned VBTableIndex = 0;
- llvm::Constant *FirstField;
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- if (!MD->isVirtual()) {
- llvm::Type *Ty;
- // Check whether the function has a computable LLVM signature.
- if (Types.isFuncTypeConvertible(FPT)) {
- // The function has a computable LLVM signature; use the correct type.
- Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD));
- } else {
- // Use an arbitrary non-function type to tell GetAddrOfFunction that the
- // function type is incomplete.
- Ty = CGM.PtrDiffTy;
- }
- FirstField = CGM.GetAddrOfFunction(MD, Ty);
- } else {
- auto &VTableContext = CGM.getMicrosoftVTableContext();
- MethodVFTableLocation ML = VTableContext.getMethodVFTableLocation(MD);
- FirstField = EmitVirtualMemPtrThunk(MD, ML);
- // Include the vfptr adjustment if the method is in a non-primary vftable.
- NonVirtualBaseAdjustment += ML.VFPtrOffset;
- if (ML.VBase)
- VBTableIndex = VTableContext.getVBTableIndex(RD, ML.VBase) * 4;
- }
-
- if (VBTableIndex == 0 &&
- RD->getMSInheritanceModel() ==
- MSInheritanceAttr::Keyword_virtual_inheritance)
- NonVirtualBaseAdjustment -= getContext().getOffsetOfBaseWithVBPtr(RD);
-
- // The rest of the fields are common with data member pointers.
- FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy);
- return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD,
- NonVirtualBaseAdjustment, VBTableIndex);
-}
-
-/// Member pointers are the same if they're either bitwise identical *or* both
-/// null. Null-ness for function members is determined by the first field,
-/// while for data member pointers we must compare all fields.
-llvm::Value *
-MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L,
- llvm::Value *R,
- const MemberPointerType *MPT,
- bool Inequality) {
- CGBuilderTy &Builder = CGF.Builder;
-
- // Handle != comparisons by switching the sense of all boolean operations.
- llvm::ICmpInst::Predicate Eq;
- llvm::Instruction::BinaryOps And, Or;
- if (Inequality) {
- Eq = llvm::ICmpInst::ICMP_NE;
- And = llvm::Instruction::Or;
- Or = llvm::Instruction::And;
- } else {
- Eq = llvm::ICmpInst::ICMP_EQ;
- And = llvm::Instruction::And;
- Or = llvm::Instruction::Or;
- }
-
- // If this is a single field member pointer (single inheritance), this is a
- // single icmp.
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
- if (MSInheritanceAttr::hasOnlyOneField(MPT->isMemberFunctionPointer(),
- Inheritance))
- return Builder.CreateICmp(Eq, L, R);
-
- // Compare the first field.
- llvm::Value *L0 = Builder.CreateExtractValue(L, 0, "lhs.0");
- llvm::Value *R0 = Builder.CreateExtractValue(R, 0, "rhs.0");
- llvm::Value *Cmp0 = Builder.CreateICmp(Eq, L0, R0, "memptr.cmp.first");
-
- // Compare everything other than the first field.
- llvm::Value *Res = nullptr;
- llvm::StructType *LType = cast<llvm::StructType>(L->getType());
- for (unsigned I = 1, E = LType->getNumElements(); I != E; ++I) {
- llvm::Value *LF = Builder.CreateExtractValue(L, I);
- llvm::Value *RF = Builder.CreateExtractValue(R, I);
- llvm::Value *Cmp = Builder.CreateICmp(Eq, LF, RF, "memptr.cmp.rest");
- if (Res)
- Res = Builder.CreateBinOp(And, Res, Cmp);
- else
- Res = Cmp;
- }
-
- // Check if the first field is 0 if this is a function pointer.
- if (MPT->isMemberFunctionPointer()) {
- // (l1 == r1 && ...) || l0 == 0
- llvm::Value *Zero = llvm::Constant::getNullValue(L0->getType());
- llvm::Value *IsZero = Builder.CreateICmp(Eq, L0, Zero, "memptr.cmp.iszero");
- Res = Builder.CreateBinOp(Or, Res, IsZero);
- }
-
- // Combine the comparison of the first field, which must always be true for
- // this comparison to succeeed.
- return Builder.CreateBinOp(And, Res, Cmp0, "memptr.cmp");
-}
-
-llvm::Value *
-MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
- CGBuilderTy &Builder = CGF.Builder;
- llvm::SmallVector<llvm::Constant *, 4> fields;
- // We only need one field for member functions.
- if (MPT->isMemberFunctionPointer())
- fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
- else
- GetNullMemberPointerFields(MPT, fields);
- assert(!fields.empty());
- llvm::Value *FirstField = MemPtr;
- if (MemPtr->getType()->isStructTy())
- FirstField = Builder.CreateExtractValue(MemPtr, 0);
- llvm::Value *Res = Builder.CreateICmpNE(FirstField, fields[0], "memptr.cmp0");
-
- // For function member pointers, we only need to test the function pointer
- // field. The other fields if any can be garbage.
- if (MPT->isMemberFunctionPointer())
- return Res;
-
- // Otherwise, emit a series of compares and combine the results.
- for (int I = 1, E = fields.size(); I < E; ++I) {
- llvm::Value *Field = Builder.CreateExtractValue(MemPtr, I);
- llvm::Value *Next = Builder.CreateICmpNE(Field, fields[I], "memptr.cmp");
- Res = Builder.CreateOr(Res, Next, "memptr.tobool");
- }
- return Res;
-}
-
-bool MicrosoftCXXABI::MemberPointerConstantIsNull(const MemberPointerType *MPT,
- llvm::Constant *Val) {
- // Function pointers are null if the pointer in the first field is null.
- if (MPT->isMemberFunctionPointer()) {
- llvm::Constant *FirstField = Val->getType()->isStructTy() ?
- Val->getAggregateElement(0U) : Val;
- return FirstField->isNullValue();
- }
-
- // If it's not a function pointer and it's zero initializable, we can easily
- // check zero.
- if (isZeroInitializable(MPT) && Val->isNullValue())
- return true;
-
- // Otherwise, break down all the fields for comparison. Hopefully these
- // little Constants are reused, while a big null struct might not be.
- llvm::SmallVector<llvm::Constant *, 4> Fields;
- GetNullMemberPointerFields(MPT, Fields);
- if (Fields.size() == 1) {
- assert(Val->getType()->isIntegerTy());
- return Val == Fields[0];
- }
-
- unsigned I, E;
- for (I = 0, E = Fields.size(); I != E; ++I) {
- if (Val->getAggregateElement(I) != Fields[I])
- break;
- }
- return I == E;
-}
-
-llvm::Value *
-MicrosoftCXXABI::GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
- Address This,
- llvm::Value *VBPtrOffset,
- llvm::Value *VBTableOffset,
- llvm::Value **VBPtrOut) {
- CGBuilderTy &Builder = CGF.Builder;
- // Load the vbtable pointer from the vbptr in the instance.
- This = Builder.CreateElementBitCast(This, CGM.Int8Ty);
- llvm::Value *VBPtr =
- Builder.CreateInBoundsGEP(This.getPointer(), VBPtrOffset, "vbptr");
- if (VBPtrOut) *VBPtrOut = VBPtr;
- VBPtr = Builder.CreateBitCast(VBPtr,
- CGM.Int32Ty->getPointerTo(0)->getPointerTo(This.getAddressSpace()));
-
- CharUnits VBPtrAlign;
- if (auto CI = dyn_cast<llvm::ConstantInt>(VBPtrOffset)) {
- VBPtrAlign = This.getAlignment().alignmentAtOffset(
- CharUnits::fromQuantity(CI->getSExtValue()));
- } else {
- VBPtrAlign = CGF.getPointerAlign();
- }
-
- llvm::Value *VBTable = Builder.CreateAlignedLoad(VBPtr, VBPtrAlign, "vbtable");
-
- // Translate from byte offset to table index. It improves analyzability.
- llvm::Value *VBTableIndex = Builder.CreateAShr(
- VBTableOffset, llvm::ConstantInt::get(VBTableOffset->getType(), 2),
- "vbtindex", /*isExact=*/true);
-
- // Load an i32 offset from the vb-table.
- llvm::Value *VBaseOffs = Builder.CreateInBoundsGEP(VBTable, VBTableIndex);
- VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0));
- return Builder.CreateAlignedLoad(VBaseOffs, CharUnits::fromQuantity(4),
- "vbase_offs");
-}
-
-// Returns an adjusted base cast to i8*, since we do more address arithmetic on
-// it.
-llvm::Value *MicrosoftCXXABI::AdjustVirtualBase(
- CodeGenFunction &CGF, const Expr *E, const CXXRecordDecl *RD,
- Address Base, llvm::Value *VBTableOffset, llvm::Value *VBPtrOffset) {
- CGBuilderTy &Builder = CGF.Builder;
- Base = Builder.CreateElementBitCast(Base, CGM.Int8Ty);
- llvm::BasicBlock *OriginalBB = nullptr;
- llvm::BasicBlock *SkipAdjustBB = nullptr;
- llvm::BasicBlock *VBaseAdjustBB = nullptr;
-
- // In the unspecified inheritance model, there might not be a vbtable at all,
- // in which case we need to skip the virtual base lookup. If there is a
- // vbtable, the first entry is a no-op entry that gives back the original
- // base, so look for a virtual base adjustment offset of zero.
- if (VBPtrOffset) {
- OriginalBB = Builder.GetInsertBlock();
- VBaseAdjustBB = CGF.createBasicBlock("memptr.vadjust");
- SkipAdjustBB = CGF.createBasicBlock("memptr.skip_vadjust");
- llvm::Value *IsVirtual =
- Builder.CreateICmpNE(VBTableOffset, getZeroInt(),
- "memptr.is_vbase");
- Builder.CreateCondBr(IsVirtual, VBaseAdjustBB, SkipAdjustBB);
- CGF.EmitBlock(VBaseAdjustBB);
- }
-
- // If we weren't given a dynamic vbptr offset, RD should be complete and we'll
- // know the vbptr offset.
- if (!VBPtrOffset) {
- CharUnits offs = CharUnits::Zero();
- if (!RD->hasDefinition()) {
- DiagnosticsEngine &Diags = CGF.CGM.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(
- DiagnosticsEngine::Error,
- "member pointer representation requires a "
- "complete class type for %0 to perform this expression");
- Diags.Report(E->getExprLoc(), DiagID) << RD << E->getSourceRange();
- } else if (RD->getNumVBases())
- offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
- VBPtrOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity());
- }
- llvm::Value *VBPtr = nullptr;
- llvm::Value *VBaseOffs =
- GetVBaseOffsetFromVBPtr(CGF, Base, VBPtrOffset, VBTableOffset, &VBPtr);
- llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs);
-
- // Merge control flow with the case where we didn't have to adjust.
- if (VBaseAdjustBB) {
- Builder.CreateBr(SkipAdjustBB);
- CGF.EmitBlock(SkipAdjustBB);
- llvm::PHINode *Phi = Builder.CreatePHI(CGM.Int8PtrTy, 2, "memptr.base");
- Phi->addIncoming(Base.getPointer(), OriginalBB);
- Phi->addIncoming(AdjustedBase, VBaseAdjustBB);
- return Phi;
- }
- return AdjustedBase;
-}
-
-llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress(
- CodeGenFunction &CGF, const Expr *E, Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
- assert(MPT->isMemberDataPointer());
- unsigned AS = Base.getAddressSpace();
- llvm::Type *PType =
- CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
- CGBuilderTy &Builder = CGF.Builder;
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
-
- // Extract the fields we need, regardless of model. We'll apply them if we
- // have them.
- llvm::Value *FieldOffset = MemPtr;
- llvm::Value *VirtualBaseAdjustmentOffset = nullptr;
- llvm::Value *VBPtrOffset = nullptr;
- if (MemPtr->getType()->isStructTy()) {
- // We need to extract values.
- unsigned I = 0;
- FieldOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
- VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
- VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
- }
-
- llvm::Value *Addr;
- if (VirtualBaseAdjustmentOffset) {
- Addr = AdjustVirtualBase(CGF, E, RD, Base, VirtualBaseAdjustmentOffset,
- VBPtrOffset);
- } else {
- Addr = Base.getPointer();
- }
-
- // Cast to char*.
- Addr = Builder.CreateBitCast(Addr, CGF.Int8Ty->getPointerTo(AS));
-
- // Apply the offset, which we assume is non-null.
- Addr = Builder.CreateInBoundsGEP(Addr, FieldOffset, "memptr.offset");
-
- // Cast the address to the appropriate pointer type, adopting the address
- // space of the base pointer.
- return Builder.CreateBitCast(Addr, PType);
-}
-
-llvm::Value *
-MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
- const CastExpr *E,
- llvm::Value *Src) {
- assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
- E->getCastKind() == CK_BaseToDerivedMemberPointer ||
- E->getCastKind() == CK_ReinterpretMemberPointer);
-
- // Use constant emission if we can.
- if (isa<llvm::Constant>(Src))
- return EmitMemberPointerConversion(E, cast<llvm::Constant>(Src));
-
- // We may be adding or dropping fields from the member pointer, so we need
- // both types and the inheritance models of both records.
- const MemberPointerType *SrcTy =
- E->getSubExpr()->getType()->castAs<MemberPointerType>();
- const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
- bool IsFunc = SrcTy->isMemberFunctionPointer();
-
- // If the classes use the same null representation, reinterpret_cast is a nop.
- bool IsReinterpret = E->getCastKind() == CK_ReinterpretMemberPointer;
- if (IsReinterpret && IsFunc)
- return Src;
-
- CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl();
- CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl();
- if (IsReinterpret &&
- SrcRD->nullFieldOffsetIsZero() == DstRD->nullFieldOffsetIsZero())
- return Src;
-
- CGBuilderTy &Builder = CGF.Builder;
-
- // Branch past the conversion if Src is null.
- llvm::Value *IsNotNull = EmitMemberPointerIsNotNull(CGF, Src, SrcTy);
- llvm::Constant *DstNull = EmitNullMemberPointer(DstTy);
-
- // C++ 5.2.10p9: The null member pointer value is converted to the null member
- // pointer value of the destination type.
- if (IsReinterpret) {
- // For reinterpret casts, sema ensures that src and dst are both functions
- // or data and have the same size, which means the LLVM types should match.
- assert(Src->getType() == DstNull->getType());
- return Builder.CreateSelect(IsNotNull, Src, DstNull);
- }
-
- llvm::BasicBlock *OriginalBB = Builder.GetInsertBlock();
- llvm::BasicBlock *ConvertBB = CGF.createBasicBlock("memptr.convert");
- llvm::BasicBlock *ContinueBB = CGF.createBasicBlock("memptr.converted");
- Builder.CreateCondBr(IsNotNull, ConvertBB, ContinueBB);
- CGF.EmitBlock(ConvertBB);
-
- llvm::Value *Dst = EmitNonNullMemberPointerConversion(
- SrcTy, DstTy, E->getCastKind(), E->path_begin(), E->path_end(), Src,
- Builder);
-
- Builder.CreateBr(ContinueBB);
-
- // In the continuation, choose between DstNull and Dst.
- CGF.EmitBlock(ContinueBB);
- llvm::PHINode *Phi = Builder.CreatePHI(DstNull->getType(), 2, "memptr.converted");
- Phi->addIncoming(DstNull, OriginalBB);
- Phi->addIncoming(Dst, ConvertBB);
- return Phi;
-}
-
-llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion(
- const MemberPointerType *SrcTy, const MemberPointerType *DstTy, CastKind CK,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd, llvm::Value *Src,
- CGBuilderTy &Builder) {
- const CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl();
- const CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling SrcInheritance = SrcRD->getMSInheritanceModel();
- MSInheritanceAttr::Spelling DstInheritance = DstRD->getMSInheritanceModel();
- bool IsFunc = SrcTy->isMemberFunctionPointer();
- bool IsConstant = isa<llvm::Constant>(Src);
-
- // Decompose src.
- llvm::Value *FirstField = Src;
- llvm::Value *NonVirtualBaseAdjustment = getZeroInt();
- llvm::Value *VirtualBaseAdjustmentOffset = getZeroInt();
- llvm::Value *VBPtrOffset = getZeroInt();
- if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) {
- // We need to extract values.
- unsigned I = 0;
- FirstField = Builder.CreateExtractValue(Src, I++);
- if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance))
- NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance))
- VBPtrOffset = Builder.CreateExtractValue(Src, I++);
- if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance))
- VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++);
- }
-
- bool IsDerivedToBase = (CK == CK_DerivedToBaseMemberPointer);
- const MemberPointerType *DerivedTy = IsDerivedToBase ? SrcTy : DstTy;
- const CXXRecordDecl *DerivedClass = DerivedTy->getMostRecentCXXRecordDecl();
-
- // For data pointers, we adjust the field offset directly. For functions, we
- // have a separate field.
- llvm::Value *&NVAdjustField = IsFunc ? NonVirtualBaseAdjustment : FirstField;
-
- // The virtual inheritance model has a quirk: the virtual base table is always
- // referenced when dereferencing a member pointer even if the member pointer
- // is non-virtual. This is accounted for by adjusting the non-virtual offset
- // to point backwards to the top of the MDC from the first VBase. Undo this
- // adjustment to normalize the member pointer.
- llvm::Value *SrcVBIndexEqZero =
- Builder.CreateICmpEQ(VirtualBaseAdjustmentOffset, getZeroInt());
- if (SrcInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
- if (int64_t SrcOffsetToFirstVBase =
- getContext().getOffsetOfBaseWithVBPtr(SrcRD).getQuantity()) {
- llvm::Value *UndoSrcAdjustment = Builder.CreateSelect(
- SrcVBIndexEqZero,
- llvm::ConstantInt::get(CGM.IntTy, SrcOffsetToFirstVBase),
- getZeroInt());
- NVAdjustField = Builder.CreateNSWAdd(NVAdjustField, UndoSrcAdjustment);
- }
- }
-
- // A non-zero vbindex implies that we are dealing with a source member in a
- // floating virtual base in addition to some non-virtual offset. If the
- // vbindex is zero, we are dealing with a source that exists in a non-virtual,
- // fixed, base. The difference between these two cases is that the vbindex +
- // nvoffset *always* point to the member regardless of what context they are
- // evaluated in so long as the vbindex is adjusted. A member inside a fixed
- // base requires explicit nv adjustment.
- llvm::Constant *BaseClassOffset = llvm::ConstantInt::get(
- CGM.IntTy,
- CGM.computeNonVirtualBaseClassOffset(DerivedClass, PathBegin, PathEnd)
- .getQuantity());
-
- llvm::Value *NVDisp;
- if (IsDerivedToBase)
- NVDisp = Builder.CreateNSWSub(NVAdjustField, BaseClassOffset, "adj");
- else
- NVDisp = Builder.CreateNSWAdd(NVAdjustField, BaseClassOffset, "adj");
-
- NVAdjustField = Builder.CreateSelect(SrcVBIndexEqZero, NVDisp, getZeroInt());
-
- // Update the vbindex to an appropriate value in the destination because
- // SrcRD's vbtable might not be a strict prefix of the one in DstRD.
- llvm::Value *DstVBIndexEqZero = SrcVBIndexEqZero;
- if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance) &&
- MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance)) {
- if (llvm::GlobalVariable *VDispMap =
- getAddrOfVirtualDisplacementMap(SrcRD, DstRD)) {
- llvm::Value *VBIndex = Builder.CreateExactUDiv(
- VirtualBaseAdjustmentOffset, llvm::ConstantInt::get(CGM.IntTy, 4));
- if (IsConstant) {
- llvm::Constant *Mapping = VDispMap->getInitializer();
- VirtualBaseAdjustmentOffset =
- Mapping->getAggregateElement(cast<llvm::Constant>(VBIndex));
- } else {
- llvm::Value *Idxs[] = {getZeroInt(), VBIndex};
- VirtualBaseAdjustmentOffset =
- Builder.CreateAlignedLoad(Builder.CreateInBoundsGEP(VDispMap, Idxs),
- CharUnits::fromQuantity(4));
- }
-
- DstVBIndexEqZero =
- Builder.CreateICmpEQ(VirtualBaseAdjustmentOffset, getZeroInt());
- }
- }
-
- // Set the VBPtrOffset to zero if the vbindex is zero. Otherwise, initialize
- // it to the offset of the vbptr.
- if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance)) {
- llvm::Value *DstVBPtrOffset = llvm::ConstantInt::get(
- CGM.IntTy,
- getContext().getASTRecordLayout(DstRD).getVBPtrOffset().getQuantity());
- VBPtrOffset =
- Builder.CreateSelect(DstVBIndexEqZero, getZeroInt(), DstVBPtrOffset);
- }
-
- // Likewise, apply a similar adjustment so that dereferencing the member
- // pointer correctly accounts for the distance between the start of the first
- // virtual base and the top of the MDC.
- if (DstInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
- if (int64_t DstOffsetToFirstVBase =
- getContext().getOffsetOfBaseWithVBPtr(DstRD).getQuantity()) {
- llvm::Value *DoDstAdjustment = Builder.CreateSelect(
- DstVBIndexEqZero,
- llvm::ConstantInt::get(CGM.IntTy, DstOffsetToFirstVBase),
- getZeroInt());
- NVAdjustField = Builder.CreateNSWSub(NVAdjustField, DoDstAdjustment);
- }
- }
-
- // Recompose dst from the null struct and the adjusted fields from src.
- llvm::Value *Dst;
- if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance)) {
- Dst = FirstField;
- } else {
- Dst = llvm::UndefValue::get(ConvertMemberPointerType(DstTy));
- unsigned Idx = 0;
- Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++);
- if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance))
- Dst = Builder.CreateInsertValue(Dst, NonVirtualBaseAdjustment, Idx++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance))
- Dst = Builder.CreateInsertValue(Dst, VBPtrOffset, Idx++);
- if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance))
- Dst = Builder.CreateInsertValue(Dst, VirtualBaseAdjustmentOffset, Idx++);
- }
- return Dst;
-}
-
-llvm::Constant *
-MicrosoftCXXABI::EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *Src) {
- const MemberPointerType *SrcTy =
- E->getSubExpr()->getType()->castAs<MemberPointerType>();
- const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
-
- CastKind CK = E->getCastKind();
-
- return EmitMemberPointerConversion(SrcTy, DstTy, CK, E->path_begin(),
- E->path_end(), Src);
-}
-
-llvm::Constant *MicrosoftCXXABI::EmitMemberPointerConversion(
- const MemberPointerType *SrcTy, const MemberPointerType *DstTy, CastKind CK,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd, llvm::Constant *Src) {
- assert(CK == CK_DerivedToBaseMemberPointer ||
- CK == CK_BaseToDerivedMemberPointer ||
- CK == CK_ReinterpretMemberPointer);
- // If src is null, emit a new null for dst. We can't return src because dst
- // might have a new representation.
- if (MemberPointerConstantIsNull(SrcTy, Src))
- return EmitNullMemberPointer(DstTy);
-
- // We don't need to do anything for reinterpret_casts of non-null member
- // pointers. We should only get here when the two type representations have
- // the same size.
- if (CK == CK_ReinterpretMemberPointer)
- return Src;
-
- CGBuilderTy Builder(CGM, CGM.getLLVMContext());
- auto *Dst = cast<llvm::Constant>(EmitNonNullMemberPointerConversion(
- SrcTy, DstTy, CK, PathBegin, PathEnd, Src, Builder));
-
- return Dst;
-}
-
-CGCallee MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(
- CodeGenFunction &CGF, const Expr *E, Address This,
- llvm::Value *&ThisPtrForCall, llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
- assert(MPT->isMemberFunctionPointer());
- const FunctionProtoType *FPT =
- MPT->getPointeeType()->castAs<FunctionProtoType>();
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
- CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
- CGBuilderTy &Builder = CGF.Builder;
-
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
-
- // Extract the fields we need, regardless of model. We'll apply them if we
- // have them.
- llvm::Value *FunctionPointer = MemPtr;
- llvm::Value *NonVirtualBaseAdjustment = nullptr;
- llvm::Value *VirtualBaseAdjustmentOffset = nullptr;
- llvm::Value *VBPtrOffset = nullptr;
- if (MemPtr->getType()->isStructTy()) {
- // We need to extract values.
- unsigned I = 0;
- FunctionPointer = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasNVOffsetField(MPT, Inheritance))
- NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
- VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
- VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
- }
-
- if (VirtualBaseAdjustmentOffset) {
- ThisPtrForCall = AdjustVirtualBase(CGF, E, RD, This,
- VirtualBaseAdjustmentOffset, VBPtrOffset);
- } else {
- ThisPtrForCall = This.getPointer();
- }
-
- if (NonVirtualBaseAdjustment) {
- // Apply the adjustment and cast back to the original struct type.
- llvm::Value *Ptr = Builder.CreateBitCast(ThisPtrForCall, CGF.Int8PtrTy);
- Ptr = Builder.CreateInBoundsGEP(Ptr, NonVirtualBaseAdjustment);
- ThisPtrForCall = Builder.CreateBitCast(Ptr, ThisPtrForCall->getType(),
- "this.adjusted");
- }
-
- FunctionPointer =
- Builder.CreateBitCast(FunctionPointer, FTy->getPointerTo());
- CGCallee Callee(FPT, FunctionPointer);
- return Callee;
-}
-
-CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
- return new MicrosoftCXXABI(CGM);
-}
-
-// MS RTTI Overview:
-// The run time type information emitted by cl.exe contains 5 distinct types of
-// structures. Many of them reference each other.
-//
-// TypeInfo: Static classes that are returned by typeid.
-//
-// CompleteObjectLocator: Referenced by vftables. They contain information
-// required for dynamic casting, including OffsetFromTop. They also contain
-// a reference to the TypeInfo for the type and a reference to the
-// CompleteHierarchyDescriptor for the type.
-//
-// ClassHierarchyDescriptor: Contains information about a class hierarchy.
-// Used during dynamic_cast to walk a class hierarchy. References a base
-// class array and the size of said array.
-//
-// BaseClassArray: Contains a list of classes in a hierarchy. BaseClassArray is
-// somewhat of a misnomer because the most derived class is also in the list
-// as well as multiple copies of virtual bases (if they occur multiple times
-// in the hierarchy.) The BaseClassArray contains one BaseClassDescriptor for
-// every path in the hierarchy, in pre-order depth first order. Note, we do
-// not declare a specific llvm type for BaseClassArray, it's merely an array
-// of BaseClassDescriptor pointers.
-//
-// BaseClassDescriptor: Contains information about a class in a class hierarchy.
-// BaseClassDescriptor is also somewhat of a misnomer for the same reason that
-// BaseClassArray is. It contains information about a class within a
-// hierarchy such as: is this base is ambiguous and what is its offset in the
-// vbtable. The names of the BaseClassDescriptors have all of their fields
-// mangled into them so they can be aggressively deduplicated by the linker.
-
-static llvm::GlobalVariable *getTypeInfoVTable(CodeGenModule &CGM) {
- StringRef MangledName("??_7type_info@@6B@");
- if (auto VTable = CGM.getModule().getNamedGlobal(MangledName))
- return VTable;
- return new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
- /*Constant=*/true,
- llvm::GlobalVariable::ExternalLinkage,
- /*Initializer=*/nullptr, MangledName);
-}
-
-namespace {
-
-/// A Helper struct that stores information about a class in a class
-/// hierarchy. The information stored in these structs struct is used during
-/// the generation of ClassHierarchyDescriptors and BaseClassDescriptors.
-// During RTTI creation, MSRTTIClasses are stored in a contiguous array with
-// implicit depth first pre-order tree connectivity. getFirstChild and
-// getNextSibling allow us to walk the tree efficiently.
-struct MSRTTIClass {
- enum {
- IsPrivateOnPath = 1 | 8,
- IsAmbiguous = 2,
- IsPrivate = 4,
- IsVirtual = 16,
- HasHierarchyDescriptor = 64
- };
- MSRTTIClass(const CXXRecordDecl *RD) : RD(RD) {}
- uint32_t initialize(const MSRTTIClass *Parent,
- const CXXBaseSpecifier *Specifier);
-
- MSRTTIClass *getFirstChild() { return this + 1; }
- static MSRTTIClass *getNextChild(MSRTTIClass *Child) {
- return Child + 1 + Child->NumBases;
- }
-
- const CXXRecordDecl *RD, *VirtualRoot;
- uint32_t Flags, NumBases, OffsetInVBase;
-};
-
-/// Recursively initialize the base class array.
-uint32_t MSRTTIClass::initialize(const MSRTTIClass *Parent,
- const CXXBaseSpecifier *Specifier) {
- Flags = HasHierarchyDescriptor;
- if (!Parent) {
- VirtualRoot = nullptr;
- OffsetInVBase = 0;
- } else {
- if (Specifier->getAccessSpecifier() != AS_public)
- Flags |= IsPrivate | IsPrivateOnPath;
- if (Specifier->isVirtual()) {
- Flags |= IsVirtual;
- VirtualRoot = RD;
- OffsetInVBase = 0;
- } else {
- if (Parent->Flags & IsPrivateOnPath)
- Flags |= IsPrivateOnPath;
- VirtualRoot = Parent->VirtualRoot;
- OffsetInVBase = Parent->OffsetInVBase + RD->getASTContext()
- .getASTRecordLayout(Parent->RD).getBaseClassOffset(RD).getQuantity();
- }
- }
- NumBases = 0;
- MSRTTIClass *Child = getFirstChild();
- for (const CXXBaseSpecifier &Base : RD->bases()) {
- NumBases += Child->initialize(this, &Base) + 1;
- Child = getNextChild(Child);
- }
- return NumBases;
-}
-
-static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) {
- switch (Ty->getLinkage()) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
- return llvm::GlobalValue::InternalLinkage;
-
- case VisibleNoLinkage:
- case ModuleInternalLinkage:
- case ModuleLinkage:
- case ExternalLinkage:
- return llvm::GlobalValue::LinkOnceODRLinkage;
- }
- llvm_unreachable("Invalid linkage!");
-}
-
-/// An ephemeral helper class for building MS RTTI types. It caches some
-/// calls to the module and information about the most derived class in a
-/// hierarchy.
-struct MSRTTIBuilder {
- enum {
- HasBranchingHierarchy = 1,
- HasVirtualBranchingHierarchy = 2,
- HasAmbiguousBases = 4
- };
-
- MSRTTIBuilder(MicrosoftCXXABI &ABI, const CXXRecordDecl *RD)
- : CGM(ABI.CGM), Context(CGM.getContext()),
- VMContext(CGM.getLLVMContext()), Module(CGM.getModule()), RD(RD),
- Linkage(getLinkageForRTTI(CGM.getContext().getTagDeclType(RD))),
- ABI(ABI) {}
-
- llvm::GlobalVariable *getBaseClassDescriptor(const MSRTTIClass &Classes);
- llvm::GlobalVariable *
- getBaseClassArray(SmallVectorImpl<MSRTTIClass> &Classes);
- llvm::GlobalVariable *getClassHierarchyDescriptor();
- llvm::GlobalVariable *getCompleteObjectLocator(const VPtrInfo &Info);
-
- CodeGenModule &CGM;
- ASTContext &Context;
- llvm::LLVMContext &VMContext;
- llvm::Module &Module;
- const CXXRecordDecl *RD;
- llvm::GlobalVariable::LinkageTypes Linkage;
- MicrosoftCXXABI &ABI;
-};
-
-} // namespace
-
-/// Recursively serializes a class hierarchy in pre-order depth first
-/// order.
-static void serializeClassHierarchy(SmallVectorImpl<MSRTTIClass> &Classes,
- const CXXRecordDecl *RD) {
- Classes.push_back(MSRTTIClass(RD));
- for (const CXXBaseSpecifier &Base : RD->bases())
- serializeClassHierarchy(Classes, Base.getType()->getAsCXXRecordDecl());
-}
-
-/// Find ambiguity among base classes.
-static void
-detectAmbiguousBases(SmallVectorImpl<MSRTTIClass> &Classes) {
- llvm::SmallPtrSet<const CXXRecordDecl *, 8> VirtualBases;
- llvm::SmallPtrSet<const CXXRecordDecl *, 8> UniqueBases;
- llvm::SmallPtrSet<const CXXRecordDecl *, 8> AmbiguousBases;
- for (MSRTTIClass *Class = &Classes.front(); Class <= &Classes.back();) {
- if ((Class->Flags & MSRTTIClass::IsVirtual) &&
- !VirtualBases.insert(Class->RD).second) {
- Class = MSRTTIClass::getNextChild(Class);
- continue;
- }
- if (!UniqueBases.insert(Class->RD).second)
- AmbiguousBases.insert(Class->RD);
- Class++;
- }
- if (AmbiguousBases.empty())
- return;
- for (MSRTTIClass &Class : Classes)
- if (AmbiguousBases.count(Class.RD))
- Class.Flags |= MSRTTIClass::IsAmbiguous;
-}
-
-llvm::GlobalVariable *MSRTTIBuilder::getClassHierarchyDescriptor() {
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- ABI.getMangleContext().mangleCXXRTTIClassHierarchyDescriptor(RD, Out);
- }
-
- // Check to see if we've already declared this ClassHierarchyDescriptor.
- if (auto CHD = Module.getNamedGlobal(MangledName))
- return CHD;
-
- // Serialize the class hierarchy and initialize the CHD Fields.
- SmallVector<MSRTTIClass, 8> Classes;
- serializeClassHierarchy(Classes, RD);
- Classes.front().initialize(/*Parent=*/nullptr, /*Specifier=*/nullptr);
- detectAmbiguousBases(Classes);
- int Flags = 0;
- for (auto Class : Classes) {
- if (Class.RD->getNumBases() > 1)
- Flags |= HasBranchingHierarchy;
- // Note: cl.exe does not calculate "HasAmbiguousBases" correctly. We
- // believe the field isn't actually used.
- if (Class.Flags & MSRTTIClass::IsAmbiguous)
- Flags |= HasAmbiguousBases;
- }
- if ((Flags & HasBranchingHierarchy) && RD->getNumVBases() != 0)
- Flags |= HasVirtualBranchingHierarchy;
- // These gep indices are used to get the address of the first element of the
- // base class array.
- llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
- llvm::ConstantInt::get(CGM.IntTy, 0)};
-
- // Forward-declare the class hierarchy descriptor
- auto Type = ABI.getClassHierarchyDescriptorType();
- auto CHD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr,
- MangledName);
- if (CHD->isWeakForLinker())
- CHD->setComdat(CGM.getModule().getOrInsertComdat(CHD->getName()));
-
- auto *Bases = getBaseClassArray(Classes);
-
- // Initialize the base class ClassHierarchyDescriptor.
- llvm::Constant *Fields[] = {
- llvm::ConstantInt::get(CGM.IntTy, 0), // reserved by the runtime
- llvm::ConstantInt::get(CGM.IntTy, Flags),
- llvm::ConstantInt::get(CGM.IntTy, Classes.size()),
- ABI.getImageRelativeConstant(llvm::ConstantExpr::getInBoundsGetElementPtr(
- Bases->getValueType(), Bases,
- llvm::ArrayRef<llvm::Value *>(GEPIndices))),
- };
- CHD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
- return CHD;
-}
-
-llvm::GlobalVariable *
-MSRTTIBuilder::getBaseClassArray(SmallVectorImpl<MSRTTIClass> &Classes) {
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- ABI.getMangleContext().mangleCXXRTTIBaseClassArray(RD, Out);
- }
-
- // Forward-declare the base class array.
- // cl.exe pads the base class array with 1 (in 32 bit mode) or 4 (in 64 bit
- // mode) bytes of padding. We provide a pointer sized amount of padding by
- // adding +1 to Classes.size(). The sections have pointer alignment and are
- // marked pick-any so it shouldn't matter.
- llvm::Type *PtrType = ABI.getImageRelativeType(
- ABI.getBaseClassDescriptorType()->getPointerTo());
- auto *ArrType = llvm::ArrayType::get(PtrType, Classes.size() + 1);
- auto *BCA =
- new llvm::GlobalVariable(Module, ArrType,
- /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr, MangledName);
- if (BCA->isWeakForLinker())
- BCA->setComdat(CGM.getModule().getOrInsertComdat(BCA->getName()));
-
- // Initialize the BaseClassArray.
- SmallVector<llvm::Constant *, 8> BaseClassArrayData;
- for (MSRTTIClass &Class : Classes)
- BaseClassArrayData.push_back(
- ABI.getImageRelativeConstant(getBaseClassDescriptor(Class)));
- BaseClassArrayData.push_back(llvm::Constant::getNullValue(PtrType));
- BCA->setInitializer(llvm::ConstantArray::get(ArrType, BaseClassArrayData));
- return BCA;
-}
-
-llvm::GlobalVariable *
-MSRTTIBuilder::getBaseClassDescriptor(const MSRTTIClass &Class) {
- // Compute the fields for the BaseClassDescriptor. They are computed up front
- // because they are mangled into the name of the object.
- uint32_t OffsetInVBTable = 0;
- int32_t VBPtrOffset = -1;
- if (Class.VirtualRoot) {
- auto &VTableContext = CGM.getMicrosoftVTableContext();
- OffsetInVBTable = VTableContext.getVBTableIndex(RD, Class.VirtualRoot) * 4;
- VBPtrOffset = Context.getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
- }
-
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- ABI.getMangleContext().mangleCXXRTTIBaseClassDescriptor(
- Class.RD, Class.OffsetInVBase, VBPtrOffset, OffsetInVBTable,
- Class.Flags, Out);
- }
-
- // Check to see if we've already declared this object.
- if (auto BCD = Module.getNamedGlobal(MangledName))
- return BCD;
-
- // Forward-declare the base class descriptor.
- auto Type = ABI.getBaseClassDescriptorType();
- auto BCD =
- new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr, MangledName);
- if (BCD->isWeakForLinker())
- BCD->setComdat(CGM.getModule().getOrInsertComdat(BCD->getName()));
-
- // Initialize the BaseClassDescriptor.
- llvm::Constant *Fields[] = {
- ABI.getImageRelativeConstant(
- ABI.getAddrOfRTTIDescriptor(Context.getTypeDeclType(Class.RD))),
- llvm::ConstantInt::get(CGM.IntTy, Class.NumBases),
- llvm::ConstantInt::get(CGM.IntTy, Class.OffsetInVBase),
- llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
- llvm::ConstantInt::get(CGM.IntTy, OffsetInVBTable),
- llvm::ConstantInt::get(CGM.IntTy, Class.Flags),
- ABI.getImageRelativeConstant(
- MSRTTIBuilder(ABI, Class.RD).getClassHierarchyDescriptor()),
- };
- BCD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
- return BCD;
-}
-
-llvm::GlobalVariable *
-MSRTTIBuilder::getCompleteObjectLocator(const VPtrInfo &Info) {
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- ABI.getMangleContext().mangleCXXRTTICompleteObjectLocator(RD, Info.MangledPath, Out);
- }
-
- // Check to see if we've already computed this complete object locator.
- if (auto COL = Module.getNamedGlobal(MangledName))
- return COL;
-
- // Compute the fields of the complete object locator.
- int OffsetToTop = Info.FullOffsetInMDC.getQuantity();
- int VFPtrOffset = 0;
- // The offset includes the vtordisp if one exists.
- if (const CXXRecordDecl *VBase = Info.getVBaseWithVPtr())
- if (Context.getASTRecordLayout(RD)
- .getVBaseOffsetsMap()
- .find(VBase)
- ->second.hasVtorDisp())
- VFPtrOffset = Info.NonVirtualOffset.getQuantity() + 4;
-
- // Forward-declare the complete object locator.
- llvm::StructType *Type = ABI.getCompleteObjectLocatorType();
- auto COL = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr, MangledName);
-
- // Initialize the CompleteObjectLocator.
- llvm::Constant *Fields[] = {
- llvm::ConstantInt::get(CGM.IntTy, ABI.isImageRelative()),
- llvm::ConstantInt::get(CGM.IntTy, OffsetToTop),
- llvm::ConstantInt::get(CGM.IntTy, VFPtrOffset),
- ABI.getImageRelativeConstant(
- CGM.GetAddrOfRTTIDescriptor(Context.getTypeDeclType(RD))),
- ABI.getImageRelativeConstant(getClassHierarchyDescriptor()),
- ABI.getImageRelativeConstant(COL),
- };
- llvm::ArrayRef<llvm::Constant *> FieldsRef(Fields);
- if (!ABI.isImageRelative())
- FieldsRef = FieldsRef.drop_back();
- COL->setInitializer(llvm::ConstantStruct::get(Type, FieldsRef));
- if (COL->isWeakForLinker())
- COL->setComdat(CGM.getModule().getOrInsertComdat(COL->getName()));
- return COL;
-}
-
-static QualType decomposeTypeForEH(ASTContext &Context, QualType T,
- bool &IsConst, bool &IsVolatile,
- bool &IsUnaligned) {
- T = Context.getExceptionObjectType(T);
-
- // C++14 [except.handle]p3:
- // A handler is a match for an exception object of type E if [...]
- // - the handler is of type cv T or const T& where T is a pointer type and
- // E is a pointer type that can be converted to T by [...]
- // - a qualification conversion
- IsConst = false;
- IsVolatile = false;
- IsUnaligned = false;
- QualType PointeeType = T->getPointeeType();
- if (!PointeeType.isNull()) {
- IsConst = PointeeType.isConstQualified();
- IsVolatile = PointeeType.isVolatileQualified();
- IsUnaligned = PointeeType.getQualifiers().hasUnaligned();
- }
-
- // Member pointer types like "const int A::*" are represented by having RTTI
- // for "int A::*" and separately storing the const qualifier.
- if (const auto *MPTy = T->getAs<MemberPointerType>())
- T = Context.getMemberPointerType(PointeeType.getUnqualifiedType(),
- MPTy->getClass());
-
- // Pointer types like "const int * const *" are represented by having RTTI
- // for "const int **" and separately storing the const qualifier.
- if (T->isPointerType())
- T = Context.getPointerType(PointeeType.getUnqualifiedType());
-
- return T;
-}
-
-CatchTypeInfo
-MicrosoftCXXABI::getAddrOfCXXCatchHandlerType(QualType Type,
- QualType CatchHandlerType) {
- // TypeDescriptors for exceptions never have qualified pointer types,
- // qualifiers are stored separately in order to support qualification
- // conversions.
- bool IsConst, IsVolatile, IsUnaligned;
- Type =
- decomposeTypeForEH(getContext(), Type, IsConst, IsVolatile, IsUnaligned);
-
- bool IsReference = CatchHandlerType->isReferenceType();
-
- uint32_t Flags = 0;
- if (IsConst)
- Flags |= 1;
- if (IsVolatile)
- Flags |= 2;
- if (IsUnaligned)
- Flags |= 4;
- if (IsReference)
- Flags |= 8;
-
- return CatchTypeInfo{getAddrOfRTTIDescriptor(Type)->stripPointerCasts(),
- Flags};
-}
-
-/// Gets a TypeDescriptor. Returns a llvm::Constant * rather than a
-/// llvm::GlobalVariable * because different type descriptors have different
-/// types, and need to be abstracted. They are abstracting by casting the
-/// address to an Int8PtrTy.
-llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- getMangleContext().mangleCXXRTTI(Type, Out);
- }
-
- // Check to see if we've already declared this TypeDescriptor.
- if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-
- // Note for the future: If we would ever like to do deferred emission of
- // RTTI, check if emitting vtables opportunistically need any adjustment.
-
- // Compute the fields for the TypeDescriptor.
- SmallString<256> TypeInfoString;
- {
- llvm::raw_svector_ostream Out(TypeInfoString);
- getMangleContext().mangleCXXRTTIName(Type, Out);
- }
-
- // Declare and initialize the TypeDescriptor.
- llvm::Constant *Fields[] = {
- getTypeInfoVTable(CGM), // VFPtr
- llvm::ConstantPointerNull::get(CGM.Int8PtrTy), // Runtime data
- llvm::ConstantDataArray::getString(CGM.getLLVMContext(), TypeInfoString)};
- llvm::StructType *TypeDescriptorType =
- getTypeDescriptorType(TypeInfoString);
- auto *Var = new llvm::GlobalVariable(
- CGM.getModule(), TypeDescriptorType, /*Constant=*/false,
- getLinkageForRTTI(Type),
- llvm::ConstantStruct::get(TypeDescriptorType, Fields),
- MangledName);
- if (Var->isWeakForLinker())
- Var->setComdat(CGM.getModule().getOrInsertComdat(Var->getName()));
- return llvm::ConstantExpr::getBitCast(Var, CGM.Int8PtrTy);
-}
-
-/// Gets or a creates a Microsoft CompleteObjectLocator.
-llvm::GlobalVariable *
-MicrosoftCXXABI::getMSCompleteObjectLocator(const CXXRecordDecl *RD,
- const VPtrInfo &Info) {
- return MSRTTIBuilder(*this, RD).getCompleteObjectLocator(Info);
-}
-
-static void emitCXXConstructor(CodeGenModule &CGM,
- const CXXConstructorDecl *ctor,
- StructorType ctorType) {
- // There are no constructor variants, always emit the complete destructor.
- llvm::Function *Fn = CGM.codegenCXXStructor(ctor, StructorType::Complete);
- CGM.maybeSetTrivialComdat(*ctor, *Fn);
-}
-
-static void emitCXXDestructor(CodeGenModule &CGM, const CXXDestructorDecl *dtor,
- StructorType dtorType) {
- // Emit the base destructor if the base and complete (vbase) destructors are
- // equivalent. This effectively implements -mconstructor-aliases as part of
- // the ABI.
- if (dtorType == StructorType::Complete &&
- dtor->getParent()->getNumVBases() == 0)
- dtorType = StructorType::Base;
-
- // The base destructor is equivalent to the base destructor of its
- // base class if there is exactly one non-virtual base class with a
- // non-trivial destructor, there are no fields with a non-trivial
- // destructor, and the body of the destructor is trivial.
- if (dtorType == StructorType::Base && !CGM.TryEmitBaseDestructorAsAlias(dtor))
- return;
-
- llvm::Function *Fn = CGM.codegenCXXStructor(dtor, dtorType);
- if (Fn->isWeakForLinker())
- Fn->setComdat(CGM.getModule().getOrInsertComdat(Fn->getName()));
-}
-
-void MicrosoftCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
- StructorType Type) {
- if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
- emitCXXConstructor(CGM, CD, Type);
- return;
- }
- emitCXXDestructor(CGM, cast<CXXDestructorDecl>(MD), Type);
-}
-
-llvm::Function *
-MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
- CXXCtorType CT) {
- assert(CT == Ctor_CopyingClosure || CT == Ctor_DefaultClosure);
-
- // Calculate the mangled name.
- SmallString<256> ThunkName;
- llvm::raw_svector_ostream Out(ThunkName);
- getMangleContext().mangleCXXCtor(CD, CT, Out);
-
- // If the thunk has been generated previously, just return it.
- if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
- return cast<llvm::Function>(GV);
-
- // Create the llvm::Function.
- const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSCtorClosure(CD, CT);
- llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
- const CXXRecordDecl *RD = CD->getParent();
- QualType RecordTy = getContext().getRecordType(RD);
- llvm::Function *ThunkFn = llvm::Function::Create(
- ThunkTy, getLinkageForRTTI(RecordTy), ThunkName.str(), &CGM.getModule());
- ThunkFn->setCallingConv(static_cast<llvm::CallingConv::ID>(
- FnInfo.getEffectiveCallingConvention()));
- if (ThunkFn->isWeakForLinker())
- ThunkFn->setComdat(CGM.getModule().getOrInsertComdat(ThunkFn->getName()));
- bool IsCopy = CT == Ctor_CopyingClosure;
-
- // Start codegen.
- CodeGenFunction CGF(CGM);
- CGF.CurGD = GlobalDecl(CD, Ctor_Complete);
-
- // Build FunctionArgs.
- FunctionArgList FunctionArgs;
-
- // A constructor always starts with a 'this' pointer as its first argument.
- buildThisParam(CGF, FunctionArgs);
-
- // Following the 'this' pointer is a reference to the source object that we
- // are copying from.
- ImplicitParamDecl SrcParam(
- getContext(), /*DC=*/nullptr, SourceLocation(),
- &getContext().Idents.get("src"),
- getContext().getLValueReferenceType(RecordTy,
- /*SpelledAsLValue=*/true),
- ImplicitParamDecl::Other);
- if (IsCopy)
- FunctionArgs.push_back(&SrcParam);
-
- // Constructors for classes which utilize virtual bases have an additional
- // parameter which indicates whether or not it is being delegated to by a more
- // derived constructor.
- ImplicitParamDecl IsMostDerived(getContext(), /*DC=*/nullptr,
- SourceLocation(),
- &getContext().Idents.get("is_most_derived"),
- getContext().IntTy, ImplicitParamDecl::Other);
- // Only add the parameter to the list if the class has virtual bases.
- if (RD->getNumVBases() > 0)
- FunctionArgs.push_back(&IsMostDerived);
-
- // Start defining the function.
- auto NL = ApplyDebugLocation::CreateEmpty(CGF);
- CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
- FunctionArgs, CD->getLocation(), SourceLocation());
- // Create a scope with an artificial location for the body of this function.
- auto AL = ApplyDebugLocation::CreateArtificial(CGF);
- setCXXABIThisValue(CGF, loadIncomingCXXThis(CGF));
- llvm::Value *This = getThisValue(CGF);
-
- llvm::Value *SrcVal =
- IsCopy ? CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&SrcParam), "src")
- : nullptr;
-
- CallArgList Args;
-
- // Push the this ptr.
- Args.add(RValue::get(This), CD->getThisType());
-
- // Push the src ptr.
- if (SrcVal)
- Args.add(RValue::get(SrcVal), SrcParam.getType());
-
- // Add the rest of the default arguments.
- SmallVector<const Stmt *, 4> ArgVec;
- ArrayRef<ParmVarDecl *> params = CD->parameters().drop_front(IsCopy ? 1 : 0);
- for (const ParmVarDecl *PD : params) {
- assert(PD->hasDefaultArg() && "ctor closure lacks default args");
- ArgVec.push_back(PD->getDefaultArg());
- }
-
- CodeGenFunction::RunCleanupsScope Cleanups(CGF);
-
- const auto *FPT = CD->getType()->castAs<FunctionProtoType>();
- CGF.EmitCallArgs(Args, FPT, llvm::makeArrayRef(ArgVec), CD, IsCopy ? 1 : 0);
-
- // Insert any ABI-specific implicit constructor arguments.
- AddedStructorArgs ExtraArgs =
- addImplicitConstructorArgs(CGF, CD, Ctor_Complete,
- /*ForVirtualBase=*/false,
- /*Delegating=*/false, Args);
- // Call the destructor with our arguments.
- llvm::Constant *CalleePtr =
- CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
- CGCallee Callee =
- CGCallee::forDirect(CalleePtr, GlobalDecl(CD, Ctor_Complete));
- const CGFunctionInfo &CalleeInfo = CGM.getTypes().arrangeCXXConstructorCall(
- Args, CD, Ctor_Complete, ExtraArgs.Prefix, ExtraArgs.Suffix);
- CGF.EmitCall(CalleeInfo, Callee, ReturnValueSlot(), Args);
-
- Cleanups.ForceCleanup();
-
- // Emit the ret instruction, remove any temporary instructions created for the
- // aid of CodeGen.
- CGF.FinishFunction(SourceLocation());
-
- return ThunkFn;
-}
-
-llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
- uint32_t NVOffset,
- int32_t VBPtrOffset,
- uint32_t VBIndex) {
- assert(!T->isReferenceType());
-
- CXXRecordDecl *RD = T->getAsCXXRecordDecl();
- const CXXConstructorDecl *CD =
- RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr;
- CXXCtorType CT = Ctor_Complete;
- if (CD)
- if (!hasDefaultCXXMethodCC(getContext(), CD) || CD->getNumParams() != 1)
- CT = Ctor_CopyingClosure;
-
- uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity();
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- getMangleContext().mangleCXXCatchableType(T, CD, CT, Size, NVOffset,
- VBPtrOffset, VBIndex, Out);
- }
- if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
- return getImageRelativeConstant(GV);
-
- // The TypeDescriptor is used by the runtime to determine if a catch handler
- // is appropriate for the exception object.
- llvm::Constant *TD = getImageRelativeConstant(getAddrOfRTTIDescriptor(T));
-
- // The runtime is responsible for calling the copy constructor if the
- // exception is caught by value.
- llvm::Constant *CopyCtor;
- if (CD) {
- if (CT == Ctor_CopyingClosure)
- CopyCtor = getAddrOfCXXCtorClosure(CD, Ctor_CopyingClosure);
- else
- CopyCtor = CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
-
- CopyCtor = llvm::ConstantExpr::getBitCast(CopyCtor, CGM.Int8PtrTy);
- } else {
- CopyCtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
- }
- CopyCtor = getImageRelativeConstant(CopyCtor);
-
- bool IsScalar = !RD;
- bool HasVirtualBases = false;
- bool IsStdBadAlloc = false; // std::bad_alloc is special for some reason.
- QualType PointeeType = T;
- if (T->isPointerType())
- PointeeType = T->getPointeeType();
- if (const CXXRecordDecl *RD = PointeeType->getAsCXXRecordDecl()) {
- HasVirtualBases = RD->getNumVBases() > 0;
- if (IdentifierInfo *II = RD->getIdentifier())
- IsStdBadAlloc = II->isStr("bad_alloc") && RD->isInStdNamespace();
- }
-
- // Encode the relevant CatchableType properties into the Flags bitfield.
- // FIXME: Figure out how bits 2 or 8 can get set.
- uint32_t Flags = 0;
- if (IsScalar)
- Flags |= 1;
- if (HasVirtualBases)
- Flags |= 4;
- if (IsStdBadAlloc)
- Flags |= 16;
-
- llvm::Constant *Fields[] = {
- llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags
- TD, // TypeDescriptor
- llvm::ConstantInt::get(CGM.IntTy, NVOffset), // NonVirtualAdjustment
- llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset), // OffsetToVBPtr
- llvm::ConstantInt::get(CGM.IntTy, VBIndex), // VBTableIndex
- llvm::ConstantInt::get(CGM.IntTy, Size), // Size
- CopyCtor // CopyCtor
- };
- llvm::StructType *CTType = getCatchableTypeType();
- auto *GV = new llvm::GlobalVariable(
- CGM.getModule(), CTType, /*Constant=*/true, getLinkageForRTTI(T),
- llvm::ConstantStruct::get(CTType, Fields), MangledName);
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- GV->setSection(".xdata");
- if (GV->isWeakForLinker())
- GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName()));
- return getImageRelativeConstant(GV);
-}
-
-llvm::GlobalVariable *MicrosoftCXXABI::getCatchableTypeArray(QualType T) {
- assert(!T->isReferenceType());
-
- // See if we've already generated a CatchableTypeArray for this type before.
- llvm::GlobalVariable *&CTA = CatchableTypeArrays[T];
- if (CTA)
- return CTA;
-
- // Ensure that we don't have duplicate entries in our CatchableTypeArray by
- // using a SmallSetVector. Duplicates may arise due to virtual bases
- // occurring more than once in the hierarchy.
- llvm::SmallSetVector<llvm::Constant *, 2> CatchableTypes;
-
- // C++14 [except.handle]p3:
- // A handler is a match for an exception object of type E if [...]
- // - the handler is of type cv T or cv T& and T is an unambiguous public
- // base class of E, or
- // - the handler is of type cv T or const T& where T is a pointer type and
- // E is a pointer type that can be converted to T by [...]
- // - a standard pointer conversion (4.10) not involving conversions to
- // pointers to private or protected or ambiguous classes
- const CXXRecordDecl *MostDerivedClass = nullptr;
- bool IsPointer = T->isPointerType();
- if (IsPointer)
- MostDerivedClass = T->getPointeeType()->getAsCXXRecordDecl();
- else
- MostDerivedClass = T->getAsCXXRecordDecl();
-
- // Collect all the unambiguous public bases of the MostDerivedClass.
- if (MostDerivedClass) {
- const ASTContext &Context = getContext();
- const ASTRecordLayout &MostDerivedLayout =
- Context.getASTRecordLayout(MostDerivedClass);
- MicrosoftVTableContext &VTableContext = CGM.getMicrosoftVTableContext();
- SmallVector<MSRTTIClass, 8> Classes;
- serializeClassHierarchy(Classes, MostDerivedClass);
- Classes.front().initialize(/*Parent=*/nullptr, /*Specifier=*/nullptr);
- detectAmbiguousBases(Classes);
- for (const MSRTTIClass &Class : Classes) {
- // Skip any ambiguous or private bases.
- if (Class.Flags &
- (MSRTTIClass::IsPrivateOnPath | MSRTTIClass::IsAmbiguous))
- continue;
- // Write down how to convert from a derived pointer to a base pointer.
- uint32_t OffsetInVBTable = 0;
- int32_t VBPtrOffset = -1;
- if (Class.VirtualRoot) {
- OffsetInVBTable =
- VTableContext.getVBTableIndex(MostDerivedClass, Class.VirtualRoot)*4;
- VBPtrOffset = MostDerivedLayout.getVBPtrOffset().getQuantity();
- }
-
- // Turn our record back into a pointer if the exception object is a
- // pointer.
- QualType RTTITy = QualType(Class.RD->getTypeForDecl(), 0);
- if (IsPointer)
- RTTITy = Context.getPointerType(RTTITy);
- CatchableTypes.insert(getCatchableType(RTTITy, Class.OffsetInVBase,
- VBPtrOffset, OffsetInVBTable));
- }
- }
-
- // C++14 [except.handle]p3:
- // A handler is a match for an exception object of type E if
- // - The handler is of type cv T or cv T& and E and T are the same type
- // (ignoring the top-level cv-qualifiers)
- CatchableTypes.insert(getCatchableType(T));
-
- // C++14 [except.handle]p3:
- // A handler is a match for an exception object of type E if
- // - the handler is of type cv T or const T& where T is a pointer type and
- // E is a pointer type that can be converted to T by [...]
- // - a standard pointer conversion (4.10) not involving conversions to
- // pointers to private or protected or ambiguous classes
- //
- // C++14 [conv.ptr]p2:
- // A prvalue of type "pointer to cv T," where T is an object type, can be
- // converted to a prvalue of type "pointer to cv void".
- if (IsPointer && T->getPointeeType()->isObjectType())
- CatchableTypes.insert(getCatchableType(getContext().VoidPtrTy));
-
- // C++14 [except.handle]p3:
- // A handler is a match for an exception object of type E if [...]
- // - the handler is of type cv T or const T& where T is a pointer or
- // pointer to member type and E is std::nullptr_t.
- //
- // We cannot possibly list all possible pointer types here, making this
- // implementation incompatible with the standard. However, MSVC includes an
- // entry for pointer-to-void in this case. Let's do the same.
- if (T->isNullPtrType())
- CatchableTypes.insert(getCatchableType(getContext().VoidPtrTy));
-
- uint32_t NumEntries = CatchableTypes.size();
- llvm::Type *CTType =
- getImageRelativeType(getCatchableTypeType()->getPointerTo());
- llvm::ArrayType *AT = llvm::ArrayType::get(CTType, NumEntries);
- llvm::StructType *CTAType = getCatchableTypeArrayType(NumEntries);
- llvm::Constant *Fields[] = {
- llvm::ConstantInt::get(CGM.IntTy, NumEntries), // NumEntries
- llvm::ConstantArray::get(
- AT, llvm::makeArrayRef(CatchableTypes.begin(),
- CatchableTypes.end())) // CatchableTypes
- };
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- getMangleContext().mangleCXXCatchableTypeArray(T, NumEntries, Out);
- }
- CTA = new llvm::GlobalVariable(
- CGM.getModule(), CTAType, /*Constant=*/true, getLinkageForRTTI(T),
- llvm::ConstantStruct::get(CTAType, Fields), MangledName);
- CTA->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- CTA->setSection(".xdata");
- if (CTA->isWeakForLinker())
- CTA->setComdat(CGM.getModule().getOrInsertComdat(CTA->getName()));
- return CTA;
-}
-
-llvm::GlobalVariable *MicrosoftCXXABI::getThrowInfo(QualType T) {
- bool IsConst, IsVolatile, IsUnaligned;
- T = decomposeTypeForEH(getContext(), T, IsConst, IsVolatile, IsUnaligned);
-
- // The CatchableTypeArray enumerates the various (CV-unqualified) types that
- // the exception object may be caught as.
- llvm::GlobalVariable *CTA = getCatchableTypeArray(T);
- // The first field in a CatchableTypeArray is the number of CatchableTypes.
- // This is used as a component of the mangled name which means that we need to
- // know what it is in order to see if we have previously generated the
- // ThrowInfo.
- uint32_t NumEntries =
- cast<llvm::ConstantInt>(CTA->getInitializer()->getAggregateElement(0U))
- ->getLimitedValue();
-
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- getMangleContext().mangleCXXThrowInfo(T, IsConst, IsVolatile, IsUnaligned,
- NumEntries, Out);
- }
-
- // Reuse a previously generated ThrowInfo if we have generated an appropriate
- // one before.
- if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
- return GV;
-
- // The RTTI TypeDescriptor uses an unqualified type but catch clauses must
- // be at least as CV qualified. Encode this requirement into the Flags
- // bitfield.
- uint32_t Flags = 0;
- if (IsConst)
- Flags |= 1;
- if (IsVolatile)
- Flags |= 2;
- if (IsUnaligned)
- Flags |= 4;
-
- // The cleanup-function (a destructor) must be called when the exception
- // object's lifetime ends.
- llvm::Constant *CleanupFn = llvm::Constant::getNullValue(CGM.Int8PtrTy);
- if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
- if (CXXDestructorDecl *DtorD = RD->getDestructor())
- if (!DtorD->isTrivial())
- CleanupFn = llvm::ConstantExpr::getBitCast(
- CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete),
- CGM.Int8PtrTy);
- // This is unused as far as we can tell, initialize it to null.
- llvm::Constant *ForwardCompat =
- getImageRelativeConstant(llvm::Constant::getNullValue(CGM.Int8PtrTy));
- llvm::Constant *PointerToCatchableTypes = getImageRelativeConstant(
- llvm::ConstantExpr::getBitCast(CTA, CGM.Int8PtrTy));
- llvm::StructType *TIType = getThrowInfoType();
- llvm::Constant *Fields[] = {
- llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags
- getImageRelativeConstant(CleanupFn), // CleanupFn
- ForwardCompat, // ForwardCompat
- PointerToCatchableTypes // CatchableTypeArray
- };
- auto *GV = new llvm::GlobalVariable(
- CGM.getModule(), TIType, /*Constant=*/true, getLinkageForRTTI(T),
- llvm::ConstantStruct::get(TIType, Fields), StringRef(MangledName));
- GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- GV->setSection(".xdata");
- if (GV->isWeakForLinker())
- GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName()));
- return GV;
-}
-
-void MicrosoftCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
- const Expr *SubExpr = E->getSubExpr();
- QualType ThrowType = SubExpr->getType();
- // The exception object lives on the stack and it's address is passed to the
- // runtime function.
- Address AI = CGF.CreateMemTemp(ThrowType);
- CGF.EmitAnyExprToMem(SubExpr, AI, ThrowType.getQualifiers(),
- /*IsInit=*/true);
-
- // The so-called ThrowInfo is used to describe how the exception object may be
- // caught.
- llvm::GlobalVariable *TI = getThrowInfo(ThrowType);
-
- // Call into the runtime to throw the exception.
- llvm::Value *Args[] = {
- CGF.Builder.CreateBitCast(AI.getPointer(), CGM.Int8PtrTy),
- TI
- };
- CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(), Args);
-}
-
-std::pair<llvm::Value *, const CXXRecordDecl *>
-MicrosoftCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This,
- const CXXRecordDecl *RD) {
- std::tie(This, std::ignore, RD) =
- performBaseAdjustment(CGF, This, QualType(RD->getTypeForDecl(), 0));
- return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD};
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp b/gnu/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp
deleted file mode 100644
index c0a37698e76..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp
+++ /dev/null
@@ -1,332 +0,0 @@
-//===--- ModuleBuilder.cpp - Emit LLVM Code from ASTs ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This builds an AST and converts it to LLVM Code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CodeGen/ModuleBuilder.h"
-#include "CGDebugInfo.h"
-#include "CodeGenModule.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include <memory>
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
- class CodeGeneratorImpl : public CodeGenerator {
- DiagnosticsEngine &Diags;
- ASTContext *Ctx;
- const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
- const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
- const CodeGenOptions CodeGenOpts; // Intentionally copied in.
-
- unsigned HandlingTopLevelDecls;
-
- /// Use this when emitting decls to block re-entrant decl emission. It will
- /// emit all deferred decls on scope exit. Set EmitDeferred to false if decl
- /// emission must be deferred longer, like at the end of a tag definition.
- struct HandlingTopLevelDeclRAII {
- CodeGeneratorImpl &Self;
- bool EmitDeferred;
- HandlingTopLevelDeclRAII(CodeGeneratorImpl &Self,
- bool EmitDeferred = true)
- : Self(Self), EmitDeferred(EmitDeferred) {
- ++Self.HandlingTopLevelDecls;
- }
- ~HandlingTopLevelDeclRAII() {
- unsigned Level = --Self.HandlingTopLevelDecls;
- if (Level == 0 && EmitDeferred)
- Self.EmitDeferredDecls();
- }
- };
-
- CoverageSourceInfo *CoverageInfo;
-
- protected:
- std::unique_ptr<llvm::Module> M;
- std::unique_ptr<CodeGen::CodeGenModule> Builder;
-
- private:
- SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
-
- public:
- CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
- const HeaderSearchOptions &HSO,
- const PreprocessorOptions &PPO, const CodeGenOptions &CGO,
- llvm::LLVMContext &C,
- CoverageSourceInfo *CoverageInfo = nullptr)
- : Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO),
- PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
- CoverageInfo(CoverageInfo), M(new llvm::Module(ModuleName, C)) {
- C.setDiscardValueNames(CGO.DiscardValueNames);
- }
-
- ~CodeGeneratorImpl() override {
- // There should normally not be any leftover inline method definitions.
- assert(DeferredInlineMemberFuncDefs.empty() ||
- Diags.hasErrorOccurred());
- }
-
- CodeGenModule &CGM() {
- return *Builder;
- }
-
- llvm::Module *GetModule() {
- return M.get();
- }
-
- CGDebugInfo *getCGDebugInfo() {
- return Builder->getModuleDebugInfo();
- }
-
- llvm::Module *ReleaseModule() {
- return M.release();
- }
-
- const Decl *GetDeclForMangledName(StringRef MangledName) {
- GlobalDecl Result;
- if (!Builder->lookupRepresentativeDecl(MangledName, Result))
- return nullptr;
- const Decl *D = Result.getCanonicalDecl().getDecl();
- if (auto FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->hasBody(FD))
- return FD;
- } else if (auto TD = dyn_cast<TagDecl>(D)) {
- if (auto Def = TD->getDefinition())
- return Def;
- }
- return D;
- }
-
- llvm::Constant *GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) {
- return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition));
- }
-
- llvm::Module *StartModule(llvm::StringRef ModuleName,
- llvm::LLVMContext &C) {
- assert(!M && "Replacing existing Module?");
- M.reset(new llvm::Module(ModuleName, C));
- Initialize(*Ctx);
- return M.get();
- }
-
- void Initialize(ASTContext &Context) override {
- Ctx = &Context;
-
- M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
- M->setDataLayout(Ctx->getTargetInfo().getDataLayout());
- const auto &SDKVersion = Ctx->getTargetInfo().getSDKVersion();
- if (!SDKVersion.empty())
- M->setSDKVersion(SDKVersion);
- Builder.reset(new CodeGen::CodeGenModule(Context, HeaderSearchOpts,
- PreprocessorOpts, CodeGenOpts,
- *M, Diags, CoverageInfo));
-
- for (auto &&Lib : CodeGenOpts.DependentLibraries)
- Builder->AddDependentLib(Lib);
- for (auto &&Opt : CodeGenOpts.LinkerOptions)
- Builder->AppendLinkerOptions(Opt);
- }
-
- void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
- if (Diags.hasErrorOccurred())
- return;
-
- Builder->HandleCXXStaticMemberVarInstantiation(VD);
- }
-
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
- if (Diags.hasErrorOccurred())
- return true;
-
- HandlingTopLevelDeclRAII HandlingDecl(*this);
-
- // Make sure to emit all elements of a Decl.
- for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
- Builder->EmitTopLevelDecl(*I);
-
- return true;
- }
-
- void EmitDeferredDecls() {
- if (DeferredInlineMemberFuncDefs.empty())
- return;
-
- // Emit any deferred inline method definitions. Note that more deferred
- // methods may be added during this loop, since ASTConsumer callbacks
- // can be invoked if AST inspection results in declarations being added.
- HandlingTopLevelDeclRAII HandlingDecl(*this);
- for (unsigned I = 0; I != DeferredInlineMemberFuncDefs.size(); ++I)
- Builder->EmitTopLevelDecl(DeferredInlineMemberFuncDefs[I]);
- DeferredInlineMemberFuncDefs.clear();
- }
-
- void HandleInlineFunctionDefinition(FunctionDecl *D) override {
- if (Diags.hasErrorOccurred())
- return;
-
- assert(D->doesThisDeclarationHaveABody());
-
- // We may want to emit this definition. However, that decision might be
- // based on computing the linkage, and we have to defer that in case we
- // are inside of something that will change the method's final linkage,
- // e.g.
- // typedef struct {
- // void bar();
- // void foo() { bar(); }
- // } A;
- DeferredInlineMemberFuncDefs.push_back(D);
-
- // Provide some coverage mapping even for methods that aren't emitted.
- // Don't do this for templated classes though, as they may not be
- // instantiable.
- if (!D->getLexicalDeclContext()->isDependentContext())
- Builder->AddDeferredUnusedCoverageMapping(D);
- }
-
- /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
- /// to (e.g. struct, union, enum, class) is completed. This allows the
- /// client hack on the type, which can occur at any point in the file
- /// (because these can be defined in declspecs).
- void HandleTagDeclDefinition(TagDecl *D) override {
- if (Diags.hasErrorOccurred())
- return;
-
- // Don't allow re-entrant calls to CodeGen triggered by PCH
- // deserialization to emit deferred decls.
- HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
-
- Builder->UpdateCompletedType(D);
-
- // For MSVC compatibility, treat declarations of static data members with
- // inline initializers as definitions.
- if (Ctx->getTargetInfo().getCXXABI().isMicrosoft()) {
- for (Decl *Member : D->decls()) {
- if (VarDecl *VD = dyn_cast<VarDecl>(Member)) {
- if (Ctx->isMSStaticDataMemberInlineDefinition(VD) &&
- Ctx->DeclMustBeEmitted(VD)) {
- Builder->EmitGlobal(VD);
- }
- }
- }
- }
- // For OpenMP emit declare reduction functions, if required.
- if (Ctx->getLangOpts().OpenMP) {
- for (Decl *Member : D->decls()) {
- if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Member)) {
- if (Ctx->DeclMustBeEmitted(DRD))
- Builder->EmitGlobal(DRD);
- }
- }
- }
- }
-
- void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
- if (Diags.hasErrorOccurred())
- return;
-
- // Don't allow re-entrant calls to CodeGen triggered by PCH
- // deserialization to emit deferred decls.
- HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
-
- if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
- DI->completeRequiredType(RD);
- }
-
- void HandleTranslationUnit(ASTContext &Ctx) override {
- // Release the Builder when there is no error.
- if (!Diags.hasErrorOccurred() && Builder)
- Builder->Release();
-
- // If there are errors before or when releasing the Builder, reset
- // the module to stop here before invoking the backend.
- if (Diags.hasErrorOccurred()) {
- if (Builder)
- Builder->clear();
- M.reset();
- return;
- }
- }
-
- void AssignInheritanceModel(CXXRecordDecl *RD) override {
- if (Diags.hasErrorOccurred())
- return;
-
- Builder->RefreshTypeCacheForClass(RD);
- }
-
- void CompleteTentativeDefinition(VarDecl *D) override {
- if (Diags.hasErrorOccurred())
- return;
-
- Builder->EmitTentativeDefinition(D);
- }
-
- void HandleVTable(CXXRecordDecl *RD) override {
- if (Diags.hasErrorOccurred())
- return;
-
- Builder->EmitVTable(RD);
- }
- };
-}
-
-void CodeGenerator::anchor() { }
-
-CodeGenModule &CodeGenerator::CGM() {
- return static_cast<CodeGeneratorImpl*>(this)->CGM();
-}
-
-llvm::Module *CodeGenerator::GetModule() {
- return static_cast<CodeGeneratorImpl*>(this)->GetModule();
-}
-
-llvm::Module *CodeGenerator::ReleaseModule() {
- return static_cast<CodeGeneratorImpl*>(this)->ReleaseModule();
-}
-
-CGDebugInfo *CodeGenerator::getCGDebugInfo() {
- return static_cast<CodeGeneratorImpl*>(this)->getCGDebugInfo();
-}
-
-const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) {
- return static_cast<CodeGeneratorImpl*>(this)->GetDeclForMangledName(name);
-}
-
-llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global,
- bool isForDefinition) {
- return static_cast<CodeGeneratorImpl*>(this)
- ->GetAddrOfGlobal(global, isForDefinition);
-}
-
-llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
- llvm::LLVMContext &C) {
- return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
-}
-
-CodeGenerator *clang::CreateLLVMCodeGen(
- DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PreprocessorOpts, const CodeGenOptions &CGO,
- llvm::LLVMContext &C, CoverageSourceInfo *CoverageInfo) {
- return new CodeGeneratorImpl(Diags, ModuleName, HeaderSearchOpts,
- PreprocessorOpts, CGO, C, CoverageInfo);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/gnu/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
deleted file mode 100644
index 6f00c836f93..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-//===--- ObjectFilePCHContainerOperations.cpp -----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
-#include "CGDebugInfo.h"
-#include "CodeGenModule.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/CodeGen/BackendUtil.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/TargetRegistry.h"
-#include <memory>
-#include <utility>
-
-using namespace clang;
-
-#define DEBUG_TYPE "pchcontainer"
-
-namespace {
-class PCHContainerGenerator : public ASTConsumer {
- DiagnosticsEngine &Diags;
- const std::string MainFileName;
- const std::string OutputFileName;
- ASTContext *Ctx;
- ModuleMap &MMap;
- const HeaderSearchOptions &HeaderSearchOpts;
- const PreprocessorOptions &PreprocessorOpts;
- CodeGenOptions CodeGenOpts;
- const TargetOptions TargetOpts;
- const LangOptions LangOpts;
- std::unique_ptr<llvm::LLVMContext> VMContext;
- std::unique_ptr<llvm::Module> M;
- std::unique_ptr<CodeGen::CodeGenModule> Builder;
- std::unique_ptr<raw_pwrite_stream> OS;
- std::shared_ptr<PCHBuffer> Buffer;
-
- /// Visit every type and emit debug info for it.
- struct DebugTypeVisitor : public RecursiveASTVisitor<DebugTypeVisitor> {
- clang::CodeGen::CGDebugInfo &DI;
- ASTContext &Ctx;
- DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx)
- : DI(DI), Ctx(Ctx) {}
-
- /// Determine whether this type can be represented in DWARF.
- static bool CanRepresent(const Type *Ty) {
- return !Ty->isDependentType() && !Ty->isUndeducedType();
- }
-
- bool VisitImportDecl(ImportDecl *D) {
- if (!D->getImportedOwningModule())
- DI.EmitImportDecl(*D);
- return true;
- }
-
- bool VisitTypeDecl(TypeDecl *D) {
- // TagDecls may be deferred until after all decls have been merged and we
- // know the complete type. Pure forward declarations will be skipped, but
- // they don't need to be emitted into the module anyway.
- if (auto *TD = dyn_cast<TagDecl>(D))
- if (!TD->isCompleteDefinition())
- return true;
-
- QualType QualTy = Ctx.getTypeDeclType(D);
- if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
- DI.getOrCreateStandaloneType(QualTy, D->getLocation());
- return true;
- }
-
- bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
- QualType QualTy(D->getTypeForDecl(), 0);
- if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
- DI.getOrCreateStandaloneType(QualTy, D->getLocation());
- return true;
- }
-
- bool VisitFunctionDecl(FunctionDecl *D) {
- if (isa<CXXMethodDecl>(D))
- // This is not yet supported. Constructing the `this' argument
- // mandates a CodeGenFunction.
- return true;
-
- SmallVector<QualType, 16> ArgTypes;
- for (auto i : D->parameters())
- ArgTypes.push_back(i->getType());
- QualType RetTy = D->getReturnType();
- QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
- FunctionProtoType::ExtProtoInfo());
- if (CanRepresent(FnTy.getTypePtr()))
- DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
- return true;
- }
-
- bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
- if (!D->getClassInterface())
- return true;
-
- bool selfIsPseudoStrong, selfIsConsumed;
- SmallVector<QualType, 16> ArgTypes;
- ArgTypes.push_back(D->getSelfType(Ctx, D->getClassInterface(),
- selfIsPseudoStrong, selfIsConsumed));
- ArgTypes.push_back(Ctx.getObjCSelType());
- for (auto i : D->parameters())
- ArgTypes.push_back(i->getType());
- QualType RetTy = D->getReturnType();
- QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
- FunctionProtoType::ExtProtoInfo());
- if (CanRepresent(FnTy.getTypePtr()))
- DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
- return true;
- }
- };
-
-public:
- PCHContainerGenerator(CompilerInstance &CI, const std::string &MainFileName,
- const std::string &OutputFileName,
- std::unique_ptr<raw_pwrite_stream> OS,
- std::shared_ptr<PCHBuffer> Buffer)
- : Diags(CI.getDiagnostics()), MainFileName(MainFileName),
- OutputFileName(OutputFileName), Ctx(nullptr),
- MMap(CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()),
- HeaderSearchOpts(CI.getHeaderSearchOpts()),
- PreprocessorOpts(CI.getPreprocessorOpts()),
- TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()),
- OS(std::move(OS)), Buffer(std::move(Buffer)) {
- // The debug info output isn't affected by CodeModel and
- // ThreadModel, but the backend expects them to be nonempty.
- CodeGenOpts.CodeModel = "default";
- CodeGenOpts.ThreadModel = "single";
- CodeGenOpts.DebugTypeExtRefs = true;
- // When building a module MainFileName is the name of the modulemap file.
- CodeGenOpts.MainFileName =
- LangOpts.CurrentModule.empty() ? MainFileName : LangOpts.CurrentModule;
- CodeGenOpts.setDebugInfo(codegenoptions::FullDebugInfo);
- CodeGenOpts.setDebuggerTuning(CI.getCodeGenOpts().getDebuggerTuning());
- CodeGenOpts.DebugPrefixMap =
- CI.getInvocation().getCodeGenOpts().DebugPrefixMap;
- }
-
- ~PCHContainerGenerator() override = default;
-
- void Initialize(ASTContext &Context) override {
- assert(!Ctx && "initialized multiple times");
-
- Ctx = &Context;
- VMContext.reset(new llvm::LLVMContext());
- M.reset(new llvm::Module(MainFileName, *VMContext));
- M->setDataLayout(Ctx->getTargetInfo().getDataLayout());
- Builder.reset(new CodeGen::CodeGenModule(
- *Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
-
- // Prepare CGDebugInfo to emit debug info for a clang module.
- auto *DI = Builder->getModuleDebugInfo();
- StringRef ModuleName = llvm::sys::path::filename(MainFileName);
- DI->setPCHDescriptor({ModuleName, "", OutputFileName,
- ASTFileSignature{{{~0U, ~0U, ~0U, ~0U, ~1U}}}});
- DI->setModuleMap(MMap);
- }
-
- bool HandleTopLevelDecl(DeclGroupRef D) override {
- if (Diags.hasErrorOccurred())
- return true;
-
- // Collect debug info for all decls in this group.
- for (auto *I : D)
- if (!I->isFromASTFile()) {
- DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
- DTV.TraverseDecl(I);
- }
- return true;
- }
-
- void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override {
- HandleTopLevelDecl(D);
- }
-
- void HandleTagDeclDefinition(TagDecl *D) override {
- if (Diags.hasErrorOccurred())
- return;
-
- if (D->isFromASTFile())
- return;
-
- // Anonymous tag decls are deferred until we are building their declcontext.
- if (D->getName().empty())
- return;
-
- // Defer tag decls until their declcontext is complete.
- auto *DeclCtx = D->getDeclContext();
- while (DeclCtx) {
- if (auto *D = dyn_cast<TagDecl>(DeclCtx))
- if (!D->isCompleteDefinition())
- return;
- DeclCtx = DeclCtx->getParent();
- }
-
- DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
- DTV.TraverseDecl(D);
- Builder->UpdateCompletedType(D);
- }
-
- void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
- if (Diags.hasErrorOccurred())
- return;
-
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
- Builder->getModuleDebugInfo()->completeRequiredType(RD);
- }
-
- void HandleImplicitImportDecl(ImportDecl *D) override {
- if (!D->getImportedOwningModule())
- Builder->getModuleDebugInfo()->EmitImportDecl(*D);
- }
-
- /// Emit a container holding the serialized AST.
- void HandleTranslationUnit(ASTContext &Ctx) override {
- assert(M && VMContext && Builder);
- // Delete these on function exit.
- std::unique_ptr<llvm::LLVMContext> VMContext = std::move(this->VMContext);
- std::unique_ptr<llvm::Module> M = std::move(this->M);
- std::unique_ptr<CodeGen::CodeGenModule> Builder = std::move(this->Builder);
-
- if (Diags.hasErrorOccurred())
- return;
-
- M->setTargetTriple(Ctx.getTargetInfo().getTriple().getTriple());
- M->setDataLayout(Ctx.getTargetInfo().getDataLayout());
-
- // PCH files don't have a signature field in the control block,
- // but LLVM detects DWO CUs by looking for a non-zero DWO id.
- // We use the lower 64 bits for debug info.
- uint64_t Signature =
- Buffer->Signature
- ? (uint64_t)Buffer->Signature[1] << 32 | Buffer->Signature[0]
- : ~1ULL;
- Builder->getModuleDebugInfo()->setDwoId(Signature);
-
- // Finalize the Builder.
- if (Builder)
- Builder->Release();
-
- // Ensure the target exists.
- std::string Error;
- auto Triple = Ctx.getTargetInfo().getTriple();
- if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error))
- llvm::report_fatal_error(Error);
-
- // Emit the serialized Clang AST into its own section.
- assert(Buffer->IsComplete && "serialization did not complete");
- auto &SerializedAST = Buffer->Data;
- auto Size = SerializedAST.size();
- auto Int8Ty = llvm::Type::getInt8Ty(*VMContext);
- auto *Ty = llvm::ArrayType::get(Int8Ty, Size);
- auto *Data = llvm::ConstantDataArray::getString(
- *VMContext, StringRef(SerializedAST.data(), Size),
- /*AddNull=*/false);
- auto *ASTSym = new llvm::GlobalVariable(
- *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, Data,
- "__clang_ast");
- // The on-disk hashtable needs to be aligned.
- ASTSym->setAlignment(8);
-
- // Mach-O also needs a segment name.
- if (Triple.isOSBinFormatMachO())
- ASTSym->setSection("__CLANG,__clangast");
- // COFF has an eight character length limit.
- else if (Triple.isOSBinFormatCOFF())
- ASTSym->setSection("clangast");
- else
- ASTSym->setSection("__clangast");
-
- LLVM_DEBUG({
- // Print the IR for the PCH container to the debug output.
- llvm::SmallString<0> Buffer;
- clang::EmitBackendOutput(
- Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts,
- Ctx.getTargetInfo().getDataLayout(), M.get(),
- BackendAction::Backend_EmitLL,
- llvm::make_unique<llvm::raw_svector_ostream>(Buffer));
- llvm::dbgs() << Buffer;
- });
-
- // Use the LLVM backend to emit the pch container.
- clang::EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts,
- LangOpts, Ctx.getTargetInfo().getDataLayout(),
- M.get(), BackendAction::Backend_EmitObj,
- std::move(OS));
-
- // Free the memory for the temporary buffer.
- llvm::SmallVector<char, 0> Empty;
- SerializedAST = std::move(Empty);
- }
-};
-
-} // anonymous namespace
-
-std::unique_ptr<ASTConsumer>
-ObjectFilePCHContainerWriter::CreatePCHContainerGenerator(
- CompilerInstance &CI, const std::string &MainFileName,
- const std::string &OutputFileName,
- std::unique_ptr<llvm::raw_pwrite_stream> OS,
- std::shared_ptr<PCHBuffer> Buffer) const {
- return llvm::make_unique<PCHContainerGenerator>(
- CI, MainFileName, OutputFileName, std::move(OS), Buffer);
-}
-
-StringRef
-ObjectFilePCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
- StringRef PCH;
- auto OFOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
- if (OFOrErr) {
- auto &OF = OFOrErr.get();
- bool IsCOFF = isa<llvm::object::COFFObjectFile>(*OF);
- // Find the clang AST section in the container.
- for (auto &Section : OF->sections()) {
- StringRef Name;
- Section.getName(Name);
- if ((!IsCOFF && Name == "__clangast") || (IsCOFF && Name == "clangast")) {
- Section.getContents(PCH);
- return PCH;
- }
- }
- }
- handleAllErrors(OFOrErr.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
- if (EIB.convertToErrorCode() ==
- llvm::object::object_error::invalid_file_type)
- // As a fallback, treat the buffer as a raw AST.
- PCH = Buffer.getBuffer();
- else
- EIB.log(llvm::errs());
- });
- return PCH;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/README.txt b/gnu/llvm/tools/clang/lib/CodeGen/README.txt
deleted file mode 100644
index e6d61095bf2..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/README.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-IRgen optimization opportunities.
-
-//===---------------------------------------------------------------------===//
-
-The common pattern of
---
-short x; // or char, etc
-(x == 10)
---
-generates an zext/sext of x which can easily be avoided.
-
-//===---------------------------------------------------------------------===//
-
-Bitfields accesses can be shifted to simplify masking and sign
-extension. For example, if the bitfield width is 8 and it is
-appropriately aligned then is is a lot shorter to just load the char
-directly.
-
-//===---------------------------------------------------------------------===//
-
-It may be worth avoiding creation of alloca's for formal arguments
-for the common situation where the argument is never written to or has
-its address taken. The idea would be to begin generating code by using
-the argument directly and if its address is taken or it is stored to
-then generate the alloca and patch up the existing code.
-
-In theory, the same optimization could be a win for block local
-variables as long as the declaration dominates all statements in the
-block.
-
-NOTE: The main case we care about this for is for -O0 -g compile time
-performance, and in that scenario we will need to emit the alloca
-anyway currently to emit proper debug info. So this is blocked by
-being able to emit debug information which refers to an LLVM
-temporary, not an alloca.
-
-//===---------------------------------------------------------------------===//
-
-We should try and avoid generating basic blocks which only contain
-jumps. At -O0, this penalizes us all the way from IRgen (malloc &
-instruction overhead), all the way down through code generation and
-assembly time.
-
-On 176.gcc:expr.ll, it looks like over 12% of basic blocks are just
-direct branches!
-
-//===---------------------------------------------------------------------===//
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp b/gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp
deleted file mode 100644
index 23cf9e49082..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-//===--- SanitizerMetadata.cpp - Blacklist for sanitizers -----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Class which emits metadata consumed by sanitizer instrumentation passes.
-//
-//===----------------------------------------------------------------------===//
-#include "SanitizerMetadata.h"
-#include "CodeGenModule.h"
-#include "clang/AST/Type.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/IR/Constants.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
-
-void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
- SourceLocation Loc, StringRef Name,
- QualType Ty, bool IsDynInit,
- bool IsBlacklisted) {
- if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
- SanitizerKind::KernelAddress |
- SanitizerKind::HWAddress |
- SanitizerKind::KernelHWAddress))
- return;
- IsDynInit &= !CGM.isInSanitizerBlacklist(GV, Loc, Ty, "init");
- IsBlacklisted |= CGM.isInSanitizerBlacklist(GV, Loc, Ty);
-
- llvm::Metadata *LocDescr = nullptr;
- llvm::Metadata *GlobalName = nullptr;
- llvm::LLVMContext &VMContext = CGM.getLLVMContext();
- if (!IsBlacklisted) {
- // Don't generate source location and global name if it is blacklisted -
- // it won't be instrumented anyway.
- LocDescr = getLocationMetadata(Loc);
- if (!Name.empty())
- GlobalName = llvm::MDString::get(VMContext, Name);
- }
-
- llvm::Metadata *GlobalMetadata[] = {
- llvm::ConstantAsMetadata::get(GV), LocDescr, GlobalName,
- llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsDynInit)),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::Type::getInt1Ty(VMContext), IsBlacklisted))};
-
- llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalMetadata);
- llvm::NamedMDNode *AsanGlobals =
- CGM.getModule().getOrInsertNamedMetadata("llvm.asan.globals");
- AsanGlobals->addOperand(ThisGlobal);
-}
-
-void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
- const VarDecl &D, bool IsDynInit) {
- if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
- SanitizerKind::KernelAddress |
- SanitizerKind::HWAddress |
- SanitizerKind::KernelHWAddress))
- return;
- std::string QualName;
- llvm::raw_string_ostream OS(QualName);
- D.printQualifiedName(OS);
-
- bool IsBlacklisted = false;
- for (auto Attr : D.specific_attrs<NoSanitizeAttr>())
- if (Attr->getMask() & SanitizerKind::Address)
- IsBlacklisted = true;
- reportGlobalToASan(GV, D.getLocation(), OS.str(), D.getType(), IsDynInit,
- IsBlacklisted);
-}
-
-void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
- // For now, just make sure the global is not modified by the ASan
- // instrumentation.
- if (CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
- SanitizerKind::KernelAddress |
- SanitizerKind::HWAddress |
- SanitizerKind::KernelHWAddress))
- reportGlobalToASan(GV, SourceLocation(), "", QualType(), false, true);
-}
-
-void SanitizerMetadata::disableSanitizerForInstruction(llvm::Instruction *I) {
- I->setMetadata(CGM.getModule().getMDKindID("nosanitize"),
- llvm::MDNode::get(CGM.getLLVMContext(), None));
-}
-
-llvm::MDNode *SanitizerMetadata::getLocationMetadata(SourceLocation Loc) {
- PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc);
- if (!PLoc.isValid())
- return nullptr;
- llvm::LLVMContext &VMContext = CGM.getLLVMContext();
- llvm::Metadata *LocMetadata[] = {
- llvm::MDString::get(VMContext, PLoc.getFilename()),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), PLoc.getLine())),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), PLoc.getColumn())),
- };
- return llvm::MDNode::get(VMContext, LocMetadata);
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.h b/gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.h
deleted file mode 100644
index 166f0e6c9b5..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.h
+++ /dev/null
@@ -1,53 +0,0 @@
-//===--- SanitizerMetadata.h - Metadata for sanitizers ----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Class which emits metadata consumed by sanitizer instrumentation passes.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LIB_CODEGEN_SANITIZERMETADATA_H
-#define LLVM_CLANG_LIB_CODEGEN_SANITIZERMETADATA_H
-
-#include "clang/AST/Type.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SourceLocation.h"
-
-namespace llvm {
-class GlobalVariable;
-class Instruction;
-class MDNode;
-}
-
-namespace clang {
-class VarDecl;
-
-namespace CodeGen {
-
-class CodeGenModule;
-
-class SanitizerMetadata {
- SanitizerMetadata(const SanitizerMetadata &) = delete;
- void operator=(const SanitizerMetadata &) = delete;
-
- CodeGenModule &CGM;
-public:
- SanitizerMetadata(CodeGenModule &CGM);
- void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D,
- bool IsDynInit = false);
- void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc,
- StringRef Name, QualType Ty, bool IsDynInit = false,
- bool IsBlacklisted = false);
- void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
- void disableSanitizerForInstruction(llvm::Instruction *I);
-private:
- llvm::MDNode *getLocationMetadata(SourceLocation Loc);
-};
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp b/gnu/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp
deleted file mode 100644
index 75a0fa5ce18..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp
+++ /dev/null
@@ -1,865 +0,0 @@
-//===--- SwiftCallingConv.cpp - Lowering for the Swift calling convention -===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of the abstract lowering for the Swift calling convention.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CodeGen/SwiftCallingConv.h"
-#include "clang/Basic/TargetInfo.h"
-#include "CodeGenModule.h"
-#include "TargetInfo.h"
-
-using namespace clang;
-using namespace CodeGen;
-using namespace swiftcall;
-
-static const SwiftABIInfo &getSwiftABIInfo(CodeGenModule &CGM) {
- return cast<SwiftABIInfo>(CGM.getTargetCodeGenInfo().getABIInfo());
-}
-
-static bool isPowerOf2(unsigned n) {
- return n == (n & -n);
-}
-
-/// Given two types with the same size, try to find a common type.
-static llvm::Type *getCommonType(llvm::Type *first, llvm::Type *second) {
- assert(first != second);
-
- // Allow pointers to merge with integers, but prefer the integer type.
- if (first->isIntegerTy()) {
- if (second->isPointerTy()) return first;
- } else if (first->isPointerTy()) {
- if (second->isIntegerTy()) return second;
- if (second->isPointerTy()) return first;
-
- // Allow two vectors to be merged (given that they have the same size).
- // This assumes that we never have two different vector register sets.
- } else if (auto firstVecTy = dyn_cast<llvm::VectorType>(first)) {
- if (auto secondVecTy = dyn_cast<llvm::VectorType>(second)) {
- if (auto commonTy = getCommonType(firstVecTy->getElementType(),
- secondVecTy->getElementType())) {
- return (commonTy == firstVecTy->getElementType() ? first : second);
- }
- }
- }
-
- return nullptr;
-}
-
-static CharUnits getTypeStoreSize(CodeGenModule &CGM, llvm::Type *type) {
- return CharUnits::fromQuantity(CGM.getDataLayout().getTypeStoreSize(type));
-}
-
-static CharUnits getTypeAllocSize(CodeGenModule &CGM, llvm::Type *type) {
- return CharUnits::fromQuantity(CGM.getDataLayout().getTypeAllocSize(type));
-}
-
-void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) {
- // Deal with various aggregate types as special cases:
-
- // Record types.
- if (auto recType = type->getAs<RecordType>()) {
- addTypedData(recType->getDecl(), begin);
-
- // Array types.
- } else if (type->isArrayType()) {
- // Incomplete array types (flexible array members?) don't provide
- // data to lay out, and the other cases shouldn't be possible.
- auto arrayType = CGM.getContext().getAsConstantArrayType(type);
- if (!arrayType) return;
-
- QualType eltType = arrayType->getElementType();
- auto eltSize = CGM.getContext().getTypeSizeInChars(eltType);
- for (uint64_t i = 0, e = arrayType->getSize().getZExtValue(); i != e; ++i) {
- addTypedData(eltType, begin + i * eltSize);
- }
-
- // Complex types.
- } else if (auto complexType = type->getAs<ComplexType>()) {
- auto eltType = complexType->getElementType();
- auto eltSize = CGM.getContext().getTypeSizeInChars(eltType);
- auto eltLLVMType = CGM.getTypes().ConvertType(eltType);
- addTypedData(eltLLVMType, begin, begin + eltSize);
- addTypedData(eltLLVMType, begin + eltSize, begin + 2 * eltSize);
-
- // Member pointer types.
- } else if (type->getAs<MemberPointerType>()) {
- // Just add it all as opaque.
- addOpaqueData(begin, begin + CGM.getContext().getTypeSizeInChars(type));
-
- // Everything else is scalar and should not convert as an LLVM aggregate.
- } else {
- // We intentionally convert as !ForMem because we want to preserve
- // that a type was an i1.
- auto llvmType = CGM.getTypes().ConvertType(type);
- addTypedData(llvmType, begin);
- }
-}
-
-void SwiftAggLowering::addTypedData(const RecordDecl *record, CharUnits begin) {
- addTypedData(record, begin, CGM.getContext().getASTRecordLayout(record));
-}
-
-void SwiftAggLowering::addTypedData(const RecordDecl *record, CharUnits begin,
- const ASTRecordLayout &layout) {
- // Unions are a special case.
- if (record->isUnion()) {
- for (auto field : record->fields()) {
- if (field->isBitField()) {
- addBitFieldData(field, begin, 0);
- } else {
- addTypedData(field->getType(), begin);
- }
- }
- return;
- }
-
- // Note that correctness does not rely on us adding things in
- // their actual order of layout; it's just somewhat more efficient
- // for the builder.
-
- // With that in mind, add "early" C++ data.
- auto cxxRecord = dyn_cast<CXXRecordDecl>(record);
- if (cxxRecord) {
- // - a v-table pointer, if the class adds its own
- if (layout.hasOwnVFPtr()) {
- addTypedData(CGM.Int8PtrTy, begin);
- }
-
- // - non-virtual bases
- for (auto &baseSpecifier : cxxRecord->bases()) {
- if (baseSpecifier.isVirtual()) continue;
-
- auto baseRecord = baseSpecifier.getType()->getAsCXXRecordDecl();
- addTypedData(baseRecord, begin + layout.getBaseClassOffset(baseRecord));
- }
-
- // - a vbptr if the class adds its own
- if (layout.hasOwnVBPtr()) {
- addTypedData(CGM.Int8PtrTy, begin + layout.getVBPtrOffset());
- }
- }
-
- // Add fields.
- for (auto field : record->fields()) {
- auto fieldOffsetInBits = layout.getFieldOffset(field->getFieldIndex());
- if (field->isBitField()) {
- addBitFieldData(field, begin, fieldOffsetInBits);
- } else {
- addTypedData(field->getType(),
- begin + CGM.getContext().toCharUnitsFromBits(fieldOffsetInBits));
- }
- }
-
- // Add "late" C++ data:
- if (cxxRecord) {
- // - virtual bases
- for (auto &vbaseSpecifier : cxxRecord->vbases()) {
- auto baseRecord = vbaseSpecifier.getType()->getAsCXXRecordDecl();
- addTypedData(baseRecord, begin + layout.getVBaseClassOffset(baseRecord));
- }
- }
-}
-
-void SwiftAggLowering::addBitFieldData(const FieldDecl *bitfield,
- CharUnits recordBegin,
- uint64_t bitfieldBitBegin) {
- assert(bitfield->isBitField());
- auto &ctx = CGM.getContext();
- auto width = bitfield->getBitWidthValue(ctx);
-
- // We can ignore zero-width bit-fields.
- if (width == 0) return;
-
- // toCharUnitsFromBits rounds down.
- CharUnits bitfieldByteBegin = ctx.toCharUnitsFromBits(bitfieldBitBegin);
-
- // Find the offset of the last byte that is partially occupied by the
- // bit-field; since we otherwise expect exclusive ends, the end is the
- // next byte.
- uint64_t bitfieldBitLast = bitfieldBitBegin + width - 1;
- CharUnits bitfieldByteEnd =
- ctx.toCharUnitsFromBits(bitfieldBitLast) + CharUnits::One();
- addOpaqueData(recordBegin + bitfieldByteBegin,
- recordBegin + bitfieldByteEnd);
-}
-
-void SwiftAggLowering::addTypedData(llvm::Type *type, CharUnits begin) {
- assert(type && "didn't provide type for typed data");
- addTypedData(type, begin, begin + getTypeStoreSize(CGM, type));
-}
-
-void SwiftAggLowering::addTypedData(llvm::Type *type,
- CharUnits begin, CharUnits end) {
- assert(type && "didn't provide type for typed data");
- assert(getTypeStoreSize(CGM, type) == end - begin);
-
- // Legalize vector types.
- if (auto vecTy = dyn_cast<llvm::VectorType>(type)) {
- SmallVector<llvm::Type*, 4> componentTys;
- legalizeVectorType(CGM, end - begin, vecTy, componentTys);
- assert(componentTys.size() >= 1);
-
- // Walk the initial components.
- for (size_t i = 0, e = componentTys.size(); i != e - 1; ++i) {
- llvm::Type *componentTy = componentTys[i];
- auto componentSize = getTypeStoreSize(CGM, componentTy);
- assert(componentSize < end - begin);
- addLegalTypedData(componentTy, begin, begin + componentSize);
- begin += componentSize;
- }
-
- return addLegalTypedData(componentTys.back(), begin, end);
- }
-
- // Legalize integer types.
- if (auto intTy = dyn_cast<llvm::IntegerType>(type)) {
- if (!isLegalIntegerType(CGM, intTy))
- return addOpaqueData(begin, end);
- }
-
- // All other types should be legal.
- return addLegalTypedData(type, begin, end);
-}
-
-void SwiftAggLowering::addLegalTypedData(llvm::Type *type,
- CharUnits begin, CharUnits end) {
- // Require the type to be naturally aligned.
- if (!begin.isZero() && !begin.isMultipleOf(getNaturalAlignment(CGM, type))) {
-
- // Try splitting vector types.
- if (auto vecTy = dyn_cast<llvm::VectorType>(type)) {
- auto split = splitLegalVectorType(CGM, end - begin, vecTy);
- auto eltTy = split.first;
- auto numElts = split.second;
-
- auto eltSize = (end - begin) / numElts;
- assert(eltSize == getTypeStoreSize(CGM, eltTy));
- for (size_t i = 0, e = numElts; i != e; ++i) {
- addLegalTypedData(eltTy, begin, begin + eltSize);
- begin += eltSize;
- }
- assert(begin == end);
- return;
- }
-
- return addOpaqueData(begin, end);
- }
-
- addEntry(type, begin, end);
-}
-
-void SwiftAggLowering::addEntry(llvm::Type *type,
- CharUnits begin, CharUnits end) {
- assert((!type ||
- (!isa<llvm::StructType>(type) && !isa<llvm::ArrayType>(type))) &&
- "cannot add aggregate-typed data");
- assert(!type || begin.isMultipleOf(getNaturalAlignment(CGM, type)));
-
- // Fast path: we can just add entries to the end.
- if (Entries.empty() || Entries.back().End <= begin) {
- Entries.push_back({begin, end, type});
- return;
- }
-
- // Find the first existing entry that ends after the start of the new data.
- // TODO: do a binary search if Entries is big enough for it to matter.
- size_t index = Entries.size() - 1;
- while (index != 0) {
- if (Entries[index - 1].End <= begin) break;
- --index;
- }
-
- // The entry ends after the start of the new data.
- // If the entry starts after the end of the new data, there's no conflict.
- if (Entries[index].Begin >= end) {
- // This insertion is potentially O(n), but the way we generally build
- // these layouts makes that unlikely to matter: we'd need a union of
- // several very large types.
- Entries.insert(Entries.begin() + index, {begin, end, type});
- return;
- }
-
- // Otherwise, the ranges overlap. The new range might also overlap
- // with later ranges.
-restartAfterSplit:
-
- // Simplest case: an exact overlap.
- if (Entries[index].Begin == begin && Entries[index].End == end) {
- // If the types match exactly, great.
- if (Entries[index].Type == type) return;
-
- // If either type is opaque, make the entry opaque and return.
- if (Entries[index].Type == nullptr) {
- return;
- } else if (type == nullptr) {
- Entries[index].Type = nullptr;
- return;
- }
-
- // If they disagree in an ABI-agnostic way, just resolve the conflict
- // arbitrarily.
- if (auto entryType = getCommonType(Entries[index].Type, type)) {
- Entries[index].Type = entryType;
- return;
- }
-
- // Otherwise, make the entry opaque.
- Entries[index].Type = nullptr;
- return;
- }
-
- // Okay, we have an overlapping conflict of some sort.
-
- // If we have a vector type, split it.
- if (auto vecTy = dyn_cast_or_null<llvm::VectorType>(type)) {
- auto eltTy = vecTy->getElementType();
- CharUnits eltSize = (end - begin) / vecTy->getNumElements();
- assert(eltSize == getTypeStoreSize(CGM, eltTy));
- for (unsigned i = 0, e = vecTy->getNumElements(); i != e; ++i) {
- addEntry(eltTy, begin, begin + eltSize);
- begin += eltSize;
- }
- assert(begin == end);
- return;
- }
-
- // If the entry is a vector type, split it and try again.
- if (Entries[index].Type && Entries[index].Type->isVectorTy()) {
- splitVectorEntry(index);
- goto restartAfterSplit;
- }
-
- // Okay, we have no choice but to make the existing entry opaque.
-
- Entries[index].Type = nullptr;
-
- // Stretch the start of the entry to the beginning of the range.
- if (begin < Entries[index].Begin) {
- Entries[index].Begin = begin;
- assert(index == 0 || begin >= Entries[index - 1].End);
- }
-
- // Stretch the end of the entry to the end of the range; but if we run
- // into the start of the next entry, just leave the range there and repeat.
- while (end > Entries[index].End) {
- assert(Entries[index].Type == nullptr);
-
- // If the range doesn't overlap the next entry, we're done.
- if (index == Entries.size() - 1 || end <= Entries[index + 1].Begin) {
- Entries[index].End = end;
- break;
- }
-
- // Otherwise, stretch to the start of the next entry.
- Entries[index].End = Entries[index + 1].Begin;
-
- // Continue with the next entry.
- index++;
-
- // This entry needs to be made opaque if it is not already.
- if (Entries[index].Type == nullptr)
- continue;
-
- // Split vector entries unless we completely subsume them.
- if (Entries[index].Type->isVectorTy() &&
- end < Entries[index].End) {
- splitVectorEntry(index);
- }
-
- // Make the entry opaque.
- Entries[index].Type = nullptr;
- }
-}
-
-/// Replace the entry of vector type at offset 'index' with a sequence
-/// of its component vectors.
-void SwiftAggLowering::splitVectorEntry(unsigned index) {
- auto vecTy = cast<llvm::VectorType>(Entries[index].Type);
- auto split = splitLegalVectorType(CGM, Entries[index].getWidth(), vecTy);
-
- auto eltTy = split.first;
- CharUnits eltSize = getTypeStoreSize(CGM, eltTy);
- auto numElts = split.second;
- Entries.insert(Entries.begin() + index + 1, numElts - 1, StorageEntry());
-
- CharUnits begin = Entries[index].Begin;
- for (unsigned i = 0; i != numElts; ++i) {
- Entries[index].Type = eltTy;
- Entries[index].Begin = begin;
- Entries[index].End = begin + eltSize;
- begin += eltSize;
- }
-}
-
-/// Given a power-of-two unit size, return the offset of the aligned unit
-/// of that size which contains the given offset.
-///
-/// In other words, round down to the nearest multiple of the unit size.
-static CharUnits getOffsetAtStartOfUnit(CharUnits offset, CharUnits unitSize) {
- assert(isPowerOf2(unitSize.getQuantity()));
- auto unitMask = ~(unitSize.getQuantity() - 1);
- return CharUnits::fromQuantity(offset.getQuantity() & unitMask);
-}
-
-static bool areBytesInSameUnit(CharUnits first, CharUnits second,
- CharUnits chunkSize) {
- return getOffsetAtStartOfUnit(first, chunkSize)
- == getOffsetAtStartOfUnit(second, chunkSize);
-}
-
-static bool isMergeableEntryType(llvm::Type *type) {
- // Opaquely-typed memory is always mergeable.
- if (type == nullptr) return true;
-
- // Pointers and integers are always mergeable. In theory we should not
- // merge pointers, but (1) it doesn't currently matter in practice because
- // the chunk size is never greater than the size of a pointer and (2)
- // Swift IRGen uses integer types for a lot of things that are "really"
- // just storing pointers (like Optional<SomePointer>). If we ever have a
- // target that would otherwise combine pointers, we should put some effort
- // into fixing those cases in Swift IRGen and then call out pointer types
- // here.
-
- // Floating-point and vector types should never be merged.
- // Most such types are too large and highly-aligned to ever trigger merging
- // in practice, but it's important for the rule to cover at least 'half'
- // and 'float', as well as things like small vectors of 'i1' or 'i8'.
- return (!type->isFloatingPointTy() && !type->isVectorTy());
-}
-
-bool SwiftAggLowering::shouldMergeEntries(const StorageEntry &first,
- const StorageEntry &second,
- CharUnits chunkSize) {
- // Only merge entries that overlap the same chunk. We test this first
- // despite being a bit more expensive because this is the condition that
- // tends to prevent merging.
- if (!areBytesInSameUnit(first.End - CharUnits::One(), second.Begin,
- chunkSize))
- return false;
-
- return (isMergeableEntryType(first.Type) &&
- isMergeableEntryType(second.Type));
-}
-
-void SwiftAggLowering::finish() {
- if (Entries.empty()) {
- Finished = true;
- return;
- }
-
- // We logically split the layout down into a series of chunks of this size,
- // which is generally the size of a pointer.
- const CharUnits chunkSize = getMaximumVoluntaryIntegerSize(CGM);
-
- // First pass: if two entries should be merged, make them both opaque
- // and stretch one to meet the next.
- // Also, remember if there are any opaque entries.
- bool hasOpaqueEntries = (Entries[0].Type == nullptr);
- for (size_t i = 1, e = Entries.size(); i != e; ++i) {
- if (shouldMergeEntries(Entries[i - 1], Entries[i], chunkSize)) {
- Entries[i - 1].Type = nullptr;
- Entries[i].Type = nullptr;
- Entries[i - 1].End = Entries[i].Begin;
- hasOpaqueEntries = true;
-
- } else if (Entries[i].Type == nullptr) {
- hasOpaqueEntries = true;
- }
- }
-
- // The rest of the algorithm leaves non-opaque entries alone, so if we
- // have no opaque entries, we're done.
- if (!hasOpaqueEntries) {
- Finished = true;
- return;
- }
-
- // Okay, move the entries to a temporary and rebuild Entries.
- auto orig = std::move(Entries);
- assert(Entries.empty());
-
- for (size_t i = 0, e = orig.size(); i != e; ++i) {
- // Just copy over non-opaque entries.
- if (orig[i].Type != nullptr) {
- Entries.push_back(orig[i]);
- continue;
- }
-
- // Scan forward to determine the full extent of the next opaque range.
- // We know from the first pass that only contiguous ranges will overlap
- // the same aligned chunk.
- auto begin = orig[i].Begin;
- auto end = orig[i].End;
- while (i + 1 != e &&
- orig[i + 1].Type == nullptr &&
- end == orig[i + 1].Begin) {
- end = orig[i + 1].End;
- i++;
- }
-
- // Add an entry per intersected chunk.
- do {
- // Find the smallest aligned storage unit in the maximal aligned
- // storage unit containing 'begin' that contains all the bytes in
- // the intersection between the range and this chunk.
- CharUnits localBegin = begin;
- CharUnits chunkBegin = getOffsetAtStartOfUnit(localBegin, chunkSize);
- CharUnits chunkEnd = chunkBegin + chunkSize;
- CharUnits localEnd = std::min(end, chunkEnd);
-
- // Just do a simple loop over ever-increasing unit sizes.
- CharUnits unitSize = CharUnits::One();
- CharUnits unitBegin, unitEnd;
- for (; ; unitSize *= 2) {
- assert(unitSize <= chunkSize);
- unitBegin = getOffsetAtStartOfUnit(localBegin, unitSize);
- unitEnd = unitBegin + unitSize;
- if (unitEnd >= localEnd) break;
- }
-
- // Add an entry for this unit.
- auto entryTy =
- llvm::IntegerType::get(CGM.getLLVMContext(),
- CGM.getContext().toBits(unitSize));
- Entries.push_back({unitBegin, unitEnd, entryTy});
-
- // The next chunk starts where this chunk left off.
- begin = localEnd;
- } while (begin != end);
- }
-
- // Okay, finally finished.
- Finished = true;
-}
-
-void SwiftAggLowering::enumerateComponents(EnumerationCallback callback) const {
- assert(Finished && "haven't yet finished lowering");
-
- for (auto &entry : Entries) {
- callback(entry.Begin, entry.End, entry.Type);
- }
-}
-
-std::pair<llvm::StructType*, llvm::Type*>
-SwiftAggLowering::getCoerceAndExpandTypes() const {
- assert(Finished && "haven't yet finished lowering");
-
- auto &ctx = CGM.getLLVMContext();
-
- if (Entries.empty()) {
- auto type = llvm::StructType::get(ctx);
- return { type, type };
- }
-
- SmallVector<llvm::Type*, 8> elts;
- CharUnits lastEnd = CharUnits::Zero();
- bool hasPadding = false;
- bool packed = false;
- for (auto &entry : Entries) {
- if (entry.Begin != lastEnd) {
- auto paddingSize = entry.Begin - lastEnd;
- assert(!paddingSize.isNegative());
-
- auto padding = llvm::ArrayType::get(llvm::Type::getInt8Ty(ctx),
- paddingSize.getQuantity());
- elts.push_back(padding);
- hasPadding = true;
- }
-
- if (!packed && !entry.Begin.isMultipleOf(
- CharUnits::fromQuantity(
- CGM.getDataLayout().getABITypeAlignment(entry.Type))))
- packed = true;
-
- elts.push_back(entry.Type);
-
- lastEnd = entry.Begin + getTypeAllocSize(CGM, entry.Type);
- assert(entry.End <= lastEnd);
- }
-
- // We don't need to adjust 'packed' to deal with possible tail padding
- // because we never do that kind of access through the coercion type.
- auto coercionType = llvm::StructType::get(ctx, elts, packed);
-
- llvm::Type *unpaddedType = coercionType;
- if (hasPadding) {
- elts.clear();
- for (auto &entry : Entries) {
- elts.push_back(entry.Type);
- }
- if (elts.size() == 1) {
- unpaddedType = elts[0];
- } else {
- unpaddedType = llvm::StructType::get(ctx, elts, /*packed*/ false);
- }
- } else if (Entries.size() == 1) {
- unpaddedType = Entries[0].Type;
- }
-
- return { coercionType, unpaddedType };
-}
-
-bool SwiftAggLowering::shouldPassIndirectly(bool asReturnValue) const {
- assert(Finished && "haven't yet finished lowering");
-
- // Empty types don't need to be passed indirectly.
- if (Entries.empty()) return false;
-
- // Avoid copying the array of types when there's just a single element.
- if (Entries.size() == 1) {
- return getSwiftABIInfo(CGM).shouldPassIndirectlyForSwift(
- Entries.back().Type,
- asReturnValue);
- }
-
- SmallVector<llvm::Type*, 8> componentTys;
- componentTys.reserve(Entries.size());
- for (auto &entry : Entries) {
- componentTys.push_back(entry.Type);
- }
- return getSwiftABIInfo(CGM).shouldPassIndirectlyForSwift(componentTys,
- asReturnValue);
-}
-
-bool swiftcall::shouldPassIndirectly(CodeGenModule &CGM,
- ArrayRef<llvm::Type*> componentTys,
- bool asReturnValue) {
- return getSwiftABIInfo(CGM).shouldPassIndirectlyForSwift(componentTys,
- asReturnValue);
-}
-
-CharUnits swiftcall::getMaximumVoluntaryIntegerSize(CodeGenModule &CGM) {
- // Currently always the size of an ordinary pointer.
- return CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().getTargetInfo().getPointerWidth(0));
-}
-
-CharUnits swiftcall::getNaturalAlignment(CodeGenModule &CGM, llvm::Type *type) {
- // For Swift's purposes, this is always just the store size of the type
- // rounded up to a power of 2.
- auto size = (unsigned long long) getTypeStoreSize(CGM, type).getQuantity();
- if (!isPowerOf2(size)) {
- size = 1ULL << (llvm::findLastSet(size, llvm::ZB_Undefined) + 1);
- }
- assert(size >= CGM.getDataLayout().getABITypeAlignment(type));
- return CharUnits::fromQuantity(size);
-}
-
-bool swiftcall::isLegalIntegerType(CodeGenModule &CGM,
- llvm::IntegerType *intTy) {
- auto size = intTy->getBitWidth();
- switch (size) {
- case 1:
- case 8:
- case 16:
- case 32:
- case 64:
- // Just assume that the above are always legal.
- return true;
-
- case 128:
- return CGM.getContext().getTargetInfo().hasInt128Type();
-
- default:
- return false;
- }
-}
-
-bool swiftcall::isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
- llvm::VectorType *vectorTy) {
- return isLegalVectorType(CGM, vectorSize, vectorTy->getElementType(),
- vectorTy->getNumElements());
-}
-
-bool swiftcall::isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
- llvm::Type *eltTy, unsigned numElts) {
- assert(numElts > 1 && "illegal vector length");
- return getSwiftABIInfo(CGM)
- .isLegalVectorTypeForSwift(vectorSize, eltTy, numElts);
-}
-
-std::pair<llvm::Type*, unsigned>
-swiftcall::splitLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
- llvm::VectorType *vectorTy) {
- auto numElts = vectorTy->getNumElements();
- auto eltTy = vectorTy->getElementType();
-
- // Try to split the vector type in half.
- if (numElts >= 4 && isPowerOf2(numElts)) {
- if (isLegalVectorType(CGM, vectorSize / 2, eltTy, numElts / 2))
- return {llvm::VectorType::get(eltTy, numElts / 2), 2};
- }
-
- return {eltTy, numElts};
-}
-
-void swiftcall::legalizeVectorType(CodeGenModule &CGM, CharUnits origVectorSize,
- llvm::VectorType *origVectorTy,
- llvm::SmallVectorImpl<llvm::Type*> &components) {
- // If it's already a legal vector type, use it.
- if (isLegalVectorType(CGM, origVectorSize, origVectorTy)) {
- components.push_back(origVectorTy);
- return;
- }
-
- // Try to split the vector into legal subvectors.
- auto numElts = origVectorTy->getNumElements();
- auto eltTy = origVectorTy->getElementType();
- assert(numElts != 1);
-
- // The largest size that we're still considering making subvectors of.
- // Always a power of 2.
- unsigned logCandidateNumElts = llvm::findLastSet(numElts, llvm::ZB_Undefined);
- unsigned candidateNumElts = 1U << logCandidateNumElts;
- assert(candidateNumElts <= numElts && candidateNumElts * 2 > numElts);
-
- // Minor optimization: don't check the legality of this exact size twice.
- if (candidateNumElts == numElts) {
- logCandidateNumElts--;
- candidateNumElts >>= 1;
- }
-
- CharUnits eltSize = (origVectorSize / numElts);
- CharUnits candidateSize = eltSize * candidateNumElts;
-
- // The sensibility of this algorithm relies on the fact that we never
- // have a legal non-power-of-2 vector size without having the power of 2
- // also be legal.
- while (logCandidateNumElts > 0) {
- assert(candidateNumElts == 1U << logCandidateNumElts);
- assert(candidateNumElts <= numElts);
- assert(candidateSize == eltSize * candidateNumElts);
-
- // Skip illegal vector sizes.
- if (!isLegalVectorType(CGM, candidateSize, eltTy, candidateNumElts)) {
- logCandidateNumElts--;
- candidateNumElts /= 2;
- candidateSize /= 2;
- continue;
- }
-
- // Add the right number of vectors of this size.
- auto numVecs = numElts >> logCandidateNumElts;
- components.append(numVecs, llvm::VectorType::get(eltTy, candidateNumElts));
- numElts -= (numVecs << logCandidateNumElts);
-
- if (numElts == 0) return;
-
- // It's possible that the number of elements remaining will be legal.
- // This can happen with e.g. <7 x float> when <3 x float> is legal.
- // This only needs to be separately checked if it's not a power of 2.
- if (numElts > 2 && !isPowerOf2(numElts) &&
- isLegalVectorType(CGM, eltSize * numElts, eltTy, numElts)) {
- components.push_back(llvm::VectorType::get(eltTy, numElts));
- return;
- }
-
- // Bring vecSize down to something no larger than numElts.
- do {
- logCandidateNumElts--;
- candidateNumElts /= 2;
- candidateSize /= 2;
- } while (candidateNumElts > numElts);
- }
-
- // Otherwise, just append a bunch of individual elements.
- components.append(numElts, eltTy);
-}
-
-bool swiftcall::mustPassRecordIndirectly(CodeGenModule &CGM,
- const RecordDecl *record) {
- // FIXME: should we not rely on the standard computation in Sema, just in
- // case we want to diverge from the platform ABI (e.g. on targets where
- // that uses the MSVC rule)?
- return !record->canPassInRegisters();
-}
-
-static ABIArgInfo classifyExpandedType(SwiftAggLowering &lowering,
- bool forReturn,
- CharUnits alignmentForIndirect) {
- if (lowering.empty()) {
- return ABIArgInfo::getIgnore();
- } else if (lowering.shouldPassIndirectly(forReturn)) {
- return ABIArgInfo::getIndirect(alignmentForIndirect, /*byval*/ false);
- } else {
- auto types = lowering.getCoerceAndExpandTypes();
- return ABIArgInfo::getCoerceAndExpand(types.first, types.second);
- }
-}
-
-static ABIArgInfo classifyType(CodeGenModule &CGM, CanQualType type,
- bool forReturn) {
- if (auto recordType = dyn_cast<RecordType>(type)) {
- auto record = recordType->getDecl();
- auto &layout = CGM.getContext().getASTRecordLayout(record);
-
- if (mustPassRecordIndirectly(CGM, record))
- return ABIArgInfo::getIndirect(layout.getAlignment(), /*byval*/ false);
-
- SwiftAggLowering lowering(CGM);
- lowering.addTypedData(recordType->getDecl(), CharUnits::Zero(), layout);
- lowering.finish();
-
- return classifyExpandedType(lowering, forReturn, layout.getAlignment());
- }
-
- // Just assume that all of our target ABIs can support returning at least
- // two integer or floating-point values.
- if (isa<ComplexType>(type)) {
- return (forReturn ? ABIArgInfo::getDirect() : ABIArgInfo::getExpand());
- }
-
- // Vector types may need to be legalized.
- if (isa<VectorType>(type)) {
- SwiftAggLowering lowering(CGM);
- lowering.addTypedData(type, CharUnits::Zero());
- lowering.finish();
-
- CharUnits alignment = CGM.getContext().getTypeAlignInChars(type);
- return classifyExpandedType(lowering, forReturn, alignment);
- }
-
- // Member pointer types need to be expanded, but it's a simple form of
- // expansion that 'Direct' can handle. Note that CanBeFlattened should be
- // true for this to work.
-
- // 'void' needs to be ignored.
- if (type->isVoidType()) {
- return ABIArgInfo::getIgnore();
- }
-
- // Everything else can be passed directly.
- return ABIArgInfo::getDirect();
-}
-
-ABIArgInfo swiftcall::classifyReturnType(CodeGenModule &CGM, CanQualType type) {
- return classifyType(CGM, type, /*forReturn*/ true);
-}
-
-ABIArgInfo swiftcall::classifyArgumentType(CodeGenModule &CGM,
- CanQualType type) {
- return classifyType(CGM, type, /*forReturn*/ false);
-}
-
-void swiftcall::computeABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) {
- auto &retInfo = FI.getReturnInfo();
- retInfo = classifyReturnType(CGM, FI.getReturnType());
-
- for (unsigned i = 0, e = FI.arg_size(); i != e; ++i) {
- auto &argInfo = FI.arg_begin()[i];
- argInfo.info = classifyArgumentType(CGM, argInfo.type);
- }
-}
-
-// Is swifterror lowered to a register by the target ABI.
-bool swiftcall::isSwiftErrorLoweredInRegister(CodeGenModule &CGM) {
- return getSwiftABIInfo(CGM).isSwiftErrorInRegister();
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp
deleted file mode 100644
index f54decf5106..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp
+++ /dev/null
@@ -1,9608 +0,0 @@
-//===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes wrap the information about a call or function
-// definition used to handle ABI compliancy.
-//
-//===----------------------------------------------------------------------===//
-
-#include "TargetInfo.h"
-#include "ABIInfo.h"
-#include "CGBlocks.h"
-#include "CGCXXABI.h"
-#include "CGValue.h"
-#include "CodeGenFunction.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/CodeGenOptions.h"
-#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/CodeGen/SwiftCallingConv.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Type.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm> // std::sort
-
-using namespace clang;
-using namespace CodeGen;
-
-// Helper for coercing an aggregate argument or return value into an integer
-// array of the same size (including padding) and alignment. This alternate
-// coercion happens only for the RenderScript ABI and can be removed after
-// runtimes that rely on it are no longer supported.
-//
-// RenderScript assumes that the size of the argument / return value in the IR
-// is the same as the size of the corresponding qualified type. This helper
-// coerces the aggregate type into an array of the same size (including
-// padding). This coercion is used in lieu of expansion of struct members or
-// other canonical coercions that return a coerced-type of larger size.
-//
-// Ty - The argument / return value type
-// Context - The associated ASTContext
-// LLVMContext - The associated LLVMContext
-static ABIArgInfo coerceToIntArray(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &LLVMContext) {
- // Alignment and Size are measured in bits.
- const uint64_t Size = Context.getTypeSize(Ty);
- const uint64_t Alignment = Context.getTypeAlign(Ty);
- llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment);
- const uint64_t NumElements = (Size + Alignment - 1) / Alignment;
- return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements));
-}
-
-static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
- llvm::Value *Array,
- llvm::Value *Value,
- unsigned FirstIndex,
- unsigned LastIndex) {
- // Alternatively, we could emit this as a loop in the source.
- for (unsigned I = FirstIndex; I <= LastIndex; ++I) {
- llvm::Value *Cell =
- Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I);
- Builder.CreateAlignedStore(Value, Cell, CharUnits::One());
- }
-}
-
-static bool isAggregateTypeForABI(QualType T) {
- return !CodeGenFunction::hasScalarEvaluationKind(T) ||
- T->isMemberFunctionPointerType();
-}
-
-ABIArgInfo
-ABIInfo::getNaturalAlignIndirect(QualType Ty, bool ByRef, bool Realign,
- llvm::Type *Padding) const {
- return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty),
- ByRef, Realign, Padding);
-}
-
-ABIArgInfo
-ABIInfo::getNaturalAlignIndirectInReg(QualType Ty, bool Realign) const {
- return ABIArgInfo::getIndirectInReg(getContext().getTypeAlignInChars(Ty),
- /*ByRef*/ false, Realign);
-}
-
-Address ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- return Address::invalid();
-}
-
-ABIInfo::~ABIInfo() {}
-
-/// Does the given lowering require more than the given number of
-/// registers when expanded?
-///
-/// This is intended to be the basis of a reasonable basic implementation
-/// of should{Pass,Return}IndirectlyForSwift.
-///
-/// For most targets, a limit of four total registers is reasonable; this
-/// limits the amount of code required in order to move around the value
-/// in case it wasn't produced immediately prior to the call by the caller
-/// (or wasn't produced in exactly the right registers) or isn't used
-/// immediately within the callee. But some targets may need to further
-/// limit the register count due to an inability to support that many
-/// return registers.
-static bool occupiesMoreThan(CodeGenTypes &cgt,
- ArrayRef<llvm::Type*> scalarTypes,
- unsigned maxAllRegisters) {
- unsigned intCount = 0, fpCount = 0;
- for (llvm::Type *type : scalarTypes) {
- if (type->isPointerTy()) {
- intCount++;
- } else if (auto intTy = dyn_cast<llvm::IntegerType>(type)) {
- auto ptrWidth = cgt.getTarget().getPointerWidth(0);
- intCount += (intTy->getBitWidth() + ptrWidth - 1) / ptrWidth;
- } else {
- assert(type->isVectorTy() || type->isFloatingPointTy());
- fpCount++;
- }
- }
-
- return (intCount + fpCount > maxAllRegisters);
-}
-
-bool SwiftABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize,
- llvm::Type *eltTy,
- unsigned numElts) const {
- // The default implementation of this assumes that the target guarantees
- // 128-bit SIMD support but nothing more.
- return (vectorSize.getQuantity() > 8 && vectorSize.getQuantity() <= 16);
-}
-
-static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT,
- CGCXXABI &CXXABI) {
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD) {
- if (!RT->getDecl()->canPassInRegisters())
- return CGCXXABI::RAA_Indirect;
- return CGCXXABI::RAA_Default;
- }
- return CXXABI.getRecordArgABI(RD);
-}
-
-static CGCXXABI::RecordArgABI getRecordArgABI(QualType T,
- CGCXXABI &CXXABI) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return CGCXXABI::RAA_Default;
- return getRecordArgABI(RT, CXXABI);
-}
-
-static bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,
- const ABIInfo &Info) {
- QualType Ty = FI.getReturnType();
-
- if (const auto *RT = Ty->getAs<RecordType>())
- if (!isa<CXXRecordDecl>(RT->getDecl()) &&
- !RT->getDecl()->canPassInRegisters()) {
- FI.getReturnInfo() = Info.getNaturalAlignIndirect(Ty);
- return true;
- }
-
- return CXXABI.classifyReturnType(FI);
-}
-
-/// Pass transparent unions as if they were the type of the first element. Sema
-/// should ensure that all elements of the union have the same "machine type".
-static QualType useFirstFieldIfTransparentUnion(QualType Ty) {
- if (const RecordType *UT = Ty->getAsUnionType()) {
- const RecordDecl *UD = UT->getDecl();
- if (UD->hasAttr<TransparentUnionAttr>()) {
- assert(!UD->field_empty() && "sema created an empty transparent union");
- return UD->field_begin()->getType();
- }
- }
- return Ty;
-}
-
-CGCXXABI &ABIInfo::getCXXABI() const {
- return CGT.getCXXABI();
-}
-
-ASTContext &ABIInfo::getContext() const {
- return CGT.getContext();
-}
-
-llvm::LLVMContext &ABIInfo::getVMContext() const {
- return CGT.getLLVMContext();
-}
-
-const llvm::DataLayout &ABIInfo::getDataLayout() const {
- return CGT.getDataLayout();
-}
-
-const TargetInfo &ABIInfo::getTarget() const {
- return CGT.getTarget();
-}
-
-const CodeGenOptions &ABIInfo::getCodeGenOpts() const {
- return CGT.getCodeGenOpts();
-}
-
-bool ABIInfo::isAndroid() const { return getTarget().getTriple().isAndroid(); }
-
-bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
- return false;
-}
-
-bool ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base,
- uint64_t Members) const {
- return false;
-}
-
-LLVM_DUMP_METHOD void ABIArgInfo::dump() const {
- raw_ostream &OS = llvm::errs();
- OS << "(ABIArgInfo Kind=";
- switch (TheKind) {
- case Direct:
- OS << "Direct Type=";
- if (llvm::Type *Ty = getCoerceToType())
- Ty->print(OS);
- else
- OS << "null";
- break;
- case Extend:
- OS << "Extend";
- break;
- case Ignore:
- OS << "Ignore";
- break;
- case InAlloca:
- OS << "InAlloca Offset=" << getInAllocaFieldIndex();
- break;
- case Indirect:
- OS << "Indirect Align=" << getIndirectAlign().getQuantity()
- << " ByVal=" << getIndirectByVal()
- << " Realign=" << getIndirectRealign();
- break;
- case Expand:
- OS << "Expand";
- break;
- case CoerceAndExpand:
- OS << "CoerceAndExpand Type=";
- getCoerceAndExpandType()->print(OS);
- break;
- }
- OS << ")\n";
-}
-
-// Dynamically round a pointer up to a multiple of the given alignment.
-static llvm::Value *emitRoundPointerUpToAlignment(CodeGenFunction &CGF,
- llvm::Value *Ptr,
- CharUnits Align) {
- llvm::Value *PtrAsInt = Ptr;
- // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align;
- PtrAsInt = CGF.Builder.CreatePtrToInt(PtrAsInt, CGF.IntPtrTy);
- PtrAsInt = CGF.Builder.CreateAdd(PtrAsInt,
- llvm::ConstantInt::get(CGF.IntPtrTy, Align.getQuantity() - 1));
- PtrAsInt = CGF.Builder.CreateAnd(PtrAsInt,
- llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity()));
- PtrAsInt = CGF.Builder.CreateIntToPtr(PtrAsInt,
- Ptr->getType(),
- Ptr->getName() + ".aligned");
- return PtrAsInt;
-}
-
-/// Emit va_arg for a platform using the common void* representation,
-/// where arguments are simply emitted in an array of slots on the stack.
-///
-/// This version implements the core direct-value passing rules.
-///
-/// \param SlotSize - The size and alignment of a stack slot.
-/// Each argument will be allocated to a multiple of this number of
-/// slots, and all the slots will be aligned to this value.
-/// \param AllowHigherAlign - The slot alignment is not a cap;
-/// an argument type with an alignment greater than the slot size
-/// will be emitted on a higher-alignment address, potentially
-/// leaving one or more empty slots behind as padding. If this
-/// is false, the returned address might be less-aligned than
-/// DirectAlign.
-static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF,
- Address VAListAddr,
- llvm::Type *DirectTy,
- CharUnits DirectSize,
- CharUnits DirectAlign,
- CharUnits SlotSize,
- bool AllowHigherAlign) {
- // Cast the element type to i8* if necessary. Some platforms define
- // va_list as a struct containing an i8* instead of just an i8*.
- if (VAListAddr.getElementType() != CGF.Int8PtrTy)
- VAListAddr = CGF.Builder.CreateElementBitCast(VAListAddr, CGF.Int8PtrTy);
-
- llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur");
-
- // If the CC aligns values higher than the slot size, do so if needed.
- Address Addr = Address::invalid();
- if (AllowHigherAlign && DirectAlign > SlotSize) {
- Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign),
- DirectAlign);
- } else {
- Addr = Address(Ptr, SlotSize);
- }
-
- // Advance the pointer past the argument, then store that back.
- CharUnits FullDirectSize = DirectSize.alignTo(SlotSize);
- llvm::Value *NextPtr =
- CGF.Builder.CreateConstInBoundsByteGEP(Addr.getPointer(), FullDirectSize,
- "argp.next");
- CGF.Builder.CreateStore(NextPtr, VAListAddr);
-
- // If the argument is smaller than a slot, and this is a big-endian
- // target, the argument will be right-adjusted in its slot.
- if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() &&
- !DirectTy->isStructTy()) {
- Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize);
- }
-
- Addr = CGF.Builder.CreateElementBitCast(Addr, DirectTy);
- return Addr;
-}
-
-/// Emit va_arg for a platform using the common void* representation,
-/// where arguments are simply emitted in an array of slots on the stack.
-///
-/// \param IsIndirect - Values of this type are passed indirectly.
-/// \param ValueInfo - The size and alignment of this type, generally
-/// computed with getContext().getTypeInfoInChars(ValueTy).
-/// \param SlotSizeAndAlign - The size and alignment of a stack slot.
-/// Each argument will be allocated to a multiple of this number of
-/// slots, and all the slots will be aligned to this value.
-/// \param AllowHigherAlign - The slot alignment is not a cap;
-/// an argument type with an alignment greater than the slot size
-/// will be emitted on a higher-alignment address, potentially
-/// leaving one or more empty slots behind as padding.
-static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType ValueTy, bool IsIndirect,
- std::pair<CharUnits, CharUnits> ValueInfo,
- CharUnits SlotSizeAndAlign,
- bool AllowHigherAlign) {
- // The size and alignment of the value that was passed directly.
- CharUnits DirectSize, DirectAlign;
- if (IsIndirect) {
- DirectSize = CGF.getPointerSize();
- DirectAlign = CGF.getPointerAlign();
- } else {
- DirectSize = ValueInfo.first;
- DirectAlign = ValueInfo.second;
- }
-
- // Cast the address we've calculated to the right type.
- llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy);
- if (IsIndirect)
- DirectTy = DirectTy->getPointerTo(0);
-
- Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy,
- DirectSize, DirectAlign,
- SlotSizeAndAlign,
- AllowHigherAlign);
-
- if (IsIndirect) {
- Addr = Address(CGF.Builder.CreateLoad(Addr), ValueInfo.second);
- }
-
- return Addr;
-
-}
-
-static Address emitMergePHI(CodeGenFunction &CGF,
- Address Addr1, llvm::BasicBlock *Block1,
- Address Addr2, llvm::BasicBlock *Block2,
- const llvm::Twine &Name = "") {
- assert(Addr1.getType() == Addr2.getType());
- llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name);
- PHI->addIncoming(Addr1.getPointer(), Block1);
- PHI->addIncoming(Addr2.getPointer(), Block2);
- CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment());
- return Address(PHI, Align);
-}
-
-TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; }
-
-// If someone can figure out a general rule for this, that would be great.
-// It's probably just doomed to be platform-dependent, though.
-unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
- // Verified for:
- // x86-64 FreeBSD, Linux, Darwin
- // x86-32 FreeBSD, Linux, Darwin
- // PowerPC Linux, Darwin
- // ARM Darwin (*not* EABI)
- // AArch64 Linux
- return 32;
-}
-
-bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,
- const FunctionNoProtoType *fnType) const {
- // The following conventions are known to require this to be false:
- // x86_stdcall
- // MIPS
- // For everything else, we just prefer false unless we opt out.
- return false;
-}
-
-void
-TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const {
- // This assumes the user is passing a library name like "rt" instead of a
- // filename like "librt.a/so", and that they don't care whether it's static or
- // dynamic.
- Opt = "-l";
- Opt += Lib;
-}
-
-unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const {
- // OpenCL kernels are called via an explicit runtime API with arguments
- // set with clSetKernelArg(), not as normal sub-functions.
- // Return SPIR_KERNEL by default as the kernel calling convention to
- // ensure the fingerprint is fixed such way that each OpenCL argument
- // gets one matching argument in the produced kernel function argument
- // list to enable feasible implementation of clSetKernelArg() with
- // aggregates etc. In case we would use the default C calling conv here,
- // clSetKernelArg() might break depending on the target-specific
- // conventions; different targets might split structs passed as values
- // to multiple function arguments etc.
- return llvm::CallingConv::SPIR_KERNEL;
-}
-
-llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
- llvm::PointerType *T, QualType QT) const {
- return llvm::ConstantPointerNull::get(T);
-}
-
-LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
- const VarDecl *D) const {
- assert(!CGM.getLangOpts().OpenCL &&
- !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
- "Address space agnostic languages only");
- return D ? D->getType().getAddressSpace() : LangAS::Default;
-}
-
-llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(
- CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr,
- LangAS DestAddr, llvm::Type *DestTy, bool isNonNull) const {
- // Since target may map different address spaces in AST to the same address
- // space, an address space conversion may end up as a bitcast.
- if (auto *C = dyn_cast<llvm::Constant>(Src))
- return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy);
- return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DestTy);
-}
-
-llvm::Constant *
-TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src,
- LangAS SrcAddr, LangAS DestAddr,
- llvm::Type *DestTy) const {
- // Since target may map different address spaces in AST to the same address
- // space, an address space conversion may end up as a bitcast.
- return llvm::ConstantExpr::getPointerCast(Src, DestTy);
-}
-
-llvm::SyncScope::ID
-TargetCodeGenInfo::getLLVMSyncScopeID(SyncScope S, llvm::LLVMContext &C) const {
- return C.getOrInsertSyncScopeID(""); /* default sync scope */
-}
-
-static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
-
-/// isEmptyField - Return true iff a the field is "empty", that is it
-/// is an unnamed bit-field or an (array of) empty record(s).
-static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
- bool AllowArrays) {
- if (FD->isUnnamedBitfield())
- return true;
-
- QualType FT = FD->getType();
-
- // Constant arrays of empty records count as empty, strip them off.
- // Constant arrays of zero length always count as empty.
- if (AllowArrays)
- while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
- if (AT->getSize() == 0)
- return true;
- FT = AT->getElementType();
- }
-
- const RecordType *RT = FT->getAs<RecordType>();
- if (!RT)
- return false;
-
- // C++ record fields are never empty, at least in the Itanium ABI.
- //
- // FIXME: We should use a predicate for whether this behavior is true in the
- // current ABI.
- if (isa<CXXRecordDecl>(RT->getDecl()))
- return false;
-
- return isEmptyRecord(Context, FT, AllowArrays);
-}
-
-/// isEmptyRecord - Return true iff a structure contains only empty
-/// fields. Note that a structure with a flexible array member is not
-/// considered empty.
-static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return false;
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return false;
-
- // If this is a C++ record, check the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- for (const auto &I : CXXRD->bases())
- if (!isEmptyRecord(Context, I.getType(), true))
- return false;
-
- for (const auto *I : RD->fields())
- if (!isEmptyField(Context, I, AllowArrays))
- return false;
- return true;
-}
-
-/// isSingleElementStruct - Determine if a structure is a "single
-/// element struct", i.e. it has exactly one non-empty field or
-/// exactly one field which is itself a single element
-/// struct. Structures with flexible array members are never
-/// considered single element structs.
-///
-/// \return The field declaration for the single non-empty field, if
-/// it exists.
-static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return nullptr;
-
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return nullptr;
-
- const Type *Found = nullptr;
-
- // If this is a C++ record, check the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (const auto &I : CXXRD->bases()) {
- // Ignore empty records.
- if (isEmptyRecord(Context, I.getType(), true))
- continue;
-
- // If we already found an element then this isn't a single-element struct.
- if (Found)
- return nullptr;
-
- // If this is non-empty and not a single element struct, the composite
- // cannot be a single element struct.
- Found = isSingleElementStruct(I.getType(), Context);
- if (!Found)
- return nullptr;
- }
- }
-
- // Check for single element.
- for (const auto *FD : RD->fields()) {
- QualType FT = FD->getType();
-
- // Ignore empty fields.
- if (isEmptyField(Context, FD, true))
- continue;
-
- // If we already found an element then this isn't a single-element
- // struct.
- if (Found)
- return nullptr;
-
- // Treat single element arrays as the element.
- while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
- if (AT->getSize().getZExtValue() != 1)
- break;
- FT = AT->getElementType();
- }
-
- if (!isAggregateTypeForABI(FT)) {
- Found = FT.getTypePtr();
- } else {
- Found = isSingleElementStruct(FT, Context);
- if (!Found)
- return nullptr;
- }
- }
-
- // We don't consider a struct a single-element struct if it has
- // padding beyond the element type.
- if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))
- return nullptr;
-
- return Found;
-}
-
-namespace {
-Address EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
- const ABIArgInfo &AI) {
- // This default implementation defers to the llvm backend's va_arg
- // instruction. It can handle only passing arguments directly
- // (typically only handled in the backend for primitive types), or
- // aggregates passed indirectly by pointer (NOTE: if the "byval"
- // flag has ABI impact in the callee, this implementation cannot
- // work.)
-
- // Only a few cases are covered here at the moment -- those needed
- // by the default abi.
- llvm::Value *Val;
-
- if (AI.isIndirect()) {
- assert(!AI.getPaddingType() &&
- "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
- assert(
- !AI.getIndirectRealign() &&
- "Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!");
-
- auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty);
- CharUnits TyAlignForABI = TyInfo.second;
-
- llvm::Type *BaseTy =
- llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty));
- llvm::Value *Addr =
- CGF.Builder.CreateVAArg(VAListAddr.getPointer(), BaseTy);
- return Address(Addr, TyAlignForABI);
- } else {
- assert((AI.isDirect() || AI.isExtend()) &&
- "Unexpected ArgInfo Kind in generic VAArg emitter!");
-
- assert(!AI.getInReg() &&
- "Unexpected InReg seen in arginfo in generic VAArg emitter!");
- assert(!AI.getPaddingType() &&
- "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
- assert(!AI.getDirectOffset() &&
- "Unexpected DirectOffset seen in arginfo in generic VAArg emitter!");
- assert(!AI.getCoerceToType() &&
- "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!");
-
- Address Temp = CGF.CreateMemTemp(Ty, "varet");
- Val = CGF.Builder.CreateVAArg(VAListAddr.getPointer(), CGF.ConvertType(Ty));
- CGF.Builder.CreateStore(Val, Temp);
- return Temp;
- }
-}
-
-/// DefaultABIInfo - The default implementation for ABI specific
-/// details. This implementation provides information which results in
-/// self-consistent and sensible LLVM IR generation, but does not
-/// conform to any particular ABI.
-class DefaultABIInfo : public ABIInfo {
-public:
- DefaultABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
-
- void computeInfo(CGFunctionInfo &FI) const override {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
- }
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override {
- return EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty));
- }
-};
-
-class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
-};
-
-ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- if (isAggregateTypeForABI(Ty)) {
- // Records with non-trivial destructors/copy-constructors should not be
- // passed by value.
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
- return getNaturalAlignIndirect(Ty);
- }
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
-}
-
-ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- if (isAggregateTypeForABI(RetTy))
- return getNaturalAlignIndirect(RetTy);
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
-}
-
-//===----------------------------------------------------------------------===//
-// WebAssembly ABI Implementation
-//
-// This is a very simple ABI that relies a lot on DefaultABIInfo.
-//===----------------------------------------------------------------------===//
-
-class WebAssemblyABIInfo final : public SwiftABIInfo {
- DefaultABIInfo defaultInfo;
-
-public:
- explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT)
- : SwiftABIInfo(CGT), defaultInfo(CGT) {}
-
-private:
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType Ty) const;
-
- // DefaultABIInfo's classifyReturnType and classifyArgumentType are
- // non-virtual, but computeInfo and EmitVAArg are virtual, so we
- // overload them.
- void computeInfo(CGFunctionInfo &FI) const override {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &Arg : FI.arguments())
- Arg.info = classifyArgumentType(Arg.type);
- }
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
-
- bool isSwiftErrorInRegister() const override {
- return false;
- }
-};
-
-class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
-public:
- explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(new WebAssemblyABIInfo(CGT)) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
- TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
- if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- llvm::AttrBuilder B;
- B.addAttribute("wasm-import-module", Attr->getImportModule());
- Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
- }
- if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- llvm::AttrBuilder B;
- B.addAttribute("wasm-import-name", Attr->getImportName());
- Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
- }
- }
-
- if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype())
- Fn->addFnAttr("no-prototype");
- }
- }
-};
-
-/// Classify argument of given type \p Ty.
-ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- if (isAggregateTypeForABI(Ty)) {
- // Records with non-trivial destructors/copy-constructors should not be
- // passed by value.
- if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
- // Lower single-element structs to just pass a regular value. TODO: We
- // could do reasonable-size multiple-element structs too, using getExpand(),
- // though watch out for things like bitfields.
- if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
- return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
- }
-
- // Otherwise just do the default thing.
- return defaultInfo.classifyArgumentType(Ty);
-}
-
-ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
- if (isAggregateTypeForABI(RetTy)) {
- // Records with non-trivial destructors/copy-constructors should not be
- // returned by value.
- if (!getRecordArgABI(RetTy, getCXXABI())) {
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), RetTy, true))
- return ABIArgInfo::getIgnore();
- // Lower single-element structs to just return a regular value. TODO: We
- // could do reasonable-size multiple-element structs too, using
- // ABIArgInfo::getDirect().
- if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
- return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
- }
- }
-
- // Otherwise just do the default thing.
- return defaultInfo.classifyReturnType(RetTy);
-}
-
-Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect=*/ false,
- getContext().getTypeInfoInChars(Ty),
- CharUnits::fromQuantity(4),
- /*AllowHigherAlign=*/ true);
-}
-
-//===----------------------------------------------------------------------===//
-// le32/PNaCl bitcode ABI Implementation
-//
-// This is a simplified version of the x86_32 ABI. Arguments and return values
-// are always passed on the stack.
-//===----------------------------------------------------------------------===//
-
-class PNaClABIInfo : public ABIInfo {
- public:
- PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
-
- void computeInfo(CGFunctionInfo &FI) const override;
- Address EmitVAArg(CodeGenFunction &CGF,
- Address VAListAddr, QualType Ty) const override;
-};
-
-class PNaClTargetCodeGenInfo : public TargetCodeGenInfo {
- public:
- PNaClTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(new PNaClABIInfo(CGT)) {}
-};
-
-void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
-
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
-}
-
-Address PNaClABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- // The PNaCL ABI is a bit odd, in that varargs don't use normal
- // function classification. Structs get passed directly for varargs
- // functions, through a rewriting transform in
- // pnacl-llvm/lib/Transforms/NaCl/ExpandVarArgs.cpp, which allows
- // this target to actually support a va_arg instructions with an
- // aggregate type, unlike other targets.
- return EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect());
-}
-
-/// Classify argument of given type \p Ty.
-ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty) const {
- if (isAggregateTypeForABI(Ty)) {
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
- return getNaturalAlignIndirect(Ty);
- } else if (const EnumType *EnumTy = Ty->getAs<EnumType>()) {
- // Treat an enum type as its underlying type.
- Ty = EnumTy->getDecl()->getIntegerType();
- } else if (Ty->isFloatingType()) {
- // Floating-point types don't go inreg.
- return ABIArgInfo::getDirect();
- }
-
- return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
-}
-
-ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- // In the PNaCl ABI we always return records/structures on the stack.
- if (isAggregateTypeForABI(RetTy))
- return getNaturalAlignIndirect(RetTy);
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
-}
-
-/// IsX86_MMXType - Return true if this is an MMX type.
-bool IsX86_MMXType(llvm::Type *IRType) {
- // Return true if the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>.
- return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 &&
- cast<llvm::VectorType>(IRType)->getElementType()->isIntegerTy() &&
- IRType->getScalarSizeInBits() != 64;
-}
-
-static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- StringRef Constraint,
- llvm::Type* Ty) {
- bool IsMMXCons = llvm::StringSwitch<bool>(Constraint)
- .Cases("y", "&y", "^Ym", true)
- .Default(false);
- if (IsMMXCons && Ty->isVectorTy()) {
- if (cast<llvm::VectorType>(Ty)->getBitWidth() != 64) {
- // Invalid MMX constraint
- return nullptr;
- }
-
- return llvm::Type::getX86_MMXTy(CGF.getLLVMContext());
- }
-
- // No operation needed
- return Ty;
-}
-
-/// Returns true if this type can be passed in SSE registers with the
-/// X86_VectorCall calling convention. Shared between x86_32 and x86_64.
-static bool isX86VectorTypeForVectorCall(ASTContext &Context, QualType Ty) {
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) {
- if (BT->getKind() == BuiltinType::LongDouble) {
- if (&Context.getTargetInfo().getLongDoubleFormat() ==
- &llvm::APFloat::x87DoubleExtended())
- return false;
- }
- return true;
- }
- } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
- // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX
- // registers specially.
- unsigned VecSize = Context.getTypeSize(VT);
- if (VecSize == 128 || VecSize == 256 || VecSize == 512)
- return true;
- }
- return false;
-}
-
-/// Returns true if this aggregate is small enough to be passed in SSE registers
-/// in the X86_VectorCall calling convention. Shared between x86_32 and x86_64.
-static bool isX86VectorCallAggregateSmallEnough(uint64_t NumMembers) {
- return NumMembers <= 4;
-}
-
-/// Returns a Homogeneous Vector Aggregate ABIArgInfo, used in X86.
-static ABIArgInfo getDirectX86Hva(llvm::Type* T = nullptr) {
- auto AI = ABIArgInfo::getDirect(T);
- AI.setInReg(true);
- AI.setCanBeFlattened(false);
- return AI;
-}
-
-//===----------------------------------------------------------------------===//
-// X86-32 ABI Implementation
-//===----------------------------------------------------------------------===//
-
-/// Similar to llvm::CCState, but for Clang.
-struct CCState {
- CCState(unsigned CC) : CC(CC), FreeRegs(0), FreeSSERegs(0) {}
-
- unsigned CC;
- unsigned FreeRegs;
- unsigned FreeSSERegs;
-};
-
-enum {
- // Vectorcall only allows the first 6 parameters to be passed in registers.
- VectorcallMaxParamNumAsReg = 6
-};
-
-/// X86_32ABIInfo - The X86-32 ABI information.
-class X86_32ABIInfo : public SwiftABIInfo {
- enum Class {
- Integer,
- Float
- };
-
- static const unsigned MinABIStackAlignInBytes = 4;
-
- bool IsDarwinVectorABI;
- bool IsRetSmallStructInRegABI;
- bool IsWin32StructABI;
- bool IsSoftFloatABI;
- bool IsMCUABI;
- unsigned DefaultNumRegisterParameters;
-
- static bool isRegisterSize(unsigned Size) {
- return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
- }
-
- bool isHomogeneousAggregateBaseType(QualType Ty) const override {
- // FIXME: Assumes vectorcall is in use.
- return isX86VectorTypeForVectorCall(getContext(), Ty);
- }
-
- bool isHomogeneousAggregateSmallEnough(const Type *Ty,
- uint64_t NumMembers) const override {
- // FIXME: Assumes vectorcall is in use.
- return isX86VectorCallAggregateSmallEnough(NumMembers);
- }
-
- bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const;
-
- /// getIndirectResult - Give a source type \arg Ty, return a suitable result
- /// such that the argument will be passed in memory.
- ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const;
-
- ABIArgInfo getIndirectReturnResult(QualType Ty, CCState &State) const;
-
- /// Return the alignment to use for the given type on the stack.
- unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
-
- Class classify(QualType Ty) const;
- ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
-
- /// Updates the number of available free registers, returns
- /// true if any registers were allocated.
- bool updateFreeRegs(QualType Ty, CCState &State) const;
-
- bool shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg,
- bool &NeedsPadding) const;
- bool shouldPrimitiveUseInReg(QualType Ty, CCState &State) const;
-
- bool canExpandIndirectArgument(QualType Ty) const;
-
- /// Rewrite the function info so that all memory arguments use
- /// inalloca.
- void rewriteWithInAlloca(CGFunctionInfo &FI) const;
-
- void addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
- CharUnits &StackOffset, ABIArgInfo &Info,
- QualType Type) const;
- void computeVectorCallArgs(CGFunctionInfo &FI, CCState &State,
- bool &UsedInAlloca) const;
-
-public:
-
- void computeInfo(CGFunctionInfo &FI) const override;
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI,
- bool RetSmallStructInRegABI, bool Win32StructABI,
- unsigned NumRegisterParameters, bool SoftFloatABI)
- : SwiftABIInfo(CGT), IsDarwinVectorABI(DarwinVectorABI),
- IsRetSmallStructInRegABI(RetSmallStructInRegABI),
- IsWin32StructABI(Win32StructABI),
- IsSoftFloatABI(SoftFloatABI),
- IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()),
- DefaultNumRegisterParameters(NumRegisterParameters) {}
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- // LLVM's x86-32 lowering currently only assigns up to three
- // integer registers and three fp registers. Oddly, it'll use up to
- // four vector registers for vectors, but those can overlap with the
- // scalar registers.
- return occupiesMoreThan(CGT, scalars, /*total*/ 3);
- }
-
- bool isSwiftErrorInRegister() const override {
- // x86-32 lowering does not support passing swifterror in a register.
- return false;
- }
-};
-
-class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI,
- bool RetSmallStructInRegABI, bool Win32StructABI,
- unsigned NumRegisterParameters, bool SoftFloatABI)
- : TargetCodeGenInfo(new X86_32ABIInfo(
- CGT, DarwinVectorABI, RetSmallStructInRegABI, Win32StructABI,
- NumRegisterParameters, SoftFloatABI)) {}
-
- static bool isStructReturnInRegABI(
- const llvm::Triple &Triple, const CodeGenOptions &Opts);
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
- // Darwin uses different dwarf register numbers for EH.
- if (CGM.getTarget().getTriple().isOSDarwin()) return 5;
- return 4;
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override;
-
- llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- StringRef Constraint,
- llvm::Type* Ty) const override {
- return X86AdjustInlineAsmType(CGF, Constraint, Ty);
- }
-
- void addReturnRegisterOutputs(CodeGenFunction &CGF, LValue ReturnValue,
- std::string &Constraints,
- std::vector<llvm::Type *> &ResultRegTypes,
- std::vector<llvm::Type *> &ResultTruncRegTypes,
- std::vector<LValue> &ResultRegDests,
- std::string &AsmString,
- unsigned NumOutputs) const override;
-
- llvm::Constant *
- getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override {
- unsigned Sig = (0xeb << 0) | // jmp rel8
- (0x06 << 8) | // .+0x08
- ('v' << 16) |
- ('2' << 24);
- return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
- }
-
- StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
- return "movl\t%ebp, %ebp"
- "\t\t// marker for objc_retainAutoreleaseReturnValue";
- }
-};
-
-}
-
-/// Rewrite input constraint references after adding some output constraints.
-/// In the case where there is one output and one input and we add one output,
-/// we need to replace all operand references greater than or equal to 1:
-/// mov $0, $1
-/// mov eax, $1
-/// The result will be:
-/// mov $0, $2
-/// mov eax, $2
-static void rewriteInputConstraintReferences(unsigned FirstIn,
- unsigned NumNewOuts,
- std::string &AsmString) {
- std::string Buf;
- llvm::raw_string_ostream OS(Buf);
- size_t Pos = 0;
- while (Pos < AsmString.size()) {
- size_t DollarStart = AsmString.find('$', Pos);
- if (DollarStart == std::string::npos)
- DollarStart = AsmString.size();
- size_t DollarEnd = AsmString.find_first_not_of('$', DollarStart);
- if (DollarEnd == std::string::npos)
- DollarEnd = AsmString.size();
- OS << StringRef(&AsmString[Pos], DollarEnd - Pos);
- Pos = DollarEnd;
- size_t NumDollars = DollarEnd - DollarStart;
- if (NumDollars % 2 != 0 && Pos < AsmString.size()) {
- // We have an operand reference.
- size_t DigitStart = Pos;
- size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart);
- if (DigitEnd == std::string::npos)
- DigitEnd = AsmString.size();
- StringRef OperandStr(&AsmString[DigitStart], DigitEnd - DigitStart);
- unsigned OperandIndex;
- if (!OperandStr.getAsInteger(10, OperandIndex)) {
- if (OperandIndex >= FirstIn)
- OperandIndex += NumNewOuts;
- OS << OperandIndex;
- } else {
- OS << OperandStr;
- }
- Pos = DigitEnd;
- }
- }
- AsmString = std::move(OS.str());
-}
-
-/// Add output constraints for EAX:EDX because they are return registers.
-void X86_32TargetCodeGenInfo::addReturnRegisterOutputs(
- CodeGenFunction &CGF, LValue ReturnSlot, std::string &Constraints,
- std::vector<llvm::Type *> &ResultRegTypes,
- std::vector<llvm::Type *> &ResultTruncRegTypes,
- std::vector<LValue> &ResultRegDests, std::string &AsmString,
- unsigned NumOutputs) const {
- uint64_t RetWidth = CGF.getContext().getTypeSize(ReturnSlot.getType());
-
- // Use the EAX constraint if the width is 32 or smaller and EAX:EDX if it is
- // larger.
- if (!Constraints.empty())
- Constraints += ',';
- if (RetWidth <= 32) {
- Constraints += "={eax}";
- ResultRegTypes.push_back(CGF.Int32Ty);
- } else {
- // Use the 'A' constraint for EAX:EDX.
- Constraints += "=A";
- ResultRegTypes.push_back(CGF.Int64Ty);
- }
-
- // Truncate EAX or EAX:EDX to an integer of the appropriate size.
- llvm::Type *CoerceTy = llvm::IntegerType::get(CGF.getLLVMContext(), RetWidth);
- ResultTruncRegTypes.push_back(CoerceTy);
-
- // Coerce the integer by bitcasting the return slot pointer.
- ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(),
- CoerceTy->getPointerTo()));
- ResultRegDests.push_back(ReturnSlot);
-
- rewriteInputConstraintReferences(NumOutputs, 1, AsmString);
-}
-
-/// shouldReturnTypeInRegister - Determine if the given type should be
-/// returned in a register (for the Darwin and MCU ABI).
-bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
- ASTContext &Context) const {
- uint64_t Size = Context.getTypeSize(Ty);
-
- // For i386, type must be register sized.
- // For the MCU ABI, it only needs to be <= 8-byte
- if ((IsMCUABI && Size > 64) || (!IsMCUABI && !isRegisterSize(Size)))
- return false;
-
- if (Ty->isVectorType()) {
- // 64- and 128- bit vectors inside structures are not returned in
- // registers.
- if (Size == 64 || Size == 128)
- return false;
-
- return true;
- }
-
- // If this is a builtin, pointer, enum, complex type, member pointer, or
- // member function pointer it is ok.
- if (Ty->getAs<BuiltinType>() || Ty->hasPointerRepresentation() ||
- Ty->isAnyComplexType() || Ty->isEnumeralType() ||
- Ty->isBlockPointerType() || Ty->isMemberPointerType())
- return true;
-
- // Arrays are treated like records.
- if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
- return shouldReturnTypeInRegister(AT->getElementType(), Context);
-
- // Otherwise, it must be a record type.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT) return false;
-
- // FIXME: Traverse bases here too.
-
- // Structure types are passed in register if all fields would be
- // passed in a register.
- for (const auto *FD : RT->getDecl()->fields()) {
- // Empty fields are ignored.
- if (isEmptyField(Context, FD, true))
- continue;
-
- // Check fields recursively.
- if (!shouldReturnTypeInRegister(FD->getType(), Context))
- return false;
- }
- return true;
-}
-
-static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
- // Treat complex types as the element type.
- if (const ComplexType *CTy = Ty->getAs<ComplexType>())
- Ty = CTy->getElementType();
-
- // Check for a type which we know has a simple scalar argument-passing
- // convention without any padding. (We're specifically looking for 32
- // and 64-bit integer and integer-equivalents, float, and double.)
- if (!Ty->getAs<BuiltinType>() && !Ty->hasPointerRepresentation() &&
- !Ty->isEnumeralType() && !Ty->isBlockPointerType())
- return false;
-
- uint64_t Size = Context.getTypeSize(Ty);
- return Size == 32 || Size == 64;
-}
-
-static bool addFieldSizes(ASTContext &Context, const RecordDecl *RD,
- uint64_t &Size) {
- for (const auto *FD : RD->fields()) {
- // Scalar arguments on the stack get 4 byte alignment on x86. If the
- // argument is smaller than 32-bits, expanding the struct will create
- // alignment padding.
- if (!is32Or64BitBasicType(FD->getType(), Context))
- return false;
-
- // FIXME: Reject bit-fields wholesale; there are two problems, we don't know
- // how to expand them yet, and the predicate for telling if a bitfield still
- // counts as "basic" is more complicated than what we were doing previously.
- if (FD->isBitField())
- return false;
-
- Size += Context.getTypeSize(FD->getType());
- }
- return true;
-}
-
-static bool addBaseAndFieldSizes(ASTContext &Context, const CXXRecordDecl *RD,
- uint64_t &Size) {
- // Don't do this if there are any non-empty bases.
- for (const CXXBaseSpecifier &Base : RD->bases()) {
- if (!addBaseAndFieldSizes(Context, Base.getType()->getAsCXXRecordDecl(),
- Size))
- return false;
- }
- if (!addFieldSizes(Context, RD, Size))
- return false;
- return true;
-}
-
-/// Test whether an argument type which is to be passed indirectly (on the
-/// stack) would have the equivalent layout if it was expanded into separate
-/// arguments. If so, we prefer to do the latter to avoid inhibiting
-/// optimizations.
-bool X86_32ABIInfo::canExpandIndirectArgument(QualType Ty) const {
- // We can only expand structure types.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT)
- return false;
- const RecordDecl *RD = RT->getDecl();
- uint64_t Size = 0;
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- if (!IsWin32StructABI) {
- // On non-Windows, we have to conservatively match our old bitcode
- // prototypes in order to be ABI-compatible at the bitcode level.
- if (!CXXRD->isCLike())
- return false;
- } else {
- // Don't do this for dynamic classes.
- if (CXXRD->isDynamicClass())
- return false;
- }
- if (!addBaseAndFieldSizes(getContext(), CXXRD, Size))
- return false;
- } else {
- if (!addFieldSizes(getContext(), RD, Size))
- return false;
- }
-
- // We can do this if there was no alignment padding.
- return Size == getContext().getTypeSize(Ty);
-}
-
-ABIArgInfo X86_32ABIInfo::getIndirectReturnResult(QualType RetTy, CCState &State) const {
- // If the return value is indirect, then the hidden argument is consuming one
- // integer register.
- if (State.FreeRegs) {
- --State.FreeRegs;
- if (!IsMCUABI)
- return getNaturalAlignIndirectInReg(RetTy);
- }
- return getNaturalAlignIndirect(RetTy, /*ByVal=*/false);
-}
-
-ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
- CCState &State) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
- if ((State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall) &&
- isHomogeneousAggregate(RetTy, Base, NumElts)) {
- // The LLVM struct type for such an aggregate should lower properly.
- return ABIArgInfo::getDirect();
- }
-
- if (const VectorType *VT = RetTy->getAs<VectorType>()) {
- // On Darwin, some vectors are returned in registers.
- if (IsDarwinVectorABI) {
- uint64_t Size = getContext().getTypeSize(RetTy);
-
- // 128-bit vectors are a special case; they are returned in
- // registers and we need to make sure to pick a type the LLVM
- // backend will like.
- if (Size == 128)
- return ABIArgInfo::getDirect(llvm::VectorType::get(
- llvm::Type::getInt64Ty(getVMContext()), 2));
-
- // Always return in register if it fits in a general purpose
- // register, or if it is 64 bits and has a single element.
- if ((Size == 8 || Size == 16 || Size == 32) ||
- (Size == 64 && VT->getNumElements() == 1))
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- Size));
-
- return getIndirectReturnResult(RetTy, State);
- }
-
- return ABIArgInfo::getDirect();
- }
-
- if (isAggregateTypeForABI(RetTy)) {
- if (const RecordType *RT = RetTy->getAs<RecordType>()) {
- // Structures with flexible arrays are always indirect.
- if (RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectReturnResult(RetTy, State);
- }
-
- // If specified, structs and unions are always indirect.
- if (!IsRetSmallStructInRegABI && !RetTy->isAnyComplexType())
- return getIndirectReturnResult(RetTy, State);
-
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), RetTy, true))
- return ABIArgInfo::getIgnore();
-
- // Small structures which are register sized are generally returned
- // in a register.
- if (shouldReturnTypeInRegister(RetTy, getContext())) {
- uint64_t Size = getContext().getTypeSize(RetTy);
-
- // As a special-case, if the struct is a "single-element" struct, and
- // the field is of type "float" or "double", return it in a
- // floating-point register. (MSVC does not apply this special case.)
- // We apply a similar transformation for pointer types to improve the
- // quality of the generated IR.
- if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
- if ((!IsWin32StructABI && SeltTy->isRealFloatingType())
- || SeltTy->hasPointerRepresentation())
- return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
-
- // FIXME: We should be able to narrow this integer in cases with dead
- // padding.
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size));
- }
-
- return getIndirectReturnResult(RetTy, State);
- }
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
-}
-
-static bool isSSEVectorType(ASTContext &Context, QualType Ty) {
- return Ty->getAs<VectorType>() && Context.getTypeSize(Ty) == 128;
-}
-
-static bool isRecordWithSSEVectorType(ASTContext &Context, QualType Ty) {
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT)
- return 0;
- const RecordDecl *RD = RT->getDecl();
-
- // If this is a C++ record, check the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- for (const auto &I : CXXRD->bases())
- if (!isRecordWithSSEVectorType(Context, I.getType()))
- return false;
-
- for (const auto *i : RD->fields()) {
- QualType FT = i->getType();
-
- if (isSSEVectorType(Context, FT))
- return true;
-
- if (isRecordWithSSEVectorType(Context, FT))
- return true;
- }
-
- return false;
-}
-
-unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty,
- unsigned Align) const {
- // Otherwise, if the alignment is less than or equal to the minimum ABI
- // alignment, just use the default; the backend will handle this.
- if (Align <= MinABIStackAlignInBytes)
- return 0; // Use default alignment.
-
- // On non-Darwin, the stack type alignment is always 4.
- if (!IsDarwinVectorABI) {
- // Set explicit alignment, since we may need to realign the top.
- return MinABIStackAlignInBytes;
- }
-
- // Otherwise, if the type contains an SSE vector type, the alignment is 16.
- if (Align >= 16 && (isSSEVectorType(getContext(), Ty) ||
- isRecordWithSSEVectorType(getContext(), Ty)))
- return 16;
-
- return MinABIStackAlignInBytes;
-}
-
-ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal,
- CCState &State) const {
- if (!ByVal) {
- if (State.FreeRegs) {
- --State.FreeRegs; // Non-byval indirects just use one pointer.
- if (!IsMCUABI)
- return getNaturalAlignIndirectInReg(Ty);
- }
- return getNaturalAlignIndirect(Ty, false);
- }
-
- // Compute the byval alignment.
- unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
- unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign);
- if (StackAlign == 0)
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true);
-
- // If the stack alignment is less than the type alignment, realign the
- // argument.
- bool Realign = TypeAlign > StackAlign;
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(StackAlign),
- /*ByVal=*/true, Realign);
-}
-
-X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
- const Type *T = isSingleElementStruct(Ty, getContext());
- if (!T)
- T = Ty.getTypePtr();
-
- if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
- BuiltinType::Kind K = BT->getKind();
- if (K == BuiltinType::Float || K == BuiltinType::Double)
- return Float;
- }
- return Integer;
-}
-
-bool X86_32ABIInfo::updateFreeRegs(QualType Ty, CCState &State) const {
- if (!IsSoftFloatABI) {
- Class C = classify(Ty);
- if (C == Float)
- return false;
- }
-
- unsigned Size = getContext().getTypeSize(Ty);
- unsigned SizeInRegs = (Size + 31) / 32;
-
- if (SizeInRegs == 0)
- return false;
-
- if (!IsMCUABI) {
- if (SizeInRegs > State.FreeRegs) {
- State.FreeRegs = 0;
- return false;
- }
- } else {
- // The MCU psABI allows passing parameters in-reg even if there are
- // earlier parameters that are passed on the stack. Also,
- // it does not allow passing >8-byte structs in-register,
- // even if there are 3 free registers available.
- if (SizeInRegs > State.FreeRegs || SizeInRegs > 2)
- return false;
- }
-
- State.FreeRegs -= SizeInRegs;
- return true;
-}
-
-bool X86_32ABIInfo::shouldAggregateUseDirect(QualType Ty, CCState &State,
- bool &InReg,
- bool &NeedsPadding) const {
- // On Windows, aggregates other than HFAs are never passed in registers, and
- // they do not consume register slots. Homogenous floating-point aggregates
- // (HFAs) have already been dealt with at this point.
- if (IsWin32StructABI && isAggregateTypeForABI(Ty))
- return false;
-
- NeedsPadding = false;
- InReg = !IsMCUABI;
-
- if (!updateFreeRegs(Ty, State))
- return false;
-
- if (IsMCUABI)
- return true;
-
- if (State.CC == llvm::CallingConv::X86_FastCall ||
- State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall) {
- if (getContext().getTypeSize(Ty) <= 32 && State.FreeRegs)
- NeedsPadding = true;
-
- return false;
- }
-
- return true;
-}
-
-bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
- if (!updateFreeRegs(Ty, State))
- return false;
-
- if (IsMCUABI)
- return false;
-
- if (State.CC == llvm::CallingConv::X86_FastCall ||
- State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall) {
- if (getContext().getTypeSize(Ty) > 32)
- return false;
-
- return (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() ||
- Ty->isReferenceType());
- }
-
- return true;
-}
-
-ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
- CCState &State) const {
- // FIXME: Set alignment on indirect arguments.
-
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- // Check with the C++ ABI first.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (RT) {
- CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
- if (RAA == CGCXXABI::RAA_Indirect) {
- return getIndirectResult(Ty, false, State);
- } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
- // The field index doesn't matter, we'll fix it up later.
- return ABIArgInfo::getInAlloca(/*FieldIndex=*/0);
- }
- }
-
- // Regcall uses the concept of a homogenous vector aggregate, similar
- // to other targets.
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
- if (State.CC == llvm::CallingConv::X86_RegCall &&
- isHomogeneousAggregate(Ty, Base, NumElts)) {
-
- if (State.FreeSSERegs >= NumElts) {
- State.FreeSSERegs -= NumElts;
- if (Ty->isBuiltinType() || Ty->isVectorType())
- return ABIArgInfo::getDirect();
- return ABIArgInfo::getExpand();
- }
- return getIndirectResult(Ty, /*ByVal=*/false, State);
- }
-
- if (isAggregateTypeForABI(Ty)) {
- // Structures with flexible arrays are always indirect.
- // FIXME: This should not be byval!
- if (RT && RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectResult(Ty, true, State);
-
- // Ignore empty structs/unions on non-Windows.
- if (!IsWin32StructABI && isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
-
- llvm::LLVMContext &LLVMContext = getVMContext();
- llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
- bool NeedsPadding = false;
- bool InReg;
- if (shouldAggregateUseDirect(Ty, State, InReg, NeedsPadding)) {
- unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
- SmallVector<llvm::Type*, 3> Elements(SizeInRegs, Int32);
- llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
- if (InReg)
- return ABIArgInfo::getDirectInReg(Result);
- else
- return ABIArgInfo::getDirect(Result);
- }
- llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : nullptr;
-
- // Expand small (<= 128-bit) record types when we know that the stack layout
- // of those arguments will match the struct. This is important because the
- // LLVM backend isn't smart enough to remove byval, which inhibits many
- // optimizations.
- // Don't do this for the MCU if there are still free integer registers
- // (see X86_64 ABI for full explanation).
- if (getContext().getTypeSize(Ty) <= 4 * 32 &&
- (!IsMCUABI || State.FreeRegs == 0) && canExpandIndirectArgument(Ty))
- return ABIArgInfo::getExpandWithPadding(
- State.CC == llvm::CallingConv::X86_FastCall ||
- State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall,
- PaddingType);
-
- return getIndirectResult(Ty, true, State);
- }
-
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- // On Darwin, some vectors are passed in memory, we handle this by passing
- // it as an i8/i16/i32/i64.
- if (IsDarwinVectorABI) {
- uint64_t Size = getContext().getTypeSize(Ty);
- if ((Size == 8 || Size == 16 || Size == 32) ||
- (Size == 64 && VT->getNumElements() == 1))
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- Size));
- }
-
- if (IsX86_MMXType(CGT.ConvertType(Ty)))
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64));
-
- return ABIArgInfo::getDirect();
- }
-
-
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- bool InReg = shouldPrimitiveUseInReg(Ty, State);
-
- if (Ty->isPromotableIntegerType()) {
- if (InReg)
- return ABIArgInfo::getExtendInReg(Ty);
- return ABIArgInfo::getExtend(Ty);
- }
-
- if (InReg)
- return ABIArgInfo::getDirectInReg();
- return ABIArgInfo::getDirect();
-}
-
-void X86_32ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, CCState &State,
- bool &UsedInAlloca) const {
- // Vectorcall x86 works subtly different than in x64, so the format is
- // a bit different than the x64 version. First, all vector types (not HVAs)
- // are assigned, with the first 6 ending up in the YMM0-5 or XMM0-5 registers.
- // This differs from the x64 implementation, where the first 6 by INDEX get
- // registers.
- // After that, integers AND HVAs are assigned Left to Right in the same pass.
- // Integers are passed as ECX/EDX if one is available (in order). HVAs will
- // first take up the remaining YMM/XMM registers. If insufficient registers
- // remain but an integer register (ECX/EDX) is available, it will be passed
- // in that, else, on the stack.
- for (auto &I : FI.arguments()) {
- // First pass do all the vector types.
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
- const QualType& Ty = I.type;
- if ((Ty->isVectorType() || Ty->isBuiltinType()) &&
- isHomogeneousAggregate(Ty, Base, NumElts)) {
- if (State.FreeSSERegs >= NumElts) {
- State.FreeSSERegs -= NumElts;
- I.info = ABIArgInfo::getDirect();
- } else {
- I.info = classifyArgumentType(Ty, State);
- }
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- }
- }
-
- for (auto &I : FI.arguments()) {
- // Second pass, do the rest!
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
- const QualType& Ty = I.type;
- bool IsHva = isHomogeneousAggregate(Ty, Base, NumElts);
-
- if (IsHva && !Ty->isVectorType() && !Ty->isBuiltinType()) {
- // Assign true HVAs (non vector/native FP types).
- if (State.FreeSSERegs >= NumElts) {
- State.FreeSSERegs -= NumElts;
- I.info = getDirectX86Hva();
- } else {
- I.info = getIndirectResult(Ty, /*ByVal=*/false, State);
- }
- } else if (!IsHva) {
- // Assign all Non-HVAs, so this will exclude Vector/FP args.
- I.info = classifyArgumentType(Ty, State);
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- }
- }
-}
-
-void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- CCState State(FI.getCallingConvention());
- if (IsMCUABI)
- State.FreeRegs = 3;
- else if (State.CC == llvm::CallingConv::X86_FastCall)
- State.FreeRegs = 2;
- else if (State.CC == llvm::CallingConv::X86_VectorCall) {
- State.FreeRegs = 2;
- State.FreeSSERegs = 6;
- } else if (FI.getHasRegParm())
- State.FreeRegs = FI.getRegParm();
- else if (State.CC == llvm::CallingConv::X86_RegCall) {
- State.FreeRegs = 5;
- State.FreeSSERegs = 8;
- } else
- State.FreeRegs = DefaultNumRegisterParameters;
-
- if (!::classifyReturnType(getCXXABI(), FI, *this)) {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State);
- } else if (FI.getReturnInfo().isIndirect()) {
- // The C++ ABI is not aware of register usage, so we have to check if the
- // return value was sret and put it in a register ourselves if appropriate.
- if (State.FreeRegs) {
- --State.FreeRegs; // The sret parameter consumes a register.
- if (!IsMCUABI)
- FI.getReturnInfo().setInReg(true);
- }
- }
-
- // The chain argument effectively gives us another free register.
- if (FI.isChainCall())
- ++State.FreeRegs;
-
- bool UsedInAlloca = false;
- if (State.CC == llvm::CallingConv::X86_VectorCall) {
- computeVectorCallArgs(FI, State, UsedInAlloca);
- } else {
- // If not vectorcall, revert to normal behavior.
- for (auto &I : FI.arguments()) {
- I.info = classifyArgumentType(I.type, State);
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- }
- }
-
- // If we needed to use inalloca for any argument, do a second pass and rewrite
- // all the memory arguments to use inalloca.
- if (UsedInAlloca)
- rewriteWithInAlloca(FI);
-}
-
-void
-X86_32ABIInfo::addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
- CharUnits &StackOffset, ABIArgInfo &Info,
- QualType Type) const {
- // Arguments are always 4-byte-aligned.
- CharUnits FieldAlign = CharUnits::fromQuantity(4);
-
- assert(StackOffset.isMultipleOf(FieldAlign) && "unaligned inalloca struct");
- Info = ABIArgInfo::getInAlloca(FrameFields.size());
- FrameFields.push_back(CGT.ConvertTypeForMem(Type));
- StackOffset += getContext().getTypeSizeInChars(Type);
-
- // Insert padding bytes to respect alignment.
- CharUnits FieldEnd = StackOffset;
- StackOffset = FieldEnd.alignTo(FieldAlign);
- if (StackOffset != FieldEnd) {
- CharUnits NumBytes = StackOffset - FieldEnd;
- llvm::Type *Ty = llvm::Type::getInt8Ty(getVMContext());
- Ty = llvm::ArrayType::get(Ty, NumBytes.getQuantity());
- FrameFields.push_back(Ty);
- }
-}
-
-static bool isArgInAlloca(const ABIArgInfo &Info) {
- // Leave ignored and inreg arguments alone.
- switch (Info.getKind()) {
- case ABIArgInfo::InAlloca:
- return true;
- case ABIArgInfo::Indirect:
- assert(Info.getIndirectByVal());
- return true;
- case ABIArgInfo::Ignore:
- return false;
- case ABIArgInfo::Direct:
- case ABIArgInfo::Extend:
- if (Info.getInReg())
- return false;
- return true;
- case ABIArgInfo::Expand:
- case ABIArgInfo::CoerceAndExpand:
- // These are aggregate types which are never passed in registers when
- // inalloca is involved.
- return true;
- }
- llvm_unreachable("invalid enum");
-}
-
-void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
- assert(IsWin32StructABI && "inalloca only supported on win32");
-
- // Build a packed struct type for all of the arguments in memory.
- SmallVector<llvm::Type *, 6> FrameFields;
-
- // The stack alignment is always 4.
- CharUnits StackAlign = CharUnits::fromQuantity(4);
-
- CharUnits StackOffset;
- CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end();
-
- // Put 'this' into the struct before 'sret', if necessary.
- bool IsThisCall =
- FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall;
- ABIArgInfo &Ret = FI.getReturnInfo();
- if (Ret.isIndirect() && Ret.isSRetAfterThis() && !IsThisCall &&
- isArgInAlloca(I->info)) {
- addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
- ++I;
- }
-
- // Put the sret parameter into the inalloca struct if it's in memory.
- if (Ret.isIndirect() && !Ret.getInReg()) {
- CanQualType PtrTy = getContext().getPointerType(FI.getReturnType());
- addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy);
- // On Windows, the hidden sret parameter is always returned in eax.
- Ret.setInAllocaSRet(IsWin32StructABI);
- }
-
- // Skip the 'this' parameter in ecx.
- if (IsThisCall)
- ++I;
-
- // Put arguments passed in memory into the struct.
- for (; I != E; ++I) {
- if (isArgInAlloca(I->info))
- addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
- }
-
- FI.setArgStruct(llvm::StructType::get(getVMContext(), FrameFields,
- /*isPacked=*/true),
- StackAlign);
-}
-
-Address X86_32ABIInfo::EmitVAArg(CodeGenFunction &CGF,
- Address VAListAddr, QualType Ty) const {
-
- auto TypeInfo = getContext().getTypeInfoInChars(Ty);
-
- // x86-32 changes the alignment of certain arguments on the stack.
- //
- // Just messing with TypeInfo like this works because we never pass
- // anything indirectly.
- TypeInfo.second = CharUnits::fromQuantity(
- getTypeStackAlignInBytes(Ty, TypeInfo.second.getQuantity()));
-
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false,
- TypeInfo, CharUnits::fromQuantity(4),
- /*AllowHigherAlign*/ true);
-}
-
-bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
- const llvm::Triple &Triple, const CodeGenOptions &Opts) {
- assert(Triple.getArch() == llvm::Triple::x86);
-
- switch (Opts.getStructReturnConvention()) {
- case CodeGenOptions::SRCK_Default:
- break;
- case CodeGenOptions::SRCK_OnStack: // -fpcc-struct-return
- return false;
- case CodeGenOptions::SRCK_InRegs: // -freg-struct-return
- return true;
- }
-
- if (Triple.isOSDarwin() || Triple.isOSIAMCU())
- return true;
-
- switch (Triple.getOS()) {
- case llvm::Triple::DragonFly:
- case llvm::Triple::FreeBSD:
- case llvm::Triple::OpenBSD:
- case llvm::Triple::Win32:
- return true;
- default:
- return false;
- }
-}
-
-void X86_32TargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
- if (GV->isDeclaration())
- return;
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- Fn->addFnAttr("stackrealign");
- }
- if (FD->hasAttr<AnyX86InterruptAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- Fn->setCallingConv(llvm::CallingConv::X86_INTR);
- }
- }
-}
-
-bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
- CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
-
- llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);
-
- // 0-7 are the eight integer registers; the order is different
- // on Darwin (for EH), but the range is the same.
- // 8 is %eip.
- AssignToArrayRange(Builder, Address, Four8, 0, 8);
-
- if (CGF.CGM.getTarget().getTriple().isOSDarwin()) {
- // 12-16 are st(0..4). Not sure why we stop at 4.
- // These have size 16, which is sizeof(long double) on
- // platforms with 8-byte alignment for that type.
- llvm::Value *Sixteen8 = llvm::ConstantInt::get(CGF.Int8Ty, 16);
- AssignToArrayRange(Builder, Address, Sixteen8, 12, 16);
-
- } else {
- // 9 is %eflags, which doesn't get a size on Darwin for some
- // reason.
- Builder.CreateAlignedStore(
- Four8, Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, Address, 9),
- CharUnits::One());
-
- // 11-16 are st(0..5). Not sure why we stop at 5.
- // These have size 12, which is sizeof(long double) on
- // platforms with 4-byte alignment for that type.
- llvm::Value *Twelve8 = llvm::ConstantInt::get(CGF.Int8Ty, 12);
- AssignToArrayRange(Builder, Address, Twelve8, 11, 16);
- }
-
- return false;
-}
-
-//===----------------------------------------------------------------------===//
-// X86-64 ABI Implementation
-//===----------------------------------------------------------------------===//
-
-
-namespace {
-/// The AVX ABI level for X86 targets.
-enum class X86AVXABILevel {
- None,
- AVX,
- AVX512
-};
-
-/// \p returns the size in bits of the largest (native) vector for \p AVXLevel.
-static unsigned getNativeVectorSizeForAVXABI(X86AVXABILevel AVXLevel) {
- switch (AVXLevel) {
- case X86AVXABILevel::AVX512:
- return 512;
- case X86AVXABILevel::AVX:
- return 256;
- case X86AVXABILevel::None:
- return 128;
- }
- llvm_unreachable("Unknown AVXLevel");
-}
-
-/// X86_64ABIInfo - The X86_64 ABI information.
-class X86_64ABIInfo : public SwiftABIInfo {
- enum Class {
- Integer = 0,
- SSE,
- SSEUp,
- X87,
- X87Up,
- ComplexX87,
- NoClass,
- Memory
- };
-
- /// merge - Implement the X86_64 ABI merging algorithm.
- ///
- /// Merge an accumulating classification \arg Accum with a field
- /// classification \arg Field.
- ///
- /// \param Accum - The accumulating classification. This should
- /// always be either NoClass or the result of a previous merge
- /// call. In addition, this should never be Memory (the caller
- /// should just return Memory for the aggregate).
- static Class merge(Class Accum, Class Field);
-
- /// postMerge - Implement the X86_64 ABI post merging algorithm.
- ///
- /// Post merger cleanup, reduces a malformed Hi and Lo pair to
- /// final MEMORY or SSE classes when necessary.
- ///
- /// \param AggregateSize - The size of the current aggregate in
- /// the classification process.
- ///
- /// \param Lo - The classification for the parts of the type
- /// residing in the low word of the containing object.
- ///
- /// \param Hi - The classification for the parts of the type
- /// residing in the higher words of the containing object.
- ///
- void postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const;
-
- /// classify - Determine the x86_64 register classes in which the
- /// given type T should be passed.
- ///
- /// \param Lo - The classification for the parts of the type
- /// residing in the low word of the containing object.
- ///
- /// \param Hi - The classification for the parts of the type
- /// residing in the high word of the containing object.
- ///
- /// \param OffsetBase - The bit offset of this type in the
- /// containing object. Some parameters are classified different
- /// depending on whether they straddle an eightbyte boundary.
- ///
- /// \param isNamedArg - Whether the argument in question is a "named"
- /// argument, as used in AMD64-ABI 3.5.7.
- ///
- /// If a word is unused its result will be NoClass; if a type should
- /// be passed in Memory then at least the classification of \arg Lo
- /// will be Memory.
- ///
- /// The \arg Lo class will be NoClass iff the argument is ignored.
- ///
- /// If the \arg Lo class is ComplexX87, then the \arg Hi class will
- /// also be ComplexX87.
- void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi,
- bool isNamedArg) const;
-
- llvm::Type *GetByteVectorType(QualType Ty) const;
- llvm::Type *GetSSETypeAtOffset(llvm::Type *IRType,
- unsigned IROffset, QualType SourceTy,
- unsigned SourceOffset) const;
- llvm::Type *GetINTEGERTypeAtOffset(llvm::Type *IRType,
- unsigned IROffset, QualType SourceTy,
- unsigned SourceOffset) const;
-
- /// getIndirectResult - Give a source type \arg Ty, return a suitable result
- /// such that the argument will be returned in memory.
- ABIArgInfo getIndirectReturnResult(QualType Ty) const;
-
- /// getIndirectResult - Give a source type \arg Ty, return a suitable result
- /// such that the argument will be passed in memory.
- ///
- /// \param freeIntRegs - The number of free integer registers remaining
- /// available.
- ABIArgInfo getIndirectResult(QualType Ty, unsigned freeIntRegs) const;
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
-
- ABIArgInfo classifyArgumentType(QualType Ty, unsigned freeIntRegs,
- unsigned &neededInt, unsigned &neededSSE,
- bool isNamedArg) const;
-
- ABIArgInfo classifyRegCallStructType(QualType Ty, unsigned &NeededInt,
- unsigned &NeededSSE) const;
-
- ABIArgInfo classifyRegCallStructTypeImpl(QualType Ty, unsigned &NeededInt,
- unsigned &NeededSSE) const;
-
- bool IsIllegalVectorType(QualType Ty) const;
-
- /// The 0.98 ABI revision clarified a lot of ambiguities,
- /// unfortunately in ways that were not always consistent with
- /// certain previous compilers. In particular, platforms which
- /// required strict binary compatibility with older versions of GCC
- /// may need to exempt themselves.
- bool honorsRevision0_98() const {
- return !getTarget().getTriple().isOSDarwin();
- }
-
- /// GCC classifies <1 x long long> as SSE but some platform ABIs choose to
- /// classify it as INTEGER (for compatibility with older clang compilers).
- bool classifyIntegerMMXAsSSE() const {
- // Clang <= 3.8 did not do this.
- if (getContext().getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver3_8)
- return false;
-
- const llvm::Triple &Triple = getTarget().getTriple();
- if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::PS4)
- return false;
- if (Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 10)
- return false;
- return true;
- }
-
- X86AVXABILevel AVXLevel;
- // Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on
- // 64-bit hardware.
- bool Has64BitPointers;
-
-public:
- X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) :
- SwiftABIInfo(CGT), AVXLevel(AVXLevel),
- Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) {
- }
-
- bool isPassedUsingAVXType(QualType type) const {
- unsigned neededInt, neededSSE;
- // The freeIntRegs argument doesn't matter here.
- ABIArgInfo info = classifyArgumentType(type, 0, neededInt, neededSSE,
- /*isNamedArg*/true);
- if (info.isDirect()) {
- llvm::Type *ty = info.getCoerceToType();
- if (llvm::VectorType *vectorTy = dyn_cast_or_null<llvm::VectorType>(ty))
- return (vectorTy->getBitWidth() > 128);
- }
- return false;
- }
-
- void computeInfo(CGFunctionInfo &FI) const override;
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
- Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- bool has64BitPointers() const {
- return Has64BitPointers;
- }
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return true;
- }
-};
-
-/// WinX86_64ABIInfo - The Windows X86_64 ABI information.
-class WinX86_64ABIInfo : public SwiftABIInfo {
-public:
- WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT)
- : SwiftABIInfo(CGT),
- IsMingw64(getTarget().getTriple().isWindowsGNUEnvironment()) {}
-
- void computeInfo(CGFunctionInfo &FI) const override;
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- bool isHomogeneousAggregateBaseType(QualType Ty) const override {
- // FIXME: Assumes vectorcall is in use.
- return isX86VectorTypeForVectorCall(getContext(), Ty);
- }
-
- bool isHomogeneousAggregateSmallEnough(const Type *Ty,
- uint64_t NumMembers) const override {
- // FIXME: Assumes vectorcall is in use.
- return isX86VectorCallAggregateSmallEnough(NumMembers);
- }
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type *> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
-
- bool isSwiftErrorInRegister() const override {
- return true;
- }
-
-private:
- ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs, bool IsReturnType,
- bool IsVectorCall, bool IsRegCall) const;
- ABIArgInfo reclassifyHvaArgType(QualType Ty, unsigned &FreeSSERegs,
- const ABIArgInfo &current) const;
- void computeVectorCallArgs(CGFunctionInfo &FI, unsigned FreeSSERegs,
- bool IsVectorCall, bool IsRegCall) const;
-
- bool IsMingw64;
-};
-
-class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel)
- : TargetCodeGenInfo(new X86_64ABIInfo(CGT, AVXLevel)) {}
-
- const X86_64ABIInfo &getABIInfo() const {
- return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
- }
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
- return 7;
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override {
- llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
-
- // 0-15 are the 16 integer registers.
- // 16 is %rip.
- AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16);
- return false;
- }
-
- llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- StringRef Constraint,
- llvm::Type* Ty) const override {
- return X86AdjustInlineAsmType(CGF, Constraint, Ty);
- }
-
- bool isNoProtoCallVariadic(const CallArgList &args,
- const FunctionNoProtoType *fnType) const override {
- // The default CC on x86-64 sets %al to the number of SSA
- // registers used, and GCC sets this when calling an unprototyped
- // function, so we override the default behavior. However, don't do
- // that when AVX types are involved: the ABI explicitly states it is
- // undefined, and it doesn't work in practice because of how the ABI
- // defines varargs anyway.
- if (fnType->getCallConv() == CC_C) {
- bool HasAVXType = false;
- for (CallArgList::const_iterator
- it = args.begin(), ie = args.end(); it != ie; ++it) {
- if (getABIInfo().isPassedUsingAVXType(it->Ty)) {
- HasAVXType = true;
- break;
- }
- }
-
- if (!HasAVXType)
- return true;
- }
-
- return TargetCodeGenInfo::isNoProtoCallVariadic(args, fnType);
- }
-
- llvm::Constant *
- getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override {
- unsigned Sig = (0xeb << 0) | // jmp rel8
- (0x06 << 8) | // .+0x08
- ('v' << 16) |
- ('2' << 24);
- return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
- }
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
- if (GV->isDeclaration())
- return;
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- Fn->addFnAttr("stackrealign");
- }
- if (FD->hasAttr<AnyX86InterruptAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- Fn->setCallingConv(llvm::CallingConv::X86_INTR);
- }
- }
- }
-};
-
-class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo {
-public:
- PS4TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel)
- : X86_64TargetCodeGenInfo(CGT, AVXLevel) {}
-
- void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const override {
- Opt = "\01";
- // If the argument contains a space, enclose it in quotes.
- if (Lib.find(" ") != StringRef::npos)
- Opt += "\"" + Lib.str() + "\"";
- else
- Opt += Lib;
- }
-};
-
-static std::string qualifyWindowsLibrary(llvm::StringRef Lib) {
- // If the argument does not end in .lib, automatically add the suffix.
- // If the argument contains a space, enclose it in quotes.
- // This matches the behavior of MSVC.
- bool Quote = (Lib.find(" ") != StringRef::npos);
- std::string ArgStr = Quote ? "\"" : "";
- ArgStr += Lib;
- if (!Lib.endswith_lower(".lib") && !Lib.endswith_lower(".a"))
- ArgStr += ".lib";
- ArgStr += Quote ? "\"" : "";
- return ArgStr;
-}
-
-class WinX86_32TargetCodeGenInfo : public X86_32TargetCodeGenInfo {
-public:
- WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
- bool DarwinVectorABI, bool RetSmallStructInRegABI, bool Win32StructABI,
- unsigned NumRegisterParameters)
- : X86_32TargetCodeGenInfo(CGT, DarwinVectorABI, RetSmallStructInRegABI,
- Win32StructABI, NumRegisterParameters, false) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
-
- void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const override {
- Opt = "/DEFAULTLIB:";
- Opt += qualifyWindowsLibrary(Lib);
- }
-
- void getDetectMismatchOption(llvm::StringRef Name,
- llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const override {
- Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
- }
-};
-
-static void addStackProbeTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) {
- if (llvm::Function *Fn = dyn_cast_or_null<llvm::Function>(GV)) {
-
- if (CGM.getCodeGenOpts().StackProbeSize != 4096)
- Fn->addFnAttr("stack-probe-size",
- llvm::utostr(CGM.getCodeGenOpts().StackProbeSize));
- if (CGM.getCodeGenOpts().NoStackArgProbe)
- Fn->addFnAttr("no-stack-arg-probe");
- }
-}
-
-void WinX86_32TargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
- X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
- if (GV->isDeclaration())
- return;
- addStackProbeTargetAttributes(D, GV, CGM);
-}
-
-class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
- X86AVXABILevel AVXLevel)
- : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
- return 7;
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override {
- llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
-
- // 0-15 are the 16 integer registers.
- // 16 is %rip.
- AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16);
- return false;
- }
-
- void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const override {
- Opt = "/DEFAULTLIB:";
- Opt += qualifyWindowsLibrary(Lib);
- }
-
- void getDetectMismatchOption(llvm::StringRef Name,
- llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const override {
- Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
- }
-};
-
-void WinX86_64TargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
- TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
- if (GV->isDeclaration())
- return;
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- Fn->addFnAttr("stackrealign");
- }
- if (FD->hasAttr<AnyX86InterruptAttr>()) {
- llvm::Function *Fn = cast<llvm::Function>(GV);
- Fn->setCallingConv(llvm::CallingConv::X86_INTR);
- }
- }
-
- addStackProbeTargetAttributes(D, GV, CGM);
-}
-}
-
-void X86_64ABIInfo::postMerge(unsigned AggregateSize, Class &Lo,
- Class &Hi) const {
- // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
- //
- // (a) If one of the classes is Memory, the whole argument is passed in
- // memory.
- //
- // (b) If X87UP is not preceded by X87, the whole argument is passed in
- // memory.
- //
- // (c) If the size of the aggregate exceeds two eightbytes and the first
- // eightbyte isn't SSE or any other eightbyte isn't SSEUP, the whole
- // argument is passed in memory. NOTE: This is necessary to keep the
- // ABI working for processors that don't support the __m256 type.
- //
- // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.
- //
- // Some of these are enforced by the merging logic. Others can arise
- // only with unions; for example:
- // union { _Complex double; unsigned; }
- //
- // Note that clauses (b) and (c) were added in 0.98.
- //
- if (Hi == Memory)
- Lo = Memory;
- if (Hi == X87Up && Lo != X87 && honorsRevision0_98())
- Lo = Memory;
- if (AggregateSize > 128 && (Lo != SSE || Hi != SSEUp))
- Lo = Memory;
- if (Hi == SSEUp && Lo != SSE)
- Hi = SSE;
-}
-
-X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) {
- // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
- // classified recursively so that always two fields are
- // considered. The resulting class is calculated according to
- // the classes of the fields in the eightbyte:
- //
- // (a) If both classes are equal, this is the resulting class.
- //
- // (b) If one of the classes is NO_CLASS, the resulting class is
- // the other class.
- //
- // (c) If one of the classes is MEMORY, the result is the MEMORY
- // class.
- //
- // (d) If one of the classes is INTEGER, the result is the
- // INTEGER.
- //
- // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class,
- // MEMORY is used as class.
- //
- // (f) Otherwise class SSE is used.
-
- // Accum should never be memory (we should have returned) or
- // ComplexX87 (because this cannot be passed in a structure).
- assert((Accum != Memory && Accum != ComplexX87) &&
- "Invalid accumulated classification during merge.");
- if (Accum == Field || Field == NoClass)
- return Accum;
- if (Field == Memory)
- return Memory;
- if (Accum == NoClass)
- return Field;
- if (Accum == Integer || Field == Integer)
- return Integer;
- if (Field == X87 || Field == X87Up || Field == ComplexX87 ||
- Accum == X87 || Accum == X87Up)
- return Memory;
- return SSE;
-}
-
-void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
- Class &Lo, Class &Hi, bool isNamedArg) const {
- // FIXME: This code can be simplified by introducing a simple value class for
- // Class pairs with appropriate constructor methods for the various
- // situations.
-
- // FIXME: Some of the split computations are wrong; unaligned vectors
- // shouldn't be passed in registers for example, so there is no chance they
- // can straddle an eightbyte. Verify & simplify.
-
- Lo = Hi = NoClass;
-
- Class &Current = OffsetBase < 64 ? Lo : Hi;
- Current = Memory;
-
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- BuiltinType::Kind k = BT->getKind();
-
- if (k == BuiltinType::Void) {
- Current = NoClass;
- } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) {
- Lo = Integer;
- Hi = Integer;
- } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
- Current = Integer;
- } else if (k == BuiltinType::Float || k == BuiltinType::Double) {
- Current = SSE;
- } else if (k == BuiltinType::LongDouble) {
- const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
- if (LDF == &llvm::APFloat::IEEEquad()) {
- Lo = SSE;
- Hi = SSEUp;
- } else if (LDF == &llvm::APFloat::x87DoubleExtended()) {
- Lo = X87;
- Hi = X87Up;
- } else if (LDF == &llvm::APFloat::IEEEdouble()) {
- Current = SSE;
- } else
- llvm_unreachable("unexpected long double representation!");
- }
- // FIXME: _Decimal32 and _Decimal64 are SSE.
- // FIXME: _float128 and _Decimal128 are (SSE, SSEUp).
- return;
- }
-
- if (const EnumType *ET = Ty->getAs<EnumType>()) {
- // Classify the underlying integer type.
- classify(ET->getDecl()->getIntegerType(), OffsetBase, Lo, Hi, isNamedArg);
- return;
- }
-
- if (Ty->hasPointerRepresentation()) {
- Current = Integer;
- return;
- }
-
- if (Ty->isMemberPointerType()) {
- if (Ty->isMemberFunctionPointerType()) {
- if (Has64BitPointers) {
- // If Has64BitPointers, this is an {i64, i64}, so classify both
- // Lo and Hi now.
- Lo = Hi = Integer;
- } else {
- // Otherwise, with 32-bit pointers, this is an {i32, i32}. If that
- // straddles an eightbyte boundary, Hi should be classified as well.
- uint64_t EB_FuncPtr = (OffsetBase) / 64;
- uint64_t EB_ThisAdj = (OffsetBase + 64 - 1) / 64;
- if (EB_FuncPtr != EB_ThisAdj) {
- Lo = Hi = Integer;
- } else {
- Current = Integer;
- }
- }
- } else {
- Current = Integer;
- }
- return;
- }
-
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- uint64_t Size = getContext().getTypeSize(VT);
- if (Size == 1 || Size == 8 || Size == 16 || Size == 32) {
- // gcc passes the following as integer:
- // 4 bytes - <4 x char>, <2 x short>, <1 x int>, <1 x float>
- // 2 bytes - <2 x char>, <1 x short>
- // 1 byte - <1 x char>
- Current = Integer;
-
- // If this type crosses an eightbyte boundary, it should be
- // split.
- uint64_t EB_Lo = (OffsetBase) / 64;
- uint64_t EB_Hi = (OffsetBase + Size - 1) / 64;
- if (EB_Lo != EB_Hi)
- Hi = Lo;
- } else if (Size == 64) {
- QualType ElementType = VT->getElementType();
-
- // gcc passes <1 x double> in memory. :(
- if (ElementType->isSpecificBuiltinType(BuiltinType::Double))
- return;
-
- // gcc passes <1 x long long> as SSE but clang used to unconditionally
- // pass them as integer. For platforms where clang is the de facto
- // platform compiler, we must continue to use integer.
- if (!classifyIntegerMMXAsSSE() &&
- (ElementType->isSpecificBuiltinType(BuiltinType::LongLong) ||
- ElementType->isSpecificBuiltinType(BuiltinType::ULongLong) ||
- ElementType->isSpecificBuiltinType(BuiltinType::Long) ||
- ElementType->isSpecificBuiltinType(BuiltinType::ULong)))
- Current = Integer;
- else
- Current = SSE;
-
- // If this type crosses an eightbyte boundary, it should be
- // split.
- if (OffsetBase && OffsetBase != 64)
- Hi = Lo;
- } else if (Size == 128 ||
- (isNamedArg && Size <= getNativeVectorSizeForAVXABI(AVXLevel))) {
- // Arguments of 256-bits are split into four eightbyte chunks. The
- // least significant one belongs to class SSE and all the others to class
- // SSEUP. The original Lo and Hi design considers that types can't be
- // greater than 128-bits, so a 64-bit split in Hi and Lo makes sense.
- // This design isn't correct for 256-bits, but since there're no cases
- // where the upper parts would need to be inspected, avoid adding
- // complexity and just consider Hi to match the 64-256 part.
- //
- // Note that per 3.5.7 of AMD64-ABI, 256-bit args are only passed in
- // registers if they are "named", i.e. not part of the "..." of a
- // variadic function.
- //
- // Similarly, per 3.2.3. of the AVX512 draft, 512-bits ("named") args are
- // split into eight eightbyte chunks, one SSE and seven SSEUP.
- Lo = SSE;
- Hi = SSEUp;
- }
- return;
- }
-
- if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
- QualType ET = getContext().getCanonicalType(CT->getElementType());
-
- uint64_t Size = getContext().getTypeSize(Ty);
- if (ET->isIntegralOrEnumerationType()) {
- if (Size <= 64)
- Current = Integer;
- else if (Size <= 128)
- Lo = Hi = Integer;
- } else if (ET == getContext().FloatTy) {
- Current = SSE;
- } else if (ET == getContext().DoubleTy) {
- Lo = Hi = SSE;
- } else if (ET == getContext().LongDoubleTy) {
- const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
- if (LDF == &llvm::APFloat::IEEEquad())
- Current = Memory;
- else if (LDF == &llvm::APFloat::x87DoubleExtended())
- Current = ComplexX87;
- else if (LDF == &llvm::APFloat::IEEEdouble())
- Lo = Hi = SSE;
- else
- llvm_unreachable("unexpected long double representation!");
- }
-
- // If this complex type crosses an eightbyte boundary then it
- // should be split.
- uint64_t EB_Real = (OffsetBase) / 64;
- uint64_t EB_Imag = (OffsetBase + getContext().getTypeSize(ET)) / 64;
- if (Hi == NoClass && EB_Real != EB_Imag)
- Hi = Lo;
-
- return;
- }
-
- if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
- // Arrays are treated like structures.
-
- uint64_t Size = getContext().getTypeSize(Ty);
-
- // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
- // than eight eightbytes, ..., it has class MEMORY.
- if (Size > 512)
- return;
-
- // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
- // fields, it has class MEMORY.
- //
- // Only need to check alignment of array base.
- if (OffsetBase % getContext().getTypeAlign(AT->getElementType()))
- return;
-
- // Otherwise implement simplified merge. We could be smarter about
- // this, but it isn't worth it and would be harder to verify.
- Current = NoClass;
- uint64_t EltSize = getContext().getTypeSize(AT->getElementType());
- uint64_t ArraySize = AT->getSize().getZExtValue();
-
- // The only case a 256-bit wide vector could be used is when the array
- // contains a single 256-bit element. Since Lo and Hi logic isn't extended
- // to work for sizes wider than 128, early check and fallback to memory.
- //
- if (Size > 128 &&
- (Size != EltSize || Size > getNativeVectorSizeForAVXABI(AVXLevel)))
- return;
-
- for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
- Class FieldLo, FieldHi;
- classify(AT->getElementType(), Offset, FieldLo, FieldHi, isNamedArg);
- Lo = merge(Lo, FieldLo);
- Hi = merge(Hi, FieldHi);
- if (Lo == Memory || Hi == Memory)
- break;
- }
-
- postMerge(Size, Lo, Hi);
- assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
- return;
- }
-
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- uint64_t Size = getContext().getTypeSize(Ty);
-
- // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
- // than eight eightbytes, ..., it has class MEMORY.
- if (Size > 512)
- return;
-
- // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
- // copy constructor or a non-trivial destructor, it is passed by invisible
- // reference.
- if (getRecordArgABI(RT, getCXXABI()))
- return;
-
- const RecordDecl *RD = RT->getDecl();
-
- // Assume variable sized types are passed in memory.
- if (RD->hasFlexibleArrayMember())
- return;
-
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
-
- // Reset Lo class, this will be recomputed.
- Current = NoClass;
-
- // If this is a C++ record, classify the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (const auto &I : CXXRD->bases()) {
- assert(!I.isVirtual() && !I.getType()->isDependentType() &&
- "Unexpected base class!");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
- // Classify this field.
- //
- // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a
- // single eightbyte, each is classified separately. Each eightbyte gets
- // initialized to class NO_CLASS.
- Class FieldLo, FieldHi;
- uint64_t Offset =
- OffsetBase + getContext().toBits(Layout.getBaseClassOffset(Base));
- classify(I.getType(), Offset, FieldLo, FieldHi, isNamedArg);
- Lo = merge(Lo, FieldLo);
- Hi = merge(Hi, FieldHi);
- if (Lo == Memory || Hi == Memory) {
- postMerge(Size, Lo, Hi);
- return;
- }
- }
- }
-
- // Classify the fields one at a time, merging the results.
- unsigned idx = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i, ++idx) {
- uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
- bool BitField = i->isBitField();
-
- // Ignore padding bit-fields.
- if (BitField && i->isUnnamedBitfield())
- continue;
-
- // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger than
- // four eightbytes, or it contains unaligned fields, it has class MEMORY.
- //
- // The only case a 256-bit wide vector could be used is when the struct
- // contains a single 256-bit element. Since Lo and Hi logic isn't extended
- // to work for sizes wider than 128, early check and fallback to memory.
- //
- if (Size > 128 && (Size != getContext().getTypeSize(i->getType()) ||
- Size > getNativeVectorSizeForAVXABI(AVXLevel))) {
- Lo = Memory;
- postMerge(Size, Lo, Hi);
- return;
- }
- // Note, skip this test for bit-fields, see below.
- if (!BitField && Offset % getContext().getTypeAlign(i->getType())) {
- Lo = Memory;
- postMerge(Size, Lo, Hi);
- return;
- }
-
- // Classify this field.
- //
- // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate
- // exceeds a single eightbyte, each is classified
- // separately. Each eightbyte gets initialized to class
- // NO_CLASS.
- Class FieldLo, FieldHi;
-
- // Bit-fields require special handling, they do not force the
- // structure to be passed in memory even if unaligned, and
- // therefore they can straddle an eightbyte.
- if (BitField) {
- assert(!i->isUnnamedBitfield());
- uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
- uint64_t Size = i->getBitWidthValue(getContext());
-
- uint64_t EB_Lo = Offset / 64;
- uint64_t EB_Hi = (Offset + Size - 1) / 64;
-
- if (EB_Lo) {
- assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes.");
- FieldLo = NoClass;
- FieldHi = Integer;
- } else {
- FieldLo = Integer;
- FieldHi = EB_Hi ? Integer : NoClass;
- }
- } else
- classify(i->getType(), Offset, FieldLo, FieldHi, isNamedArg);
- Lo = merge(Lo, FieldLo);
- Hi = merge(Hi, FieldHi);
- if (Lo == Memory || Hi == Memory)
- break;
- }
-
- postMerge(Size, Lo, Hi);
- }
-}
-
-ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
- // If this is a scalar LLVM value then assume LLVM will pass it in the right
- // place naturally.
- if (!isAggregateTypeForABI(Ty)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
- }
-
- return getNaturalAlignIndirect(Ty);
-}
-
-bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
- if (const VectorType *VecTy = Ty->getAs<VectorType>()) {
- uint64_t Size = getContext().getTypeSize(VecTy);
- unsigned LargestVector = getNativeVectorSizeForAVXABI(AVXLevel);
- if (Size <= 64 || Size > LargestVector)
- return true;
- }
-
- return false;
-}
-
-ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
- unsigned freeIntRegs) const {
- // If this is a scalar LLVM value then assume LLVM will pass it in the right
- // place naturally.
- //
- // This assumption is optimistic, as there could be free registers available
- // when we need to pass this argument in memory, and LLVM could try to pass
- // the argument in the free register. This does not seem to happen currently,
- // but this code would be much safer if we could mark the argument with
- // 'onstack'. See PR12193.
- if (!isAggregateTypeForABI(Ty) && !IsIllegalVectorType(Ty)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
- }
-
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
- // Compute the byval alignment. We specify the alignment of the byval in all
- // cases so that the mid-level optimizer knows the alignment of the byval.
- unsigned Align = std::max(getContext().getTypeAlign(Ty) / 8, 8U);
-
- // Attempt to avoid passing indirect results using byval when possible. This
- // is important for good codegen.
- //
- // We do this by coercing the value into a scalar type which the backend can
- // handle naturally (i.e., without using byval).
- //
- // For simplicity, we currently only do this when we have exhausted all of the
- // free integer registers. Doing this when there are free integer registers
- // would require more care, as we would have to ensure that the coerced value
- // did not claim the unused register. That would require either reording the
- // arguments to the function (so that any subsequent inreg values came first),
- // or only doing this optimization when there were no following arguments that
- // might be inreg.
- //
- // We currently expect it to be rare (particularly in well written code) for
- // arguments to be passed on the stack when there are still free integer
- // registers available (this would typically imply large structs being passed
- // by value), so this seems like a fair tradeoff for now.
- //
- // We can revisit this if the backend grows support for 'onstack' parameter
- // attributes. See PR12193.
- if (freeIntRegs == 0) {
- uint64_t Size = getContext().getTypeSize(Ty);
-
- // If this type fits in an eightbyte, coerce it into the matching integral
- // type, which will end up on the stack (with alignment 8).
- if (Align == 8 && Size <= 64)
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- Size));
- }
-
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(Align));
-}
-
-/// The ABI specifies that a value should be passed in a full vector XMM/YMM
-/// register. Pick an LLVM IR type that will be passed as a vector register.
-llvm::Type *X86_64ABIInfo::GetByteVectorType(QualType Ty) const {
- // Wrapper structs/arrays that only contain vectors are passed just like
- // vectors; strip them off if present.
- if (const Type *InnerTy = isSingleElementStruct(Ty, getContext()))
- Ty = QualType(InnerTy, 0);
-
- llvm::Type *IRType = CGT.ConvertType(Ty);
- if (isa<llvm::VectorType>(IRType) ||
- IRType->getTypeID() == llvm::Type::FP128TyID)
- return IRType;
-
- // We couldn't find the preferred IR vector type for 'Ty'.
- uint64_t Size = getContext().getTypeSize(Ty);
- assert((Size == 128 || Size == 256 || Size == 512) && "Invalid type found!");
-
- // Return a LLVM IR vector type based on the size of 'Ty'.
- return llvm::VectorType::get(llvm::Type::getDoubleTy(getVMContext()),
- Size / 64);
-}
-
-/// BitsContainNoUserData - Return true if the specified [start,end) bit range
-/// is known to either be off the end of the specified type or being in
-/// alignment padding. The user type specified is known to be at most 128 bits
-/// in size, and have passed through X86_64ABIInfo::classify with a successful
-/// classification that put one of the two halves in the INTEGER class.
-///
-/// It is conservatively correct to return false.
-static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
- unsigned EndBit, ASTContext &Context) {
- // If the bytes being queried are off the end of the type, there is no user
- // data hiding here. This handles analysis of builtins, vectors and other
- // types that don't contain interesting padding.
- unsigned TySize = (unsigned)Context.getTypeSize(Ty);
- if (TySize <= StartBit)
- return true;
-
- if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
- unsigned EltSize = (unsigned)Context.getTypeSize(AT->getElementType());
- unsigned NumElts = (unsigned)AT->getSize().getZExtValue();
-
- // Check each element to see if the element overlaps with the queried range.
- for (unsigned i = 0; i != NumElts; ++i) {
- // If the element is after the span we care about, then we're done..
- unsigned EltOffset = i*EltSize;
- if (EltOffset >= EndBit) break;
-
- unsigned EltStart = EltOffset < StartBit ? StartBit-EltOffset :0;
- if (!BitsContainNoUserData(AT->getElementType(), EltStart,
- EndBit-EltOffset, Context))
- return false;
- }
- // If it overlaps no elements, then it is safe to process as padding.
- return true;
- }
-
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- // If this is a C++ record, check the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (const auto &I : CXXRD->bases()) {
- assert(!I.isVirtual() && !I.getType()->isDependentType() &&
- "Unexpected base class!");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
- // If the base is after the span we care about, ignore it.
- unsigned BaseOffset = Context.toBits(Layout.getBaseClassOffset(Base));
- if (BaseOffset >= EndBit) continue;
-
- unsigned BaseStart = BaseOffset < StartBit ? StartBit-BaseOffset :0;
- if (!BitsContainNoUserData(I.getType(), BaseStart,
- EndBit-BaseOffset, Context))
- return false;
- }
- }
-
- // Verify that no field has data that overlaps the region of interest. Yes
- // this could be sped up a lot by being smarter about queried fields,
- // however we're only looking at structs up to 16 bytes, so we don't care
- // much.
- unsigned idx = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i, ++idx) {
- unsigned FieldOffset = (unsigned)Layout.getFieldOffset(idx);
-
- // If we found a field after the region we care about, then we're done.
- if (FieldOffset >= EndBit) break;
-
- unsigned FieldStart = FieldOffset < StartBit ? StartBit-FieldOffset :0;
- if (!BitsContainNoUserData(i->getType(), FieldStart, EndBit-FieldOffset,
- Context))
- return false;
- }
-
- // If nothing in this record overlapped the area of interest, then we're
- // clean.
- return true;
- }
-
- return false;
-}
-
-/// ContainsFloatAtOffset - Return true if the specified LLVM IR type has a
-/// float member at the specified offset. For example, {int,{float}} has a
-/// float at offset 4. It is conservatively correct for this routine to return
-/// false.
-static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset,
- const llvm::DataLayout &TD) {
- // Base case if we find a float.
- if (IROffset == 0 && IRType->isFloatTy())
- return true;
-
- // If this is a struct, recurse into the field at the specified offset.
- if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
- const llvm::StructLayout *SL = TD.getStructLayout(STy);
- unsigned Elt = SL->getElementContainingOffset(IROffset);
- IROffset -= SL->getElementOffset(Elt);
- return ContainsFloatAtOffset(STy->getElementType(Elt), IROffset, TD);
- }
-
- // If this is an array, recurse into the field at the specified offset.
- if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
- llvm::Type *EltTy = ATy->getElementType();
- unsigned EltSize = TD.getTypeAllocSize(EltTy);
- IROffset -= IROffset/EltSize*EltSize;
- return ContainsFloatAtOffset(EltTy, IROffset, TD);
- }
-
- return false;
-}
-
-
-/// GetSSETypeAtOffset - Return a type that will be passed by the backend in the
-/// low 8 bytes of an XMM register, corresponding to the SSE class.
-llvm::Type *X86_64ABIInfo::
-GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
- QualType SourceTy, unsigned SourceOffset) const {
- // The only three choices we have are either double, <2 x float>, or float. We
- // pass as float if the last 4 bytes is just padding. This happens for
- // structs that contain 3 floats.
- if (BitsContainNoUserData(SourceTy, SourceOffset*8+32,
- SourceOffset*8+64, getContext()))
- return llvm::Type::getFloatTy(getVMContext());
-
- // We want to pass as <2 x float> if the LLVM IR type contains a float at
- // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the
- // case.
- if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) &&
- ContainsFloatAtOffset(IRType, IROffset+4, getDataLayout()))
- return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2);
-
- return llvm::Type::getDoubleTy(getVMContext());
-}
-
-
-/// GetINTEGERTypeAtOffset - The ABI specifies that a value should be passed in
-/// an 8-byte GPR. This means that we either have a scalar or we are talking
-/// about the high or low part of an up-to-16-byte struct. This routine picks
-/// the best LLVM IR type to represent this, which may be i64 or may be anything
-/// else that the backend will pass in a GPR that works better (e.g. i8, %foo*,
-/// etc).
-///
-/// PrefType is an LLVM IR type that corresponds to (part of) the IR type for
-/// the source type. IROffset is an offset in bytes into the LLVM IR type that
-/// the 8-byte value references. PrefType may be null.
-///
-/// SourceTy is the source-level type for the entire argument. SourceOffset is
-/// an offset into this that we're processing (which is always either 0 or 8).
-///
-llvm::Type *X86_64ABIInfo::
-GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
- QualType SourceTy, unsigned SourceOffset) const {
- // If we're dealing with an un-offset LLVM IR type, then it means that we're
- // returning an 8-byte unit starting with it. See if we can safely use it.
- if (IROffset == 0) {
- // Pointers and int64's always fill the 8-byte unit.
- if ((isa<llvm::PointerType>(IRType) && Has64BitPointers) ||
- IRType->isIntegerTy(64))
- return IRType;
-
- // If we have a 1/2/4-byte integer, we can use it only if the rest of the
- // goodness in the source type is just tail padding. This is allowed to
- // kick in for struct {double,int} on the int, but not on
- // struct{double,int,int} because we wouldn't return the second int. We
- // have to do this analysis on the source type because we can't depend on
- // unions being lowered a specific way etc.
- if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) ||
- IRType->isIntegerTy(32) ||
- (isa<llvm::PointerType>(IRType) && !Has64BitPointers)) {
- unsigned BitWidth = isa<llvm::PointerType>(IRType) ? 32 :
- cast<llvm::IntegerType>(IRType)->getBitWidth();
-
- if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth,
- SourceOffset*8+64, getContext()))
- return IRType;
- }
- }
-
- if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
- // If this is a struct, recurse into the field at the specified offset.
- const llvm::StructLayout *SL = getDataLayout().getStructLayout(STy);
- if (IROffset < SL->getSizeInBytes()) {
- unsigned FieldIdx = SL->getElementContainingOffset(IROffset);
- IROffset -= SL->getElementOffset(FieldIdx);
-
- return GetINTEGERTypeAtOffset(STy->getElementType(FieldIdx), IROffset,
- SourceTy, SourceOffset);
- }
- }
-
- if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
- llvm::Type *EltTy = ATy->getElementType();
- unsigned EltSize = getDataLayout().getTypeAllocSize(EltTy);
- unsigned EltOffset = IROffset/EltSize*EltSize;
- return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy,
- SourceOffset);
- }
-
- // Okay, we don't have any better idea of what to pass, so we pass this in an
- // integer register that isn't too big to fit the rest of the struct.
- unsigned TySizeInBytes =
- (unsigned)getContext().getTypeSizeInChars(SourceTy).getQuantity();
-
- assert(TySizeInBytes != SourceOffset && "Empty field?");
-
- // It is always safe to classify this as an integer type up to i64 that
- // isn't larger than the structure.
- return llvm::IntegerType::get(getVMContext(),
- std::min(TySizeInBytes-SourceOffset, 8U)*8);
-}
-
-
-/// GetX86_64ByValArgumentPair - Given a high and low type that can ideally
-/// be used as elements of a two register pair to pass or return, return a
-/// first class aggregate to represent them. For example, if the low part of
-/// a by-value argument should be passed as i32* and the high part as float,
-/// return {i32*, float}.
-static llvm::Type *
-GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
- const llvm::DataLayout &TD) {
- // In order to correctly satisfy the ABI, we need to the high part to start
- // at offset 8. If the high and low parts we inferred are both 4-byte types
- // (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have
- // the second element at offset 8. Check for this:
- unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo);
- unsigned HiAlign = TD.getABITypeAlignment(Hi);
- unsigned HiStart = llvm::alignTo(LoSize, HiAlign);
- assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!");
-
- // To handle this, we have to increase the size of the low part so that the
- // second element will start at an 8 byte offset. We can't increase the size
- // of the second element because it might make us access off the end of the
- // struct.
- if (HiStart != 8) {
- // There are usually two sorts of types the ABI generation code can produce
- // for the low part of a pair that aren't 8 bytes in size: float or
- // i8/i16/i32. This can also include pointers when they are 32-bit (X32 and
- // NaCl).
- // Promote these to a larger type.
- if (Lo->isFloatTy())
- Lo = llvm::Type::getDoubleTy(Lo->getContext());
- else {
- assert((Lo->isIntegerTy() || Lo->isPointerTy())
- && "Invalid/unknown lo type");
- Lo = llvm::Type::getInt64Ty(Lo->getContext());
- }
- }
-
- llvm::StructType *Result = llvm::StructType::get(Lo, Hi);
-
- // Verify that the second element is at an 8-byte offset.
- assert(TD.getStructLayout(Result)->getElementOffset(1) == 8 &&
- "Invalid x86-64 argument pair!");
- return Result;
-}
-
-ABIArgInfo X86_64ABIInfo::
-classifyReturnType(QualType RetTy) const {
- // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
- // classification algorithm.
- X86_64ABIInfo::Class Lo, Hi;
- classify(RetTy, 0, Lo, Hi, /*isNamedArg*/ true);
-
- // Check some invariants.
- assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
- assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
-
- llvm::Type *ResType = nullptr;
- switch (Lo) {
- case NoClass:
- if (Hi == NoClass)
- return ABIArgInfo::getIgnore();
- // If the low part is just padding, it takes no register, leave ResType
- // null.
- assert((Hi == SSE || Hi == Integer || Hi == X87Up) &&
- "Unknown missing lo part");
- break;
-
- case SSEUp:
- case X87Up:
- llvm_unreachable("Invalid classification for lo word.");
-
- // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
- // hidden argument.
- case Memory:
- return getIndirectReturnResult(RetTy);
-
- // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
- // available register of the sequence %rax, %rdx is used.
- case Integer:
- ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0);
-
- // If we have a sign or zero extended integer, make sure to return Extend
- // so that the parameter gets the right LLVM IR attributes.
- if (Hi == NoClass && isa<llvm::IntegerType>(ResType)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- if (RetTy->isIntegralOrEnumerationType() &&
- RetTy->isPromotableIntegerType())
- return ABIArgInfo::getExtend(RetTy);
- }
- break;
-
- // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
- // available SSE register of the sequence %xmm0, %xmm1 is used.
- case SSE:
- ResType = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0);
- break;
-
- // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
- // returned on the X87 stack in %st0 as 80-bit x87 number.
- case X87:
- ResType = llvm::Type::getX86_FP80Ty(getVMContext());
- break;
-
- // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real
- // part of the value is returned in %st0 and the imaginary part in
- // %st1.
- case ComplexX87:
- assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
- ResType = llvm::StructType::get(llvm::Type::getX86_FP80Ty(getVMContext()),
- llvm::Type::getX86_FP80Ty(getVMContext()));
- break;
- }
-
- llvm::Type *HighPart = nullptr;
- switch (Hi) {
- // Memory was handled previously and X87 should
- // never occur as a hi class.
- case Memory:
- case X87:
- llvm_unreachable("Invalid classification for hi word.");
-
- case ComplexX87: // Previously handled.
- case NoClass:
- break;
-
- case Integer:
- HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8);
- if (Lo == NoClass) // Return HighPart at offset 8 in memory.
- return ABIArgInfo::getDirect(HighPart, 8);
- break;
- case SSE:
- HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8);
- if (Lo == NoClass) // Return HighPart at offset 8 in memory.
- return ABIArgInfo::getDirect(HighPart, 8);
- break;
-
- // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
- // is passed in the next available eightbyte chunk if the last used
- // vector register.
- //
- // SSEUP should always be preceded by SSE, just widen.
- case SSEUp:
- assert(Lo == SSE && "Unexpected SSEUp classification.");
- ResType = GetByteVectorType(RetTy);
- break;
-
- // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
- // returned together with the previous X87 value in %st0.
- case X87Up:
- // If X87Up is preceded by X87, we don't need to do
- // anything. However, in some cases with unions it may not be
- // preceded by X87. In such situations we follow gcc and pass the
- // extra bits in an SSE reg.
- if (Lo != X87) {
- HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8);
- if (Lo == NoClass) // Return HighPart at offset 8 in memory.
- return ABIArgInfo::getDirect(HighPart, 8);
- }
- break;
- }
-
- // If a high part was specified, merge it together with the low part. It is
- // known to pass in the high eightbyte of the result. We do this by forming a
- // first class struct aggregate with the high and low part: {low, high}
- if (HighPart)
- ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout());
-
- return ABIArgInfo::getDirect(ResType);
-}
-
-ABIArgInfo X86_64ABIInfo::classifyArgumentType(
- QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE,
- bool isNamedArg)
- const
-{
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- X86_64ABIInfo::Class Lo, Hi;
- classify(Ty, 0, Lo, Hi, isNamedArg);
-
- // Check some invariants.
- // FIXME: Enforce these by construction.
- assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
- assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
-
- neededInt = 0;
- neededSSE = 0;
- llvm::Type *ResType = nullptr;
- switch (Lo) {
- case NoClass:
- if (Hi == NoClass)
- return ABIArgInfo::getIgnore();
- // If the low part is just padding, it takes no register, leave ResType
- // null.
- assert((Hi == SSE || Hi == Integer || Hi == X87Up) &&
- "Unknown missing lo part");
- break;
-
- // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument
- // on the stack.
- case Memory:
-
- // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or
- // COMPLEX_X87, it is passed in memory.
- case X87:
- case ComplexX87:
- if (getRecordArgABI(Ty, getCXXABI()) == CGCXXABI::RAA_Indirect)
- ++neededInt;
- return getIndirectResult(Ty, freeIntRegs);
-
- case SSEUp:
- case X87Up:
- llvm_unreachable("Invalid classification for lo word.");
-
- // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next
- // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8
- // and %r9 is used.
- case Integer:
- ++neededInt;
-
- // Pick an 8-byte type based on the preferred type.
- ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 0, Ty, 0);
-
- // If we have a sign or zero extended integer, make sure to return Extend
- // so that the parameter gets the right LLVM IR attributes.
- if (Hi == NoClass && isa<llvm::IntegerType>(ResType)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- if (Ty->isIntegralOrEnumerationType() &&
- Ty->isPromotableIntegerType())
- return ABIArgInfo::getExtend(Ty);
- }
-
- break;
-
- // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
- // available SSE register is used, the registers are taken in the
- // order from %xmm0 to %xmm7.
- case SSE: {
- llvm::Type *IRType = CGT.ConvertType(Ty);
- ResType = GetSSETypeAtOffset(IRType, 0, Ty, 0);
- ++neededSSE;
- break;
- }
- }
-
- llvm::Type *HighPart = nullptr;
- switch (Hi) {
- // Memory was handled previously, ComplexX87 and X87 should
- // never occur as hi classes, and X87Up must be preceded by X87,
- // which is passed in memory.
- case Memory:
- case X87:
- case ComplexX87:
- llvm_unreachable("Invalid classification for hi word.");
-
- case NoClass: break;
-
- case Integer:
- ++neededInt;
- // Pick an 8-byte type based on the preferred type.
- HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8);
-
- if (Lo == NoClass) // Pass HighPart at offset 8 in memory.
- return ABIArgInfo::getDirect(HighPart, 8);
- break;
-
- // X87Up generally doesn't occur here (long double is passed in
- // memory), except in situations involving unions.
- case X87Up:
- case SSE:
- HighPart = GetSSETypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8);
-
- if (Lo == NoClass) // Pass HighPart at offset 8 in memory.
- return ABIArgInfo::getDirect(HighPart, 8);
-
- ++neededSSE;
- break;
-
- // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the
- // eightbyte is passed in the upper half of the last used SSE
- // register. This only happens when 128-bit vectors are passed.
- case SSEUp:
- assert(Lo == SSE && "Unexpected SSEUp classification");
- ResType = GetByteVectorType(Ty);
- break;
- }
-
- // If a high part was specified, merge it together with the low part. It is
- // known to pass in the high eightbyte of the result. We do this by forming a
- // first class struct aggregate with the high and low part: {low, high}
- if (HighPart)
- ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout());
-
- return ABIArgInfo::getDirect(ResType);
-}
-
-ABIArgInfo
-X86_64ABIInfo::classifyRegCallStructTypeImpl(QualType Ty, unsigned &NeededInt,
- unsigned &NeededSSE) const {
- auto RT = Ty->getAs<RecordType>();
- assert(RT && "classifyRegCallStructType only valid with struct types");
-
- if (RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectReturnResult(Ty);
-
- // Sum up bases
- if (auto CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (CXXRD->isDynamicClass()) {
- NeededInt = NeededSSE = 0;
- return getIndirectReturnResult(Ty);
- }
-
- for (const auto &I : CXXRD->bases())
- if (classifyRegCallStructTypeImpl(I.getType(), NeededInt, NeededSSE)
- .isIndirect()) {
- NeededInt = NeededSSE = 0;
- return getIndirectReturnResult(Ty);
- }
- }
-
- // Sum up members
- for (const auto *FD : RT->getDecl()->fields()) {
- if (FD->getType()->isRecordType() && !FD->getType()->isUnionType()) {
- if (classifyRegCallStructTypeImpl(FD->getType(), NeededInt, NeededSSE)
- .isIndirect()) {
- NeededInt = NeededSSE = 0;
- return getIndirectReturnResult(Ty);
- }
- } else {
- unsigned LocalNeededInt, LocalNeededSSE;
- if (classifyArgumentType(FD->getType(), UINT_MAX, LocalNeededInt,
- LocalNeededSSE, true)
- .isIndirect()) {
- NeededInt = NeededSSE = 0;
- return getIndirectReturnResult(Ty);
- }
- NeededInt += LocalNeededInt;
- NeededSSE += LocalNeededSSE;
- }
- }
-
- return ABIArgInfo::getDirect();
-}
-
-ABIArgInfo X86_64ABIInfo::classifyRegCallStructType(QualType Ty,
- unsigned &NeededInt,
- unsigned &NeededSSE) const {
-
- NeededInt = 0;
- NeededSSE = 0;
-
- return classifyRegCallStructTypeImpl(Ty, NeededInt, NeededSSE);
-}
-
-void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
-
- const unsigned CallingConv = FI.getCallingConvention();
- // It is possible to force Win64 calling convention on any x86_64 target by
- // using __attribute__((ms_abi)). In such case to correctly emit Win64
- // compatible code delegate this call to WinX86_64ABIInfo::computeInfo.
- if (CallingConv == llvm::CallingConv::Win64) {
- WinX86_64ABIInfo Win64ABIInfo(CGT);
- Win64ABIInfo.computeInfo(FI);
- return;
- }
-
- bool IsRegCall = CallingConv == llvm::CallingConv::X86_RegCall;
-
- // Keep track of the number of assigned registers.
- unsigned FreeIntRegs = IsRegCall ? 11 : 6;
- unsigned FreeSSERegs = IsRegCall ? 16 : 8;
- unsigned NeededInt, NeededSSE;
-
- if (!::classifyReturnType(getCXXABI(), FI, *this)) {
- if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() &&
- !FI.getReturnType()->getTypePtr()->isUnionType()) {
- FI.getReturnInfo() =
- classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE);
- if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) {
- FreeIntRegs -= NeededInt;
- FreeSSERegs -= NeededSSE;
- } else {
- FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType());
- }
- } else if (IsRegCall && FI.getReturnType()->getAs<ComplexType>()) {
- // Complex Long Double Type is passed in Memory when Regcall
- // calling convention is used.
- const ComplexType *CT = FI.getReturnType()->getAs<ComplexType>();
- if (getContext().getCanonicalType(CT->getElementType()) ==
- getContext().LongDoubleTy)
- FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType());
- } else
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- }
-
- // If the return value is indirect, then the hidden argument is consuming one
- // integer register.
- if (FI.getReturnInfo().isIndirect())
- --FreeIntRegs;
-
- // The chain argument effectively gives us another free register.
- if (FI.isChainCall())
- ++FreeIntRegs;
-
- unsigned NumRequiredArgs = FI.getNumRequiredArgs();
- // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
- // get assigned (in left-to-right order) for passing as follows...
- unsigned ArgNo = 0;
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it, ++ArgNo) {
- bool IsNamedArg = ArgNo < NumRequiredArgs;
-
- if (IsRegCall && it->type->isStructureOrClassType())
- it->info = classifyRegCallStructType(it->type, NeededInt, NeededSSE);
- else
- it->info = classifyArgumentType(it->type, FreeIntRegs, NeededInt,
- NeededSSE, IsNamedArg);
-
- // AMD64-ABI 3.2.3p3: If there are no registers available for any
- // eightbyte of an argument, the whole argument is passed on the
- // stack. If registers have already been assigned for some
- // eightbytes of such an argument, the assignments get reverted.
- if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) {
- FreeIntRegs -= NeededInt;
- FreeSSERegs -= NeededSSE;
- } else {
- it->info = getIndirectResult(it->type, FreeIntRegs);
- }
- }
-}
-
-static Address EmitX86_64VAArgFromMemory(CodeGenFunction &CGF,
- Address VAListAddr, QualType Ty) {
- Address overflow_arg_area_p = CGF.Builder.CreateStructGEP(
- VAListAddr, 2, CharUnits::fromQuantity(8), "overflow_arg_area_p");
- llvm::Value *overflow_arg_area =
- CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area");
-
- // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16
- // byte boundary if alignment needed by type exceeds 8 byte boundary.
- // It isn't stated explicitly in the standard, but in practice we use
- // alignment greater than 16 where necessary.
- CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty);
- if (Align > CharUnits::fromQuantity(8)) {
- overflow_arg_area = emitRoundPointerUpToAlignment(CGF, overflow_arg_area,
- Align);
- }
-
- // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
- llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
- llvm::Value *Res =
- CGF.Builder.CreateBitCast(overflow_arg_area,
- llvm::PointerType::getUnqual(LTy));
-
- // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to:
- // l->overflow_arg_area + sizeof(type).
- // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to
- // an 8 byte boundary.
-
- uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8;
- llvm::Value *Offset =
- llvm::ConstantInt::get(CGF.Int32Ty, (SizeInBytes + 7) & ~7);
- overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset,
- "overflow_arg_area.next");
- CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p);
-
- // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type.
- return Address(Res, Align);
-}
-
-Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- // Assume that va_list type is correct; should be pointer to LLVM type:
- // struct {
- // i32 gp_offset;
- // i32 fp_offset;
- // i8* overflow_arg_area;
- // i8* reg_save_area;
- // };
- unsigned neededInt, neededSSE;
-
- Ty = getContext().getCanonicalType(Ty);
- ABIArgInfo AI = classifyArgumentType(Ty, 0, neededInt, neededSSE,
- /*isNamedArg*/false);
-
- // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
- // in the registers. If not go to step 7.
- if (!neededInt && !neededSSE)
- return EmitX86_64VAArgFromMemory(CGF, VAListAddr, Ty);
-
- // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of
- // general purpose registers needed to pass type and num_fp to hold
- // the number of floating point registers needed.
-
- // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into
- // registers. In the case: l->gp_offset > 48 - num_gp * 8 or
- // l->fp_offset > 304 - num_fp * 16 go to step 7.
- //
- // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of
- // register save space).
-
- llvm::Value *InRegs = nullptr;
- Address gp_offset_p = Address::invalid(), fp_offset_p = Address::invalid();
- llvm::Value *gp_offset = nullptr, *fp_offset = nullptr;
- if (neededInt) {
- gp_offset_p =
- CGF.Builder.CreateStructGEP(VAListAddr, 0, CharUnits::Zero(),
- "gp_offset_p");
- gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
- InRegs = llvm::ConstantInt::get(CGF.Int32Ty, 48 - neededInt * 8);
- InRegs = CGF.Builder.CreateICmpULE(gp_offset, InRegs, "fits_in_gp");
- }
-
- if (neededSSE) {
- fp_offset_p =
- CGF.Builder.CreateStructGEP(VAListAddr, 1, CharUnits::fromQuantity(4),
- "fp_offset_p");
- fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset");
- llvm::Value *FitsInFP =
- llvm::ConstantInt::get(CGF.Int32Ty, 176 - neededSSE * 16);
- FitsInFP = CGF.Builder.CreateICmpULE(fp_offset, FitsInFP, "fits_in_fp");
- InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP;
- }
-
- llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
- llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
- CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock);
-
- // Emit code to load the value if it was passed in registers.
-
- CGF.EmitBlock(InRegBlock);
-
- // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with
- // an offset of l->gp_offset and/or l->fp_offset. This may require
- // copying to a temporary location in case the parameter is passed
- // in different register classes or requires an alignment greater
- // than 8 for general purpose registers and 16 for XMM registers.
- //
- // FIXME: This really results in shameful code when we end up needing to
- // collect arguments from different places; often what should result in a
- // simple assembling of a structure from scattered addresses has many more
- // loads than necessary. Can we clean this up?
- llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
- llvm::Value *RegSaveArea = CGF.Builder.CreateLoad(
- CGF.Builder.CreateStructGEP(VAListAddr, 3, CharUnits::fromQuantity(16)),
- "reg_save_area");
-
- Address RegAddr = Address::invalid();
- if (neededInt && neededSSE) {
- // FIXME: Cleanup.
- assert(AI.isDirect() && "Unexpected ABI info for mixed regs");
- llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
- Address Tmp = CGF.CreateMemTemp(Ty);
- Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST);
- assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
- llvm::Type *TyLo = ST->getElementType(0);
- llvm::Type *TyHi = ST->getElementType(1);
- assert((TyLo->isFPOrFPVectorTy() ^ TyHi->isFPOrFPVectorTy()) &&
- "Unexpected ABI info for mixed regs");
- llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
- llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
- llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegSaveArea, gp_offset);
- llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegSaveArea, fp_offset);
- llvm::Value *RegLoAddr = TyLo->isFPOrFPVectorTy() ? FPAddr : GPAddr;
- llvm::Value *RegHiAddr = TyLo->isFPOrFPVectorTy() ? GPAddr : FPAddr;
-
- // Copy the first element.
- // FIXME: Our choice of alignment here and below is probably pessimistic.
- llvm::Value *V = CGF.Builder.CreateAlignedLoad(
- TyLo, CGF.Builder.CreateBitCast(RegLoAddr, PTyLo),
- CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(TyLo)));
- CGF.Builder.CreateStore(V,
- CGF.Builder.CreateStructGEP(Tmp, 0, CharUnits::Zero()));
-
- // Copy the second element.
- V = CGF.Builder.CreateAlignedLoad(
- TyHi, CGF.Builder.CreateBitCast(RegHiAddr, PTyHi),
- CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(TyHi)));
- CharUnits Offset = CharUnits::fromQuantity(
- getDataLayout().getStructLayout(ST)->getElementOffset(1));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1, Offset));
-
- RegAddr = CGF.Builder.CreateElementBitCast(Tmp, LTy);
- } else if (neededInt) {
- RegAddr = Address(CGF.Builder.CreateGEP(RegSaveArea, gp_offset),
- CharUnits::fromQuantity(8));
- RegAddr = CGF.Builder.CreateElementBitCast(RegAddr, LTy);
-
- // Copy to a temporary if necessary to ensure the appropriate alignment.
- std::pair<CharUnits, CharUnits> SizeAlign =
- getContext().getTypeInfoInChars(Ty);
- uint64_t TySize = SizeAlign.first.getQuantity();
- CharUnits TyAlign = SizeAlign.second;
-
- // Copy into a temporary if the type is more aligned than the
- // register save area.
- if (TyAlign.getQuantity() > 8) {
- Address Tmp = CGF.CreateMemTemp(Ty);
- CGF.Builder.CreateMemCpy(Tmp, RegAddr, TySize, false);
- RegAddr = Tmp;
- }
-
- } else if (neededSSE == 1) {
- RegAddr = Address(CGF.Builder.CreateGEP(RegSaveArea, fp_offset),
- CharUnits::fromQuantity(16));
- RegAddr = CGF.Builder.CreateElementBitCast(RegAddr, LTy);
- } else {
- assert(neededSSE == 2 && "Invalid number of needed registers!");
- // SSE registers are spaced 16 bytes apart in the register save
- // area, we need to collect the two eightbytes together.
- // The ABI isn't explicit about this, but it seems reasonable
- // to assume that the slots are 16-byte aligned, since the stack is
- // naturally 16-byte aligned and the prologue is expected to store
- // all the SSE registers to the RSA.
- Address RegAddrLo = Address(CGF.Builder.CreateGEP(RegSaveArea, fp_offset),
- CharUnits::fromQuantity(16));
- Address RegAddrHi =
- CGF.Builder.CreateConstInBoundsByteGEP(RegAddrLo,
- CharUnits::fromQuantity(16));
- llvm::Type *ST = AI.canHaveCoerceToType()
- ? AI.getCoerceToType()
- : llvm::StructType::get(CGF.DoubleTy, CGF.DoubleTy);
- llvm::Value *V;
- Address Tmp = CGF.CreateMemTemp(Ty);
- Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST);
- V = CGF.Builder.CreateLoad(CGF.Builder.CreateElementBitCast(
- RegAddrLo, ST->getStructElementType(0)));
- CGF.Builder.CreateStore(V,
- CGF.Builder.CreateStructGEP(Tmp, 0, CharUnits::Zero()));
- V = CGF.Builder.CreateLoad(CGF.Builder.CreateElementBitCast(
- RegAddrHi, ST->getStructElementType(1)));
- CGF.Builder.CreateStore(V,
- CGF.Builder.CreateStructGEP(Tmp, 1, CharUnits::fromQuantity(8)));
-
- RegAddr = CGF.Builder.CreateElementBitCast(Tmp, LTy);
- }
-
- // AMD64-ABI 3.5.7p5: Step 5. Set:
- // l->gp_offset = l->gp_offset + num_gp * 8
- // l->fp_offset = l->fp_offset + num_fp * 16.
- if (neededInt) {
- llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, neededInt * 8);
- CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset),
- gp_offset_p);
- }
- if (neededSSE) {
- llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, neededSSE * 16);
- CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset),
- fp_offset_p);
- }
- CGF.EmitBranch(ContBlock);
-
- // Emit code to load the value if it was passed in memory.
-
- CGF.EmitBlock(InMemBlock);
- Address MemAddr = EmitX86_64VAArgFromMemory(CGF, VAListAddr, Ty);
-
- // Return the appropriate result.
-
- CGF.EmitBlock(ContBlock);
- Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, MemAddr, InMemBlock,
- "vaarg.addr");
- return ResAddr;
-}
-
-Address X86_64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
- CGF.getContext().getTypeInfoInChars(Ty),
- CharUnits::fromQuantity(8),
- /*allowHigherAlign*/ false);
-}
-
-ABIArgInfo
-WinX86_64ABIInfo::reclassifyHvaArgType(QualType Ty, unsigned &FreeSSERegs,
- const ABIArgInfo &current) const {
- // Assumes vectorCall calling convention.
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
-
- if (!Ty->isBuiltinType() && !Ty->isVectorType() &&
- isHomogeneousAggregate(Ty, Base, NumElts) && FreeSSERegs >= NumElts) {
- FreeSSERegs -= NumElts;
- return getDirectX86Hva();
- }
- return current;
-}
-
-ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs,
- bool IsReturnType, bool IsVectorCall,
- bool IsRegCall) const {
-
- if (Ty->isVoidType())
- return ABIArgInfo::getIgnore();
-
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- TypeInfo Info = getContext().getTypeInfo(Ty);
- uint64_t Width = Info.Width;
- CharUnits Align = getContext().toCharUnitsFromBits(Info.Align);
-
- const RecordType *RT = Ty->getAs<RecordType>();
- if (RT) {
- if (!IsReturnType) {
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
- }
-
- if (RT->getDecl()->hasFlexibleArrayMember())
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-
- }
-
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
- // vectorcall adds the concept of a homogenous vector aggregate, similar to
- // other targets.
- if ((IsVectorCall || IsRegCall) &&
- isHomogeneousAggregate(Ty, Base, NumElts)) {
- if (IsRegCall) {
- if (FreeSSERegs >= NumElts) {
- FreeSSERegs -= NumElts;
- if (IsReturnType || Ty->isBuiltinType() || Ty->isVectorType())
- return ABIArgInfo::getDirect();
- return ABIArgInfo::getExpand();
- }
- return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
- } else if (IsVectorCall) {
- if (FreeSSERegs >= NumElts &&
- (IsReturnType || Ty->isBuiltinType() || Ty->isVectorType())) {
- FreeSSERegs -= NumElts;
- return ABIArgInfo::getDirect();
- } else if (IsReturnType) {
- return ABIArgInfo::getExpand();
- } else if (!Ty->isBuiltinType() && !Ty->isVectorType()) {
- // HVAs are delayed and reclassified in the 2nd step.
- return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
- }
- }
- }
-
- if (Ty->isMemberPointerType()) {
- // If the member pointer is represented by an LLVM int or ptr, pass it
- // directly.
- llvm::Type *LLTy = CGT.ConvertType(Ty);
- if (LLTy->isPointerTy() || LLTy->isIntegerTy())
- return ABIArgInfo::getDirect();
- }
-
- if (RT || Ty->isAnyComplexType() || Ty->isMemberPointerType()) {
- // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is
- // not 1, 2, 4, or 8 bytes, must be passed by reference."
- if (Width > 64 || !llvm::isPowerOf2_64(Width))
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-
- // Otherwise, coerce it to a small integer.
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Width));
- }
-
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- switch (BT->getKind()) {
- case BuiltinType::Bool:
- // Bool type is always extended to the ABI, other builtin types are not
- // extended.
- return ABIArgInfo::getExtend(Ty);
-
- case BuiltinType::LongDouble:
- // Mingw64 GCC uses the old 80 bit extended precision floating point
- // unit. It passes them indirectly through memory.
- if (IsMingw64) {
- const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
- if (LDF == &llvm::APFloat::x87DoubleExtended())
- return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
- }
- break;
-
- case BuiltinType::Int128:
- case BuiltinType::UInt128:
- // If it's a parameter type, the normal ABI rule is that arguments larger
- // than 8 bytes are passed indirectly. GCC follows it. We follow it too,
- // even though it isn't particularly efficient.
- if (!IsReturnType)
- return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
-
- // Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that.
- // Clang matches them for compatibility.
- return ABIArgInfo::getDirect(
- llvm::VectorType::get(llvm::Type::getInt64Ty(getVMContext()), 2));
-
- default:
- break;
- }
- }
-
- return ABIArgInfo::getDirect();
-}
-
-void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI,
- unsigned FreeSSERegs,
- bool IsVectorCall,
- bool IsRegCall) const {
- unsigned Count = 0;
- for (auto &I : FI.arguments()) {
- // Vectorcall in x64 only permits the first 6 arguments to be passed
- // as XMM/YMM registers.
- if (Count < VectorcallMaxParamNumAsReg)
- I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall);
- else {
- // Since these cannot be passed in registers, pretend no registers
- // are left.
- unsigned ZeroSSERegsAvail = 0;
- I.info = classify(I.type, /*FreeSSERegs=*/ZeroSSERegsAvail, false,
- IsVectorCall, IsRegCall);
- }
- ++Count;
- }
-
- for (auto &I : FI.arguments()) {
- I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info);
- }
-}
-
-void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- bool IsVectorCall =
- FI.getCallingConvention() == llvm::CallingConv::X86_VectorCall;
- bool IsRegCall = FI.getCallingConvention() == llvm::CallingConv::X86_RegCall;
-
- unsigned FreeSSERegs = 0;
- if (IsVectorCall) {
- // We can use up to 4 SSE return registers with vectorcall.
- FreeSSERegs = 4;
- } else if (IsRegCall) {
- // RegCall gives us 16 SSE registers.
- FreeSSERegs = 16;
- }
-
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classify(FI.getReturnType(), FreeSSERegs, true,
- IsVectorCall, IsRegCall);
-
- if (IsVectorCall) {
- // We can use up to 6 SSE register parameters with vectorcall.
- FreeSSERegs = 6;
- } else if (IsRegCall) {
- // RegCall gives us 16 SSE registers, we can reuse the return registers.
- FreeSSERegs = 16;
- }
-
- if (IsVectorCall) {
- computeVectorCallArgs(FI, FreeSSERegs, IsVectorCall, IsRegCall);
- } else {
- for (auto &I : FI.arguments())
- I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall);
- }
-
-}
-
-Address WinX86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
-
- bool IsIndirect = false;
-
- // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is
- // not 1, 2, 4, or 8 bytes, must be passed by reference."
- if (isAggregateTypeForABI(Ty) || Ty->isMemberPointerType()) {
- uint64_t Width = getContext().getTypeSize(Ty);
- IsIndirect = Width > 64 || !llvm::isPowerOf2_64(Width);
- }
-
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
- CGF.getContext().getTypeInfoInChars(Ty),
- CharUnits::fromQuantity(8),
- /*allowHigherAlign*/ false);
-}
-
-// PowerPC-32
-namespace {
-/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
-class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
- bool IsSoftFloatABI;
- bool IsRetSmallStructInRegABI;
-
- CharUnits getParamTypeAlignment(QualType Ty) const;
-
-public:
- PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI,
- bool RetSmallStructInRegABI)
- : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI),
- IsRetSmallStructInRegABI(RetSmallStructInRegABI) {}
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
-
- void computeInfo(CGFunctionInfo &FI) const override {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
- }
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-};
-
-class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI,
- bool RetSmallStructInRegABI)
- : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT, SoftFloatABI,
- RetSmallStructInRegABI)) {}
-
- static bool isStructReturnInRegABI(const llvm::Triple &Triple,
- const CodeGenOptions &Opts);
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
- // This is recovered from gcc output.
- return 1; // r1 is the dedicated stack pointer
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override;
-};
-}
-
-CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
- // Complex types are passed just like their elements
- if (const ComplexType *CTy = Ty->getAs<ComplexType>())
- Ty = CTy->getElementType();
-
- if (Ty->isVectorType())
- return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16
- : 4);
-
- // For single-element float/vector structs, we consider the whole type
- // to have the same alignment requirements as its single element.
- const Type *AlignTy = nullptr;
- if (const Type *EltType = isSingleElementStruct(Ty, getContext())) {
- const BuiltinType *BT = EltType->getAs<BuiltinType>();
- if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) ||
- (BT && BT->isFloatingPoint()))
- AlignTy = EltType;
- }
-
- if (AlignTy)
- return CharUnits::fromQuantity(AlignTy->isVectorType() ? 16 : 4);
- return CharUnits::fromQuantity(4);
-}
-
-ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
- uint64_t Size;
-
- // -msvr4-struct-return puts small aggregates in GPR3 and GPR4.
- if (isAggregateTypeForABI(RetTy) && IsRetSmallStructInRegABI &&
- (Size = getContext().getTypeSize(RetTy)) <= 64) {
- // System V ABI (1995), page 3-22, specified:
- // > A structure or union whose size is less than or equal to 8 bytes
- // > shall be returned in r3 and r4, as if it were first stored in the
- // > 8-byte aligned memory area and then the low addressed word were
- // > loaded into r3 and the high-addressed word into r4. Bits beyond
- // > the last member of the structure or union are not defined.
- //
- // GCC for big-endian PPC32 inserts the pad before the first member,
- // not "beyond the last member" of the struct. To stay compatible
- // with GCC, we coerce the struct to an integer of the same size.
- // LLVM will extend it and return i32 in r3, or i64 in r3:r4.
- if (Size == 0)
- return ABIArgInfo::getIgnore();
- else {
- llvm::Type *CoerceTy = llvm::Type::getIntNTy(getVMContext(), Size);
- return ABIArgInfo::getDirect(CoerceTy);
- }
- }
-
- return DefaultABIInfo::classifyReturnType(RetTy);
-}
-
-// TODO: this implementation is now likely redundant with
-// DefaultABIInfo::EmitVAArg.
-Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
- QualType Ty) const {
- if (getTarget().getTriple().isOSDarwin()) {
- auto TI = getContext().getTypeInfoInChars(Ty);
- TI.second = getParamTypeAlignment(Ty);
-
- CharUnits SlotSize = CharUnits::fromQuantity(4);
- return emitVoidPtrVAArg(CGF, VAList, Ty,
- classifyArgumentType(Ty).isIndirect(), TI, SlotSize,
- /*AllowHigherAlign=*/true);
- }
-
- const unsigned OverflowLimit = 8;
- if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
- // TODO: Implement this. For now ignore.
- (void)CTy;
- return Address::invalid(); // FIXME?
- }
-
- // struct __va_list_tag {
- // unsigned char gpr;
- // unsigned char fpr;
- // unsigned short reserved;
- // void *overflow_arg_area;
- // void *reg_save_area;
- // };
-
- bool isI64 = Ty->isIntegerType() && getContext().getTypeSize(Ty) == 64;
- bool isInt =
- Ty->isIntegerType() || Ty->isPointerType() || Ty->isAggregateType();
- bool isF64 = Ty->isFloatingType() && getContext().getTypeSize(Ty) == 64;
-
- // All aggregates are passed indirectly? That doesn't seem consistent
- // with the argument-lowering code.
- bool isIndirect = Ty->isAggregateType();
-
- CGBuilderTy &Builder = CGF.Builder;
-
- // The calling convention either uses 1-2 GPRs or 1 FPR.
- Address NumRegsAddr = Address::invalid();
- if (isInt || IsSoftFloatABI) {
- NumRegsAddr = Builder.CreateStructGEP(VAList, 0, CharUnits::Zero(), "gpr");
- } else {
- NumRegsAddr = Builder.CreateStructGEP(VAList, 1, CharUnits::One(), "fpr");
- }
-
- llvm::Value *NumRegs = Builder.CreateLoad(NumRegsAddr, "numUsedRegs");
-
- // "Align" the register count when TY is i64.
- if (isI64 || (isF64 && IsSoftFloatABI)) {
- NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(1));
- NumRegs = Builder.CreateAnd(NumRegs, Builder.getInt8((uint8_t) ~1U));
- }
-
- llvm::Value *CC =
- Builder.CreateICmpULT(NumRegs, Builder.getInt8(OverflowLimit), "cond");
-
- llvm::BasicBlock *UsingRegs = CGF.createBasicBlock("using_regs");
- llvm::BasicBlock *UsingOverflow = CGF.createBasicBlock("using_overflow");
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
-
- Builder.CreateCondBr(CC, UsingRegs, UsingOverflow);
-
- llvm::Type *DirectTy = CGF.ConvertType(Ty);
- if (isIndirect) DirectTy = DirectTy->getPointerTo(0);
-
- // Case 1: consume registers.
- Address RegAddr = Address::invalid();
- {
- CGF.EmitBlock(UsingRegs);
-
- Address RegSaveAreaPtr =
- Builder.CreateStructGEP(VAList, 4, CharUnits::fromQuantity(8));
- RegAddr = Address(Builder.CreateLoad(RegSaveAreaPtr),
- CharUnits::fromQuantity(8));
- assert(RegAddr.getElementType() == CGF.Int8Ty);
-
- // Floating-point registers start after the general-purpose registers.
- if (!(isInt || IsSoftFloatABI)) {
- RegAddr = Builder.CreateConstInBoundsByteGEP(RegAddr,
- CharUnits::fromQuantity(32));
- }
-
- // Get the address of the saved value by scaling the number of
- // registers we've used by the number of
- CharUnits RegSize = CharUnits::fromQuantity((isInt || IsSoftFloatABI) ? 4 : 8);
- llvm::Value *RegOffset =
- Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity()));
- RegAddr = Address(Builder.CreateInBoundsGEP(CGF.Int8Ty,
- RegAddr.getPointer(), RegOffset),
- RegAddr.getAlignment().alignmentOfArrayElement(RegSize));
- RegAddr = Builder.CreateElementBitCast(RegAddr, DirectTy);
-
- // Increase the used-register count.
- NumRegs =
- Builder.CreateAdd(NumRegs,
- Builder.getInt8((isI64 || (isF64 && IsSoftFloatABI)) ? 2 : 1));
- Builder.CreateStore(NumRegs, NumRegsAddr);
-
- CGF.EmitBranch(Cont);
- }
-
- // Case 2: consume space in the overflow area.
- Address MemAddr = Address::invalid();
- {
- CGF.EmitBlock(UsingOverflow);
-
- Builder.CreateStore(Builder.getInt8(OverflowLimit), NumRegsAddr);
-
- // Everything in the overflow area is rounded up to a size of at least 4.
- CharUnits OverflowAreaAlign = CharUnits::fromQuantity(4);
-
- CharUnits Size;
- if (!isIndirect) {
- auto TypeInfo = CGF.getContext().getTypeInfoInChars(Ty);
- Size = TypeInfo.first.alignTo(OverflowAreaAlign);
- } else {
- Size = CGF.getPointerSize();
- }
-
- Address OverflowAreaAddr =
- Builder.CreateStructGEP(VAList, 3, CharUnits::fromQuantity(4));
- Address OverflowArea(Builder.CreateLoad(OverflowAreaAddr, "argp.cur"),
- OverflowAreaAlign);
- // Round up address of argument to alignment
- CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty);
- if (Align > OverflowAreaAlign) {
- llvm::Value *Ptr = OverflowArea.getPointer();
- OverflowArea = Address(emitRoundPointerUpToAlignment(CGF, Ptr, Align),
- Align);
- }
-
- MemAddr = Builder.CreateElementBitCast(OverflowArea, DirectTy);
-
- // Increase the overflow area.
- OverflowArea = Builder.CreateConstInBoundsByteGEP(OverflowArea, Size);
- Builder.CreateStore(OverflowArea.getPointer(), OverflowAreaAddr);
- CGF.EmitBranch(Cont);
- }
-
- CGF.EmitBlock(Cont);
-
- // Merge the cases with a phi.
- Address Result = emitMergePHI(CGF, RegAddr, UsingRegs, MemAddr, UsingOverflow,
- "vaarg.addr");
-
- // Load the pointer if the argument was passed indirectly.
- if (isIndirect) {
- Result = Address(Builder.CreateLoad(Result, "aggr"),
- getContext().getTypeAlignInChars(Ty));
- }
-
- return Result;
-}
-
-bool PPC32TargetCodeGenInfo::isStructReturnInRegABI(
- const llvm::Triple &Triple, const CodeGenOptions &Opts) {
- assert(Triple.getArch() == llvm::Triple::ppc);
-
- switch (Opts.getStructReturnConvention()) {
- case CodeGenOptions::SRCK_Default:
- break;
- case CodeGenOptions::SRCK_OnStack: // -maix-struct-return
- return false;
- case CodeGenOptions::SRCK_InRegs: // -msvr4-struct-return
- return true;
- }
-
- if (Triple.isOSBinFormatELF() && !Triple.isOSLinux())
- return true;
-
- return false;
-}
-
-bool
-PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- // This is calculated from the LLVM and GCC tables and verified
- // against gcc output. AFAIK all ABIs use the same encoding.
-
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
-
- llvm::IntegerType *i8 = CGF.Int8Ty;
- llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
- llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
- llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
-
- // 0-31: r0-31, the 4-byte general-purpose registers
- AssignToArrayRange(Builder, Address, Four8, 0, 31);
-
- // 32-63: fp0-31, the 8-byte floating-point registers
- AssignToArrayRange(Builder, Address, Eight8, 32, 63);
-
- // 64-76 are various 4-byte special-purpose registers:
- // 64: mq
- // 65: lr
- // 66: ctr
- // 67: ap
- // 68-75 cr0-7
- // 76: xer
- AssignToArrayRange(Builder, Address, Four8, 64, 76);
-
- // 77-108: v0-31, the 16-byte vector registers
- AssignToArrayRange(Builder, Address, Sixteen8, 77, 108);
-
- // 109: vrsave
- // 110: vscr
- // 111: spe_acc
- // 112: spefscr
- // 113: sfp
- AssignToArrayRange(Builder, Address, Four8, 109, 113);
-
- return false;
-}
-
-// PowerPC-64
-
-namespace {
-/// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information.
-class PPC64_SVR4_ABIInfo : public SwiftABIInfo {
-public:
- enum ABIKind {
- ELFv1 = 0,
- ELFv2
- };
-
-private:
- static const unsigned GPRBits = 64;
- ABIKind Kind;
- bool HasQPX;
- bool IsSoftFloatABI;
-
- // A vector of float or double will be promoted to <4 x f32> or <4 x f64> and
- // will be passed in a QPX register.
- bool IsQPXVectorTy(const Type *Ty) const {
- if (!HasQPX)
- return false;
-
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- unsigned NumElements = VT->getNumElements();
- if (NumElements == 1)
- return false;
-
- if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) {
- if (getContext().getTypeSize(Ty) <= 256)
- return true;
- } else if (VT->getElementType()->
- isSpecificBuiltinType(BuiltinType::Float)) {
- if (getContext().getTypeSize(Ty) <= 128)
- return true;
- }
- }
-
- return false;
- }
-
- bool IsQPXVectorTy(QualType Ty) const {
- return IsQPXVectorTy(Ty.getTypePtr());
- }
-
-public:
- PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind, bool HasQPX,
- bool SoftFloatABI)
- : SwiftABIInfo(CGT), Kind(Kind), HasQPX(HasQPX),
- IsSoftFloatABI(SoftFloatABI) {}
-
- bool isPromotableTypeForABI(QualType Ty) const;
- CharUnits getParamTypeAlignment(QualType Ty) const;
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType Ty) const;
-
- bool isHomogeneousAggregateBaseType(QualType Ty) const override;
- bool isHomogeneousAggregateSmallEnough(const Type *Ty,
- uint64_t Members) const override;
-
- // TODO: We can add more logic to computeInfo to improve performance.
- // Example: For aggregate arguments that fit in a register, we could
- // use getDirectInReg (as is done below for structs containing a single
- // floating-point value) to avoid pushing them to memory on function
- // entry. This would require changing the logic in PPCISelLowering
- // when lowering the parameters in the caller and args in the callee.
- void computeInfo(CGFunctionInfo &FI) const override {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments()) {
- // We rely on the default argument classification for the most part.
- // One exception: An aggregate containing a single floating-point
- // or vector item must be passed in a register if one is available.
- const Type *T = isSingleElementStruct(I.type, getContext());
- if (T) {
- const BuiltinType *BT = T->getAs<BuiltinType>();
- if (IsQPXVectorTy(T) ||
- (T->isVectorType() && getContext().getTypeSize(T) == 128) ||
- (BT && BT->isFloatingPoint())) {
- QualType QT(T, 0);
- I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
- continue;
- }
- }
- I.info = classifyArgumentType(I.type);
- }
- }
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
-
- bool isSwiftErrorInRegister() const override {
- return false;
- }
-};
-
-class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo {
-
-public:
- PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT,
- PPC64_SVR4_ABIInfo::ABIKind Kind, bool HasQPX,
- bool SoftFloatABI)
- : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind, HasQPX,
- SoftFloatABI)) {}
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
- // This is recovered from gcc output.
- return 1; // r1 is the dedicated stack pointer
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override;
-};
-
-class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
-public:
- PPC64TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {}
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
- // This is recovered from gcc output.
- return 1; // r1 is the dedicated stack pointer
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override;
-};
-
-}
-
-// Return true if the ABI requires Ty to be passed sign- or zero-
-// extended to 64 bits.
-bool
-PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- // Promotable integer types are required to be promoted by the ABI.
- if (Ty->isPromotableIntegerType())
- return true;
-
- // In addition to the usual promotable integer types, we also need to
- // extend all 32-bit types, since the ABI requires promotion to 64 bits.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Int:
- case BuiltinType::UInt:
- return true;
- default:
- break;
- }
-
- return false;
-}
-
-/// isAlignedParamType - Determine whether a type requires 16-byte or
-/// higher alignment in the parameter area. Always returns at least 8.
-CharUnits PPC64_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
- // Complex types are passed just like their elements.
- if (const ComplexType *CTy = Ty->getAs<ComplexType>())
- Ty = CTy->getElementType();
-
- // Only vector types of size 16 bytes need alignment (larger types are
- // passed via reference, smaller types are not aligned).
- if (IsQPXVectorTy(Ty)) {
- if (getContext().getTypeSize(Ty) > 128)
- return CharUnits::fromQuantity(32);
-
- return CharUnits::fromQuantity(16);
- } else if (Ty->isVectorType()) {
- return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16 : 8);
- }
-
- // For single-element float/vector structs, we consider the whole type
- // to have the same alignment requirements as its single element.
- const Type *AlignAsType = nullptr;
- const Type *EltType = isSingleElementStruct(Ty, getContext());
- if (EltType) {
- const BuiltinType *BT = EltType->getAs<BuiltinType>();
- if (IsQPXVectorTy(EltType) || (EltType->isVectorType() &&
- getContext().getTypeSize(EltType) == 128) ||
- (BT && BT->isFloatingPoint()))
- AlignAsType = EltType;
- }
-
- // Likewise for ELFv2 homogeneous aggregates.
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (!AlignAsType && Kind == ELFv2 &&
- isAggregateTypeForABI(Ty) && isHomogeneousAggregate(Ty, Base, Members))
- AlignAsType = Base;
-
- // With special case aggregates, only vector base types need alignment.
- if (AlignAsType && IsQPXVectorTy(AlignAsType)) {
- if (getContext().getTypeSize(AlignAsType) > 128)
- return CharUnits::fromQuantity(32);
-
- return CharUnits::fromQuantity(16);
- } else if (AlignAsType) {
- return CharUnits::fromQuantity(AlignAsType->isVectorType() ? 16 : 8);
- }
-
- // Otherwise, we only need alignment for any aggregate type that
- // has an alignment requirement of >= 16 bytes.
- if (isAggregateTypeForABI(Ty) && getContext().getTypeAlign(Ty) >= 128) {
- if (HasQPX && getContext().getTypeAlign(Ty) >= 256)
- return CharUnits::fromQuantity(32);
- return CharUnits::fromQuantity(16);
- }
-
- return CharUnits::fromQuantity(8);
-}
-
-/// isHomogeneousAggregate - Return true if a type is an ELFv2 homogeneous
-/// aggregate. Base is set to the base element type, and Members is set
-/// to the number of base elements.
-bool ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base,
- uint64_t &Members) const {
- if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
- uint64_t NElements = AT->getSize().getZExtValue();
- if (NElements == 0)
- return false;
- if (!isHomogeneousAggregate(AT->getElementType(), Base, Members))
- return false;
- Members *= NElements;
- } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return false;
-
- Members = 0;
-
- // If this is a C++ record, check the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (const auto &I : CXXRD->bases()) {
- // Ignore empty records.
- if (isEmptyRecord(getContext(), I.getType(), true))
- continue;
-
- uint64_t FldMembers;
- if (!isHomogeneousAggregate(I.getType(), Base, FldMembers))
- return false;
-
- Members += FldMembers;
- }
- }
-
- for (const auto *FD : RD->fields()) {
- // Ignore (non-zero arrays of) empty records.
- QualType FT = FD->getType();
- while (const ConstantArrayType *AT =
- getContext().getAsConstantArrayType(FT)) {
- if (AT->getSize().getZExtValue() == 0)
- return false;
- FT = AT->getElementType();
- }
- if (isEmptyRecord(getContext(), FT, true))
- continue;
-
- // For compatibility with GCC, ignore empty bitfields in C++ mode.
- if (getContext().getLangOpts().CPlusPlus &&
- FD->isZeroLengthBitField(getContext()))
- continue;
-
- uint64_t FldMembers;
- if (!isHomogeneousAggregate(FD->getType(), Base, FldMembers))
- return false;
-
- Members = (RD->isUnion() ?
- std::max(Members, FldMembers) : Members + FldMembers);
- }
-
- if (!Base)
- return false;
-
- // Ensure there is no padding.
- if (getContext().getTypeSize(Base) * Members !=
- getContext().getTypeSize(Ty))
- return false;
- } else {
- Members = 1;
- if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
- Members = 2;
- Ty = CT->getElementType();
- }
-
- // Most ABIs only support float, double, and some vector type widths.
- if (!isHomogeneousAggregateBaseType(Ty))
- return false;
-
- // The base type must be the same for all members. Types that
- // agree in both total size and mode (float vs. vector) are
- // treated as being equivalent here.
- const Type *TyPtr = Ty.getTypePtr();
- if (!Base) {
- Base = TyPtr;
- // If it's a non-power-of-2 vector, its size is already a power-of-2,
- // so make sure to widen it explicitly.
- if (const VectorType *VT = Base->getAs<VectorType>()) {
- QualType EltTy = VT->getElementType();
- unsigned NumElements =
- getContext().getTypeSize(VT) / getContext().getTypeSize(EltTy);
- Base = getContext()
- .getVectorType(EltTy, NumElements, VT->getVectorKind())
- .getTypePtr();
- }
- }
-
- if (Base->isVectorType() != TyPtr->isVectorType() ||
- getContext().getTypeSize(Base) != getContext().getTypeSize(TyPtr))
- return false;
- }
- return Members > 0 && isHomogeneousAggregateSmallEnough(Base, Members);
-}
-
-bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
- // Homogeneous aggregates for ELFv2 must have base types of float,
- // double, long double, or 128-bit vectors.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::Float ||
- BT->getKind() == BuiltinType::Double ||
- BT->getKind() == BuiltinType::LongDouble ||
- (getContext().getTargetInfo().hasFloat128Type() &&
- (BT->getKind() == BuiltinType::Float128))) {
- if (IsSoftFloatABI)
- return false;
- return true;
- }
- }
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- if (getContext().getTypeSize(VT) == 128 || IsQPXVectorTy(Ty))
- return true;
- }
- return false;
-}
-
-bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateSmallEnough(
- const Type *Base, uint64_t Members) const {
- // Vector and fp128 types require one register, other floating point types
- // require one or two registers depending on their size.
- uint32_t NumRegs =
- ((getContext().getTargetInfo().hasFloat128Type() &&
- Base->isFloat128Type()) ||
- Base->isVectorType()) ? 1
- : (getContext().getTypeSize(Base) + 63) / 64;
-
- // Homogeneous Aggregates may occupy at most 8 registers.
- return Members * NumRegs <= 8;
-}
-
-ABIArgInfo
-PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- if (Ty->isAnyComplexType())
- return ABIArgInfo::getDirect();
-
- // Non-Altivec vector types are passed in GPRs (smaller than 16 bytes)
- // or via reference (larger than 16 bytes).
- if (Ty->isVectorType() && !IsQPXVectorTy(Ty)) {
- uint64_t Size = getContext().getTypeSize(Ty);
- if (Size > 128)
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
- else if (Size < 128) {
- llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size);
- return ABIArgInfo::getDirect(CoerceTy);
- }
- }
-
- if (isAggregateTypeForABI(Ty)) {
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
- uint64_t ABIAlign = getParamTypeAlignment(Ty).getQuantity();
- uint64_t TyAlign = getContext().getTypeAlignInChars(Ty).getQuantity();
-
- // ELFv2 homogeneous aggregates are passed as array types.
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (Kind == ELFv2 &&
- isHomogeneousAggregate(Ty, Base, Members)) {
- llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0));
- llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members);
- return ABIArgInfo::getDirect(CoerceTy);
- }
-
- // If an aggregate may end up fully in registers, we do not
- // use the ByVal method, but pass the aggregate as array.
- // This is usually beneficial since we avoid forcing the
- // back-end to store the argument to memory.
- uint64_t Bits = getContext().getTypeSize(Ty);
- if (Bits > 0 && Bits <= 8 * GPRBits) {
- llvm::Type *CoerceTy;
-
- // Types up to 8 bytes are passed as integer type (which will be
- // properly aligned in the argument save area doubleword).
- if (Bits <= GPRBits)
- CoerceTy =
- llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
- // Larger types are passed as arrays, with the base type selected
- // according to the required alignment in the save area.
- else {
- uint64_t RegBits = ABIAlign * 8;
- uint64_t NumRegs = llvm::alignTo(Bits, RegBits) / RegBits;
- llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), RegBits);
- CoerceTy = llvm::ArrayType::get(RegTy, NumRegs);
- }
-
- return ABIArgInfo::getDirect(CoerceTy);
- }
-
- // All other aggregates are passed ByVal.
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(ABIAlign),
- /*ByVal=*/true,
- /*Realign=*/TyAlign > ABIAlign);
- }
-
- return (isPromotableTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
-}
-
-ABIArgInfo
-PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- if (RetTy->isAnyComplexType())
- return ABIArgInfo::getDirect();
-
- // Non-Altivec vector types are returned in GPRs (smaller than 16 bytes)
- // or via reference (larger than 16 bytes).
- if (RetTy->isVectorType() && !IsQPXVectorTy(RetTy)) {
- uint64_t Size = getContext().getTypeSize(RetTy);
- if (Size > 128)
- return getNaturalAlignIndirect(RetTy);
- else if (Size < 128) {
- llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size);
- return ABIArgInfo::getDirect(CoerceTy);
- }
- }
-
- if (isAggregateTypeForABI(RetTy)) {
- // ELFv2 homogeneous aggregates are returned as array types.
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (Kind == ELFv2 &&
- isHomogeneousAggregate(RetTy, Base, Members)) {
- llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0));
- llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members);
- return ABIArgInfo::getDirect(CoerceTy);
- }
-
- // ELFv2 small aggregates are returned in up to two registers.
- uint64_t Bits = getContext().getTypeSize(RetTy);
- if (Kind == ELFv2 && Bits <= 2 * GPRBits) {
- if (Bits == 0)
- return ABIArgInfo::getIgnore();
-
- llvm::Type *CoerceTy;
- if (Bits > GPRBits) {
- CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
- CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy);
- } else
- CoerceTy =
- llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
- return ABIArgInfo::getDirect(CoerceTy);
- }
-
- // All other aggregates are returned indirectly.
- return getNaturalAlignIndirect(RetTy);
- }
-
- return (isPromotableTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
-}
-
-// Based on ARMABIInfo::EmitVAArg, adjusted for 64-bit machine.
-Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- auto TypeInfo = getContext().getTypeInfoInChars(Ty);
- TypeInfo.second = getParamTypeAlignment(Ty);
-
- CharUnits SlotSize = CharUnits::fromQuantity(8);
-
- // If we have a complex type and the base type is smaller than 8 bytes,
- // the ABI calls for the real and imaginary parts to be right-adjusted
- // in separate doublewords. However, Clang expects us to produce a
- // pointer to a structure with the two parts packed tightly. So generate
- // loads of the real and imaginary parts relative to the va_list pointer,
- // and store them to a temporary structure.
- if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
- CharUnits EltSize = TypeInfo.first / 2;
- if (EltSize < SlotSize) {
- Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty,
- SlotSize * 2, SlotSize,
- SlotSize, /*AllowHigher*/ true);
-
- Address RealAddr = Addr;
- Address ImagAddr = RealAddr;
- if (CGF.CGM.getDataLayout().isBigEndian()) {
- RealAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr,
- SlotSize - EltSize);
- ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr,
- 2 * SlotSize - EltSize);
- } else {
- ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize);
- }
-
- llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType());
- RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy);
- ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy);
- llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal");
- llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag");
-
- Address Temp = CGF.CreateMemTemp(Ty, "vacplx");
- CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty),
- /*init*/ true);
- return Temp;
- }
- }
-
- // Otherwise, just use the general rule.
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false,
- TypeInfo, SlotSize, /*AllowHigher*/ true);
-}
-
-static bool
-PPC64_initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) {
- // This is calculated from the LLVM and GCC tables and verified
- // against gcc output. AFAIK all ABIs use the same encoding.
-
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
-
- llvm::IntegerType *i8 = CGF.Int8Ty;
- llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
- llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
- llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
-
- // 0-31: r0-31, the 8-byte general-purpose registers
- AssignToArrayRange(Builder, Address, Eight8, 0, 31);
-
- // 32-63: fp0-31, the 8-byte floating-point registers
- AssignToArrayRange(Builder, Address, Eight8, 32, 63);
-
- // 64-67 are various 8-byte special-purpose registers:
- // 64: mq
- // 65: lr
- // 66: ctr
- // 67: ap
- AssignToArrayRange(Builder, Address, Eight8, 64, 67);
-
- // 68-76 are various 4-byte special-purpose registers:
- // 68-75 cr0-7
- // 76: xer
- AssignToArrayRange(Builder, Address, Four8, 68, 76);
-
- // 77-108: v0-31, the 16-byte vector registers
- AssignToArrayRange(Builder, Address, Sixteen8, 77, 108);
-
- // 109: vrsave
- // 110: vscr
- // 111: spe_acc
- // 112: spefscr
- // 113: sfp
- // 114: tfhar
- // 115: tfiar
- // 116: texasr
- AssignToArrayRange(Builder, Address, Eight8, 109, 116);
-
- return false;
-}
-
-bool
-PPC64_SVR4_TargetCodeGenInfo::initDwarfEHRegSizeTable(
- CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
-
- return PPC64_initDwarfEHRegSizeTable(CGF, Address);
-}
-
-bool
-PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
-
- return PPC64_initDwarfEHRegSizeTable(CGF, Address);
-}
-
-//===----------------------------------------------------------------------===//
-// AArch64 ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class AArch64ABIInfo : public SwiftABIInfo {
-public:
- enum ABIKind {
- AAPCS = 0,
- DarwinPCS,
- Win64
- };
-
-private:
- ABIKind Kind;
-
-public:
- AArch64ABIInfo(CodeGenTypes &CGT, ABIKind Kind)
- : SwiftABIInfo(CGT), Kind(Kind) {}
-
-private:
- ABIKind getABIKind() const { return Kind; }
- bool isDarwinPCS() const { return Kind == DarwinPCS; }
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
- bool isHomogeneousAggregateBaseType(QualType Ty) const override;
- bool isHomogeneousAggregateSmallEnough(const Type *Ty,
- uint64_t Members) const override;
-
- bool isIllegalVectorType(QualType Ty) const;
-
- void computeInfo(CGFunctionInfo &FI) const override {
- if (!::classifyReturnType(getCXXABI(), FI, *this))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
-
- for (auto &it : FI.arguments())
- it.info = classifyArgumentType(it.type);
- }
-
- Address EmitDarwinVAArg(Address VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-
- Address EmitAAPCSVAArg(Address VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override {
- return Kind == Win64 ? EmitMSVAArg(CGF, VAListAddr, Ty)
- : isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
- : EmitAAPCSVAArg(VAListAddr, Ty, CGF);
- }
-
- Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return true;
- }
-
- bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
- unsigned elts) const override;
-};
-
-class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- AArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind Kind)
- : TargetCodeGenInfo(new AArch64ABIInfo(CGT, Kind)) {}
-
- StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
- return "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue";
- }
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
- return 31;
- }
-
- bool doesReturnSlotInterfereWithArgs() const override { return false; }
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD)
- return;
- llvm::Function *Fn = cast<llvm::Function>(GV);
-
- auto Kind = CGM.getCodeGenOpts().getSignReturnAddress();
- if (Kind != CodeGenOptions::SignReturnAddressScope::None) {
- Fn->addFnAttr("sign-return-address",
- Kind == CodeGenOptions::SignReturnAddressScope::All
- ? "all"
- : "non-leaf");
-
- auto Key = CGM.getCodeGenOpts().getSignReturnAddressKey();
- Fn->addFnAttr("sign-return-address-key",
- Key == CodeGenOptions::SignReturnAddressKeyValue::AKey
- ? "a_key"
- : "b_key");
- }
-
- if (CGM.getCodeGenOpts().BranchTargetEnforcement)
- Fn->addFnAttr("branch-target-enforcement");
- }
-};
-
-class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
-public:
- WindowsAArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind K)
- : AArch64TargetCodeGenInfo(CGT, K) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
-
- void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const override {
- Opt = "/DEFAULTLIB:" + qualifyWindowsLibrary(Lib);
- }
-
- void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const override {
- Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
- }
-};
-
-void WindowsAArch64TargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
- AArch64TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
- if (GV->isDeclaration())
- return;
- addStackProbeTargetAttributes(D, GV, CGM);
-}
-}
-
-ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- // Handle illegal vector types here.
- if (isIllegalVectorType(Ty)) {
- uint64_t Size = getContext().getTypeSize(Ty);
- // Android promotes <2 x i8> to i16, not i32
- if (isAndroid() && (Size <= 16)) {
- llvm::Type *ResType = llvm::Type::getInt16Ty(getVMContext());
- return ABIArgInfo::getDirect(ResType);
- }
- if (Size <= 32) {
- llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext());
- return ABIArgInfo::getDirect(ResType);
- }
- if (Size == 64) {
- llvm::Type *ResType =
- llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2);
- return ABIArgInfo::getDirect(ResType);
- }
- if (Size == 128) {
- llvm::Type *ResType =
- llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4);
- return ABIArgInfo::getDirect(ResType);
- }
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
- }
-
- if (!isAggregateTypeForABI(Ty)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- return (Ty->isPromotableIntegerType() && isDarwinPCS()
- ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
- }
-
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
- return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
- CGCXXABI::RAA_DirectInMemory);
- }
-
- // Empty records are always ignored on Darwin, but actually passed in C++ mode
- // elsewhere for GNU compatibility.
- uint64_t Size = getContext().getTypeSize(Ty);
- bool IsEmpty = isEmptyRecord(getContext(), Ty, true);
- if (IsEmpty || Size == 0) {
- if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS())
- return ABIArgInfo::getIgnore();
-
- // GNU C mode. The only argument that gets ignored is an empty one with size
- // 0.
- if (IsEmpty && Size == 0)
- return ABIArgInfo::getIgnore();
- return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
- }
-
- // Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (isHomogeneousAggregate(Ty, Base, Members)) {
- return ABIArgInfo::getDirect(
- llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members));
- }
-
- // Aggregates <= 16 bytes are passed directly in registers or on the stack.
- if (Size <= 128) {
- // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
- // same size and alignment.
- if (getTarget().isRenderScriptTarget()) {
- return coerceToIntArray(Ty, getContext(), getVMContext());
- }
- unsigned Alignment;
- if (Kind == AArch64ABIInfo::AAPCS) {
- Alignment = getContext().getTypeUnadjustedAlign(Ty);
- Alignment = Alignment < 128 ? 64 : 128;
- } else {
- Alignment = getContext().getTypeAlign(Ty);
- }
- Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes
-
- // We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
- // For aggregates with 16-byte alignment, we use i128.
- if (Alignment < 128 && Size == 128) {
- llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext());
- return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
- }
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
- }
-
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-}
-
-ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- // Large vector types should be returned via memory.
- if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128)
- return getNaturalAlignIndirect(RetTy);
-
- if (!isAggregateTypeForABI(RetTy)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- return (RetTy->isPromotableIntegerType() && isDarwinPCS()
- ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
- }
-
- uint64_t Size = getContext().getTypeSize(RetTy);
- if (isEmptyRecord(getContext(), RetTy, true) || Size == 0)
- return ABIArgInfo::getIgnore();
-
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (isHomogeneousAggregate(RetTy, Base, Members))
- // Homogeneous Floating-point Aggregates (HFAs) are returned directly.
- return ABIArgInfo::getDirect();
-
- // Aggregates <= 16 bytes are returned directly in registers or on the stack.
- if (Size <= 128) {
- // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
- // same size and alignment.
- if (getTarget().isRenderScriptTarget()) {
- return coerceToIntArray(RetTy, getContext(), getVMContext());
- }
- unsigned Alignment = getContext().getTypeAlign(RetTy);
- Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes
-
- // We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
- // For aggregates with 16-byte alignment, we use i128.
- if (Alignment < 128 && Size == 128) {
- llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext());
- return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
- }
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
- }
-
- return getNaturalAlignIndirect(RetTy);
-}
-
-/// isIllegalVectorType - check whether the vector type is legal for AArch64.
-bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- // Check whether VT is legal.
- unsigned NumElements = VT->getNumElements();
- uint64_t Size = getContext().getTypeSize(VT);
- // NumElements should be power of 2.
- if (!llvm::isPowerOf2_32(NumElements))
- return true;
- return Size != 64 && (Size != 128 || NumElements == 1);
- }
- return false;
-}
-
-bool AArch64ABIInfo::isLegalVectorTypeForSwift(CharUnits totalSize,
- llvm::Type *eltTy,
- unsigned elts) const {
- if (!llvm::isPowerOf2_32(elts))
- return false;
- if (totalSize.getQuantity() != 8 &&
- (totalSize.getQuantity() != 16 || elts == 1))
- return false;
- return true;
-}
-
-bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
- // Homogeneous aggregates for AAPCS64 must have base types of a floating
- // point type or a short-vector type. This is the same as the 32-bit ABI,
- // but with the difference that any floating-point type is allowed,
- // including __fp16.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->isFloatingPoint())
- return true;
- } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
- unsigned VecSize = getContext().getTypeSize(VT);
- if (VecSize == 64 || VecSize == 128)
- return true;
- }
- return false;
-}
-
-bool AArch64ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base,
- uint64_t Members) const {
- return Members <= 4;
-}
-
-Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr,
- QualType Ty,
- CodeGenFunction &CGF) const {
- ABIArgInfo AI = classifyArgumentType(Ty);
- bool IsIndirect = AI.isIndirect();
-
- llvm::Type *BaseTy = CGF.ConvertType(Ty);
- if (IsIndirect)
- BaseTy = llvm::PointerType::getUnqual(BaseTy);
- else if (AI.getCoerceToType())
- BaseTy = AI.getCoerceToType();
-
- unsigned NumRegs = 1;
- if (llvm::ArrayType *ArrTy = dyn_cast<llvm::ArrayType>(BaseTy)) {
- BaseTy = ArrTy->getElementType();
- NumRegs = ArrTy->getNumElements();
- }
- bool IsFPR = BaseTy->isFloatingPointTy() || BaseTy->isVectorTy();
-
- // The AArch64 va_list type and handling is specified in the Procedure Call
- // Standard, section B.4:
- //
- // struct {
- // void *__stack;
- // void *__gr_top;
- // void *__vr_top;
- // int __gr_offs;
- // int __vr_offs;
- // };
-
- llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg");
- llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
- llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
-
- auto TyInfo = getContext().getTypeInfoInChars(Ty);
- CharUnits TyAlign = TyInfo.second;
-
- Address reg_offs_p = Address::invalid();
- llvm::Value *reg_offs = nullptr;
- int reg_top_index;
- CharUnits reg_top_offset;
- int RegSize = IsIndirect ? 8 : TyInfo.first.getQuantity();
- if (!IsFPR) {
- // 3 is the field number of __gr_offs
- reg_offs_p =
- CGF.Builder.CreateStructGEP(VAListAddr, 3, CharUnits::fromQuantity(24),
- "gr_offs_p");
- reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs");
- reg_top_index = 1; // field number for __gr_top
- reg_top_offset = CharUnits::fromQuantity(8);
- RegSize = llvm::alignTo(RegSize, 8);
- } else {
- // 4 is the field number of __vr_offs.
- reg_offs_p =
- CGF.Builder.CreateStructGEP(VAListAddr, 4, CharUnits::fromQuantity(28),
- "vr_offs_p");
- reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs");
- reg_top_index = 2; // field number for __vr_top
- reg_top_offset = CharUnits::fromQuantity(16);
- RegSize = 16 * NumRegs;
- }
-
- //=======================================
- // Find out where argument was passed
- //=======================================
-
- // If reg_offs >= 0 we're already using the stack for this type of
- // argument. We don't want to keep updating reg_offs (in case it overflows,
- // though anyone passing 2GB of arguments, each at most 16 bytes, deserves
- // whatever they get).
- llvm::Value *UsingStack = nullptr;
- UsingStack = CGF.Builder.CreateICmpSGE(
- reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, 0));
-
- CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock);
-
- // Otherwise, at least some kind of argument could go in these registers, the
- // question is whether this particular type is too big.
- CGF.EmitBlock(MaybeRegBlock);
-
- // Integer arguments may need to correct register alignment (for example a
- // "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we
- // align __gr_offs to calculate the potential address.
- if (!IsFPR && !IsIndirect && TyAlign.getQuantity() > 8) {
- int Align = TyAlign.getQuantity();
-
- reg_offs = CGF.Builder.CreateAdd(
- reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, Align - 1),
- "align_regoffs");
- reg_offs = CGF.Builder.CreateAnd(
- reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, -Align),
- "aligned_regoffs");
- }
-
- // Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list.
- // The fact that this is done unconditionally reflects the fact that
- // allocating an argument to the stack also uses up all the remaining
- // registers of the appropriate kind.
- llvm::Value *NewOffset = nullptr;
- NewOffset = CGF.Builder.CreateAdd(
- reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, RegSize), "new_reg_offs");
- CGF.Builder.CreateStore(NewOffset, reg_offs_p);
-
- // Now we're in a position to decide whether this argument really was in
- // registers or not.
- llvm::Value *InRegs = nullptr;
- InRegs = CGF.Builder.CreateICmpSLE(
- NewOffset, llvm::ConstantInt::get(CGF.Int32Ty, 0), "inreg");
-
- CGF.Builder.CreateCondBr(InRegs, InRegBlock, OnStackBlock);
-
- //=======================================
- // Argument was in registers
- //=======================================
-
- // Now we emit the code for if the argument was originally passed in
- // registers. First start the appropriate block:
- CGF.EmitBlock(InRegBlock);
-
- llvm::Value *reg_top = nullptr;
- Address reg_top_p = CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index,
- reg_top_offset, "reg_top_p");
- reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top");
- Address BaseAddr(CGF.Builder.CreateInBoundsGEP(reg_top, reg_offs),
- CharUnits::fromQuantity(IsFPR ? 16 : 8));
- Address RegAddr = Address::invalid();
- llvm::Type *MemTy = CGF.ConvertTypeForMem(Ty);
-
- if (IsIndirect) {
- // If it's been passed indirectly (actually a struct), whatever we find from
- // stored registers or on the stack will actually be a struct **.
- MemTy = llvm::PointerType::getUnqual(MemTy);
- }
-
- const Type *Base = nullptr;
- uint64_t NumMembers = 0;
- bool IsHFA = isHomogeneousAggregate(Ty, Base, NumMembers);
- if (IsHFA && NumMembers > 1) {
- // Homogeneous aggregates passed in registers will have their elements split
- // and stored 16-bytes apart regardless of size (they're notionally in qN,
- // qN+1, ...). We reload and store into a temporary local variable
- // contiguously.
- assert(!IsIndirect && "Homogeneous aggregates should be passed directly");
- auto BaseTyInfo = getContext().getTypeInfoInChars(QualType(Base, 0));
- llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0));
- llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers);
- Address Tmp = CGF.CreateTempAlloca(HFATy,
- std::max(TyAlign, BaseTyInfo.second));
-
- // On big-endian platforms, the value will be right-aligned in its slot.
- int Offset = 0;
- if (CGF.CGM.getDataLayout().isBigEndian() &&
- BaseTyInfo.first.getQuantity() < 16)
- Offset = 16 - BaseTyInfo.first.getQuantity();
-
- for (unsigned i = 0; i < NumMembers; ++i) {
- CharUnits BaseOffset = CharUnits::fromQuantity(16 * i + Offset);
- Address LoadAddr =
- CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, BaseOffset);
- LoadAddr = CGF.Builder.CreateElementBitCast(LoadAddr, BaseTy);
-
- Address StoreAddr =
- CGF.Builder.CreateConstArrayGEP(Tmp, i, BaseTyInfo.first);
-
- llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr);
- CGF.Builder.CreateStore(Elem, StoreAddr);
- }
-
- RegAddr = CGF.Builder.CreateElementBitCast(Tmp, MemTy);
- } else {
- // Otherwise the object is contiguous in memory.
-
- // It might be right-aligned in its slot.
- CharUnits SlotSize = BaseAddr.getAlignment();
- if (CGF.CGM.getDataLayout().isBigEndian() && !IsIndirect &&
- (IsHFA || !isAggregateTypeForABI(Ty)) &&
- TyInfo.first < SlotSize) {
- CharUnits Offset = SlotSize - TyInfo.first;
- BaseAddr = CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, Offset);
- }
-
- RegAddr = CGF.Builder.CreateElementBitCast(BaseAddr, MemTy);
- }
-
- CGF.EmitBranch(ContBlock);
-
- //=======================================
- // Argument was on the stack
- //=======================================
- CGF.EmitBlock(OnStackBlock);
-
- Address stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0,
- CharUnits::Zero(), "stack_p");
- llvm::Value *OnStackPtr = CGF.Builder.CreateLoad(stack_p, "stack");
-
- // Again, stack arguments may need realignment. In this case both integer and
- // floating-point ones might be affected.
- if (!IsIndirect && TyAlign.getQuantity() > 8) {
- int Align = TyAlign.getQuantity();
-
- OnStackPtr = CGF.Builder.CreatePtrToInt(OnStackPtr, CGF.Int64Ty);
-
- OnStackPtr = CGF.Builder.CreateAdd(
- OnStackPtr, llvm::ConstantInt::get(CGF.Int64Ty, Align - 1),
- "align_stack");
- OnStackPtr = CGF.Builder.CreateAnd(
- OnStackPtr, llvm::ConstantInt::get(CGF.Int64Ty, -Align),
- "align_stack");
-
- OnStackPtr = CGF.Builder.CreateIntToPtr(OnStackPtr, CGF.Int8PtrTy);
- }
- Address OnStackAddr(OnStackPtr,
- std::max(CharUnits::fromQuantity(8), TyAlign));
-
- // All stack slots are multiples of 8 bytes.
- CharUnits StackSlotSize = CharUnits::fromQuantity(8);
- CharUnits StackSize;
- if (IsIndirect)
- StackSize = StackSlotSize;
- else
- StackSize = TyInfo.first.alignTo(StackSlotSize);
-
- llvm::Value *StackSizeC = CGF.Builder.getSize(StackSize);
- llvm::Value *NewStack =
- CGF.Builder.CreateInBoundsGEP(OnStackPtr, StackSizeC, "new_stack");
-
- // Write the new value of __stack for the next call to va_arg
- CGF.Builder.CreateStore(NewStack, stack_p);
-
- if (CGF.CGM.getDataLayout().isBigEndian() && !isAggregateTypeForABI(Ty) &&
- TyInfo.first < StackSlotSize) {
- CharUnits Offset = StackSlotSize - TyInfo.first;
- OnStackAddr = CGF.Builder.CreateConstInBoundsByteGEP(OnStackAddr, Offset);
- }
-
- OnStackAddr = CGF.Builder.CreateElementBitCast(OnStackAddr, MemTy);
-
- CGF.EmitBranch(ContBlock);
-
- //=======================================
- // Tidy up
- //=======================================
- CGF.EmitBlock(ContBlock);
-
- Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock,
- OnStackAddr, OnStackBlock, "vaargs.addr");
-
- if (IsIndirect)
- return Address(CGF.Builder.CreateLoad(ResAddr, "vaarg.addr"),
- TyInfo.second);
-
- return ResAddr;
-}
-
-Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- // The backend's lowering doesn't support va_arg for aggregates or
- // illegal vector types. Lower VAArg here for these cases and use
- // the LLVM va_arg instruction for everything else.
- if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty))
- return EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect());
-
- CharUnits SlotSize = CharUnits::fromQuantity(8);
-
- // Empty records are ignored for parameter passing purposes.
- if (isEmptyRecord(getContext(), Ty, true)) {
- Address Addr(CGF.Builder.CreateLoad(VAListAddr, "ap.cur"), SlotSize);
- Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty));
- return Addr;
- }
-
- // The size of the actual thing passed, which might end up just
- // being a pointer for indirect types.
- auto TyInfo = getContext().getTypeInfoInChars(Ty);
-
- // Arguments bigger than 16 bytes which aren't homogeneous
- // aggregates should be passed indirectly.
- bool IsIndirect = false;
- if (TyInfo.first.getQuantity() > 16) {
- const Type *Base = nullptr;
- uint64_t Members = 0;
- IsIndirect = !isHomogeneousAggregate(Ty, Base, Members);
- }
-
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
- TyInfo, SlotSize, /*AllowHigherAlign*/ true);
-}
-
-Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
- CGF.getContext().getTypeInfoInChars(Ty),
- CharUnits::fromQuantity(8),
- /*allowHigherAlign*/ false);
-}
-
-//===----------------------------------------------------------------------===//
-// ARM ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class ARMABIInfo : public SwiftABIInfo {
-public:
- enum ABIKind {
- APCS = 0,
- AAPCS = 1,
- AAPCS_VFP = 2,
- AAPCS16_VFP = 3,
- };
-
-private:
- ABIKind Kind;
-
-public:
- ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind)
- : SwiftABIInfo(CGT), Kind(_Kind) {
- setCCs();
- }
-
- bool isEABI() const {
- switch (getTarget().getTriple().getEnvironment()) {
- case llvm::Triple::Android:
- case llvm::Triple::EABI:
- case llvm::Triple::EABIHF:
- case llvm::Triple::GNUEABI:
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::MuslEABI:
- case llvm::Triple::MuslEABIHF:
- return true;
- default:
- return false;
- }
- }
-
- bool isEABIHF() const {
- switch (getTarget().getTriple().getEnvironment()) {
- case llvm::Triple::EABIHF:
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::MuslEABIHF:
- return true;
- default:
- return false;
- }
- }
-
- ABIKind getABIKind() const { return Kind; }
-
-private:
- ABIArgInfo classifyReturnType(QualType RetTy, bool isVariadic) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, bool isVariadic) const;
- ABIArgInfo classifyHomogeneousAggregate(QualType Ty, const Type *Base,
- uint64_t Members) const;
- ABIArgInfo coerceIllegalVector(QualType Ty) const;
- bool isIllegalVectorType(QualType Ty) const;
-
- bool isHomogeneousAggregateBaseType(QualType Ty) const override;
- bool isHomogeneousAggregateSmallEnough(const Type *Ty,
- uint64_t Members) const override;
-
- void computeInfo(CGFunctionInfo &FI) const override;
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- llvm::CallingConv::ID getLLVMDefaultCC() const;
- llvm::CallingConv::ID getABIDefaultCC() const;
- void setCCs();
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return true;
- }
- bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
- unsigned elts) const override;
-};
-
-class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- ARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K)
- :TargetCodeGenInfo(new ARMABIInfo(CGT, K)) {}
-
- const ARMABIInfo &getABIInfo() const {
- return static_cast<const ARMABIInfo&>(TargetCodeGenInfo::getABIInfo());
- }
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
- return 13;
- }
-
- StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
- return "mov\tr7, r7\t\t// marker for objc_retainAutoreleaseReturnValue";
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override {
- llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);
-
- // 0-15 are the 16 integer registers.
- AssignToArrayRange(CGF.Builder, Address, Four8, 0, 15);
- return false;
- }
-
- unsigned getSizeOfUnwindException() const override {
- if (getABIInfo().isEABI()) return 88;
- return TargetCodeGenInfo::getSizeOfUnwindException();
- }
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
- if (GV->isDeclaration())
- return;
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD)
- return;
-
- const ARMInterruptAttr *Attr = FD->getAttr<ARMInterruptAttr>();
- if (!Attr)
- return;
-
- const char *Kind;
- switch (Attr->getInterrupt()) {
- case ARMInterruptAttr::Generic: Kind = ""; break;
- case ARMInterruptAttr::IRQ: Kind = "IRQ"; break;
- case ARMInterruptAttr::FIQ: Kind = "FIQ"; break;
- case ARMInterruptAttr::SWI: Kind = "SWI"; break;
- case ARMInterruptAttr::ABORT: Kind = "ABORT"; break;
- case ARMInterruptAttr::UNDEF: Kind = "UNDEF"; break;
- }
-
- llvm::Function *Fn = cast<llvm::Function>(GV);
-
- Fn->addFnAttr("interrupt", Kind);
-
- ARMABIInfo::ABIKind ABI = cast<ARMABIInfo>(getABIInfo()).getABIKind();
- if (ABI == ARMABIInfo::APCS)
- return;
-
- // AAPCS guarantees that sp will be 8-byte aligned on any public interface,
- // however this is not necessarily true on taking any interrupt. Instruct
- // the backend to perform a realignment as part of the function prologue.
- llvm::AttrBuilder B;
- B.addStackAlignmentAttr(8);
- Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
- }
-};
-
-class WindowsARMTargetCodeGenInfo : public ARMTargetCodeGenInfo {
-public:
- WindowsARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K)
- : ARMTargetCodeGenInfo(CGT, K) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
-
- void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const override {
- Opt = "/DEFAULTLIB:" + qualifyWindowsLibrary(Lib);
- }
-
- void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const override {
- Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
- }
-};
-
-void WindowsARMTargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
- ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
- if (GV->isDeclaration())
- return;
- addStackProbeTargetAttributes(D, GV, CGM);
-}
-}
-
-void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
- if (!::classifyReturnType(getCXXABI(), FI, *this))
- FI.getReturnInfo() =
- classifyReturnType(FI.getReturnType(), FI.isVariadic());
-
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type, FI.isVariadic());
-
- // Always honor user-specified calling convention.
- if (FI.getCallingConvention() != llvm::CallingConv::C)
- return;
-
- llvm::CallingConv::ID cc = getRuntimeCC();
- if (cc != llvm::CallingConv::C)
- FI.setEffectiveCallingConvention(cc);
-}
-
-/// Return the default calling convention that LLVM will use.
-llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
- // The default calling convention that LLVM will infer.
- if (isEABIHF() || getTarget().getTriple().isWatchABI())
- return llvm::CallingConv::ARM_AAPCS_VFP;
- else if (isEABI())
- return llvm::CallingConv::ARM_AAPCS;
- else
- return llvm::CallingConv::ARM_APCS;
-}
-
-/// Return the calling convention that our ABI would like us to use
-/// as the C calling convention.
-llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC() const {
- switch (getABIKind()) {
- case APCS: return llvm::CallingConv::ARM_APCS;
- case AAPCS: return llvm::CallingConv::ARM_AAPCS;
- case AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
- case AAPCS16_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
- }
- llvm_unreachable("bad ABI kind");
-}
-
-void ARMABIInfo::setCCs() {
- assert(getRuntimeCC() == llvm::CallingConv::C);
-
- // Don't muddy up the IR with a ton of explicit annotations if
- // they'd just match what LLVM will infer from the triple.
- llvm::CallingConv::ID abiCC = getABIDefaultCC();
- if (abiCC != getLLVMDefaultCC())
- RuntimeCC = abiCC;
-}
-
-ABIArgInfo ARMABIInfo::coerceIllegalVector(QualType Ty) const {
- uint64_t Size = getContext().getTypeSize(Ty);
- if (Size <= 32) {
- llvm::Type *ResType =
- llvm::Type::getInt32Ty(getVMContext());
- return ABIArgInfo::getDirect(ResType);
- }
- if (Size == 64 || Size == 128) {
- llvm::Type *ResType = llvm::VectorType::get(
- llvm::Type::getInt32Ty(getVMContext()), Size / 32);
- return ABIArgInfo::getDirect(ResType);
- }
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-}
-
-ABIArgInfo ARMABIInfo::classifyHomogeneousAggregate(QualType Ty,
- const Type *Base,
- uint64_t Members) const {
- assert(Base && "Base class should be set for homogeneous aggregate");
- // Base can be a floating-point or a vector.
- if (const VectorType *VT = Base->getAs<VectorType>()) {
- // FP16 vectors should be converted to integer vectors
- if (!getTarget().hasLegalHalfType() &&
- (VT->getElementType()->isFloat16Type() ||
- VT->getElementType()->isHalfType())) {
- uint64_t Size = getContext().getTypeSize(VT);
- llvm::Type *NewVecTy = llvm::VectorType::get(
- llvm::Type::getInt32Ty(getVMContext()), Size / 32);
- llvm::Type *Ty = llvm::ArrayType::get(NewVecTy, Members);
- return ABIArgInfo::getDirect(Ty, 0, nullptr, false);
- }
- }
- return ABIArgInfo::getDirect(nullptr, 0, nullptr, false);
-}
-
-ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
- bool isVariadic) const {
- // 6.1.2.1 The following argument types are VFP CPRCs:
- // A single-precision floating-point type (including promoted
- // half-precision types); A double-precision floating-point type;
- // A 64-bit or 128-bit containerized vector type; Homogeneous Aggregate
- // with a Base Type of a single- or double-precision floating-point type,
- // 64-bit containerized vectors or 128-bit containerized vectors with one
- // to four Elements.
- bool IsEffectivelyAAPCS_VFP = getABIKind() == AAPCS_VFP && !isVariadic;
-
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- // Handle illegal vector types here.
- if (isIllegalVectorType(Ty))
- return coerceIllegalVector(Ty);
-
- // _Float16 and __fp16 get passed as if it were an int or float, but with
- // the top 16 bits unspecified. This is not done for OpenCL as it handles the
- // half type natively, and does not need to interwork with AAPCS code.
- if ((Ty->isFloat16Type() || Ty->isHalfType()) &&
- !getContext().getLangOpts().NativeHalfArgsAndReturns) {
- llvm::Type *ResType = IsEffectivelyAAPCS_VFP ?
- llvm::Type::getFloatTy(getVMContext()) :
- llvm::Type::getInt32Ty(getVMContext());
- return ABIArgInfo::getDirect(ResType);
- }
-
- if (!isAggregateTypeForABI(Ty)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>()) {
- Ty = EnumTy->getDecl()->getIntegerType();
- }
-
- return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
- }
-
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
- }
-
- // Ignore empty records.
- if (isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
-
- if (IsEffectivelyAAPCS_VFP) {
- // Homogeneous Aggregates need to be expanded when we can fit the aggregate
- // into VFP registers.
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (isHomogeneousAggregate(Ty, Base, Members))
- return classifyHomogeneousAggregate(Ty, Base, Members);
- } else if (getABIKind() == ARMABIInfo::AAPCS16_VFP) {
- // WatchOS does have homogeneous aggregates. Note that we intentionally use
- // this convention even for a variadic function: the backend will use GPRs
- // if needed.
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (isHomogeneousAggregate(Ty, Base, Members)) {
- assert(Base && Members <= 4 && "unexpected homogeneous aggregate");
- llvm::Type *Ty =
- llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members);
- return ABIArgInfo::getDirect(Ty, 0, nullptr, false);
- }
- }
-
- if (getABIKind() == ARMABIInfo::AAPCS16_VFP &&
- getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(16)) {
- // WatchOS is adopting the 64-bit AAPCS rule on composite types: if they're
- // bigger than 128-bits, they get placed in space allocated by the caller,
- // and a pointer is passed.
- return ABIArgInfo::getIndirect(
- CharUnits::fromQuantity(getContext().getTypeAlign(Ty) / 8), false);
- }
-
- // Support byval for ARM.
- // The ABI alignment for APCS is 4-byte and for AAPCS at least 4-byte and at
- // most 8-byte. We realign the indirect argument if type alignment is bigger
- // than ABI alignment.
- uint64_t ABIAlign = 4;
- uint64_t TyAlign;
- if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
- getABIKind() == ARMABIInfo::AAPCS) {
- TyAlign = getContext().getTypeUnadjustedAlignInChars(Ty).getQuantity();
- ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
- } else {
- TyAlign = getContext().getTypeAlignInChars(Ty).getQuantity();
- }
- if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) {
- assert(getABIKind() != ARMABIInfo::AAPCS16_VFP && "unexpected byval");
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(ABIAlign),
- /*ByVal=*/true,
- /*Realign=*/TyAlign > ABIAlign);
- }
-
- // On RenderScript, coerce Aggregates <= 64 bytes to an integer array of
- // same size and alignment.
- if (getTarget().isRenderScriptTarget()) {
- return coerceToIntArray(Ty, getContext(), getVMContext());
- }
-
- // Otherwise, pass by coercing to a structure of the appropriate size.
- llvm::Type* ElemTy;
- unsigned SizeRegs;
- // FIXME: Try to match the types of the arguments more accurately where
- // we can.
- if (TyAlign <= 4) {
- ElemTy = llvm::Type::getInt32Ty(getVMContext());
- SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32;
- } else {
- ElemTy = llvm::Type::getInt64Ty(getVMContext());
- SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64;
- }
-
- return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, SizeRegs));
-}
-
-static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
- llvm::LLVMContext &VMContext) {
- // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure
- // is called integer-like if its size is less than or equal to one word, and
- // the offset of each of its addressable sub-fields is zero.
-
- uint64_t Size = Context.getTypeSize(Ty);
-
- // Check that the type fits in a word.
- if (Size > 32)
- return false;
-
- // FIXME: Handle vector types!
- if (Ty->isVectorType())
- return false;
-
- // Float types are never treated as "integer like".
- if (Ty->isRealFloatingType())
- return false;
-
- // If this is a builtin or pointer type then it is ok.
- if (Ty->getAs<BuiltinType>() || Ty->isPointerType())
- return true;
-
- // Small complex integer types are "integer like".
- if (const ComplexType *CT = Ty->getAs<ComplexType>())
- return isIntegerLikeType(CT->getElementType(), Context, VMContext);
-
- // Single element and zero sized arrays should be allowed, by the definition
- // above, but they are not.
-
- // Otherwise, it must be a record type.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT) return false;
-
- // Ignore records with flexible arrays.
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return false;
-
- // Check that all sub-fields are at offset 0, and are themselves "integer
- // like".
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- bool HadField = false;
- unsigned idx = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i, ++idx) {
- const FieldDecl *FD = *i;
-
- // Bit-fields are not addressable, we only need to verify they are "integer
- // like". We still have to disallow a subsequent non-bitfield, for example:
- // struct { int : 0; int x }
- // is non-integer like according to gcc.
- if (FD->isBitField()) {
- if (!RD->isUnion())
- HadField = true;
-
- if (!isIntegerLikeType(FD->getType(), Context, VMContext))
- return false;
-
- continue;
- }
-
- // Check if this field is at offset 0.
- if (Layout.getFieldOffset(idx) != 0)
- return false;
-
- if (!isIntegerLikeType(FD->getType(), Context, VMContext))
- return false;
-
- // Only allow at most one field in a structure. This doesn't match the
- // wording above, but follows gcc in situations with a field following an
- // empty structure.
- if (!RD->isUnion()) {
- if (HadField)
- return false;
-
- HadField = true;
- }
- }
-
- return true;
-}
-
-ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
- bool isVariadic) const {
- bool IsEffectivelyAAPCS_VFP =
- (getABIKind() == AAPCS_VFP || getABIKind() == AAPCS16_VFP) && !isVariadic;
-
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- if (const VectorType *VT = RetTy->getAs<VectorType>()) {
- // Large vector types should be returned via memory.
- if (getContext().getTypeSize(RetTy) > 128)
- return getNaturalAlignIndirect(RetTy);
- // FP16 vectors should be converted to integer vectors
- if (!getTarget().hasLegalHalfType() &&
- (VT->getElementType()->isFloat16Type() ||
- VT->getElementType()->isHalfType()))
- return coerceIllegalVector(RetTy);
- }
-
- // _Float16 and __fp16 get returned as if it were an int or float, but with
- // the top 16 bits unspecified. This is not done for OpenCL as it handles the
- // half type natively, and does not need to interwork with AAPCS code.
- if ((RetTy->isFloat16Type() || RetTy->isHalfType()) &&
- !getContext().getLangOpts().NativeHalfArgsAndReturns) {
- llvm::Type *ResType = IsEffectivelyAAPCS_VFP ?
- llvm::Type::getFloatTy(getVMContext()) :
- llvm::Type::getInt32Ty(getVMContext());
- return ABIArgInfo::getDirect(ResType);
- }
-
- if (!isAggregateTypeForABI(RetTy)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- return RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect();
- }
-
- // Are we following APCS?
- if (getABIKind() == APCS) {
- if (isEmptyRecord(getContext(), RetTy, false))
- return ABIArgInfo::getIgnore();
-
- // Complex types are all returned as packed integers.
- //
- // FIXME: Consider using 2 x vector types if the back end handles them
- // correctly.
- if (RetTy->isAnyComplexType())
- return ABIArgInfo::getDirect(llvm::IntegerType::get(
- getVMContext(), getContext().getTypeSize(RetTy)));
-
- // Integer like structures are returned in r0.
- if (isIntegerLikeType(RetTy, getContext(), getVMContext())) {
- // Return in the smallest viable integer type.
- uint64_t Size = getContext().getTypeSize(RetTy);
- if (Size <= 8)
- return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
- if (Size <= 16)
- return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
- return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
- }
-
- // Otherwise return in memory.
- return getNaturalAlignIndirect(RetTy);
- }
-
- // Otherwise this is an AAPCS variant.
-
- if (isEmptyRecord(getContext(), RetTy, true))
- return ABIArgInfo::getIgnore();
-
- // Check for homogeneous aggregates with AAPCS-VFP.
- if (IsEffectivelyAAPCS_VFP) {
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (isHomogeneousAggregate(RetTy, Base, Members))
- return classifyHomogeneousAggregate(RetTy, Base, Members);
- }
-
- // Aggregates <= 4 bytes are returned in r0; other aggregates
- // are returned indirectly.
- uint64_t Size = getContext().getTypeSize(RetTy);
- if (Size <= 32) {
- // On RenderScript, coerce Aggregates <= 4 bytes to an integer array of
- // same size and alignment.
- if (getTarget().isRenderScriptTarget()) {
- return coerceToIntArray(RetTy, getContext(), getVMContext());
- }
- if (getDataLayout().isBigEndian())
- // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4)
- return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
-
- // Return in the smallest viable integer type.
- if (Size <= 8)
- return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
- if (Size <= 16)
- return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
- return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
- } else if (Size <= 128 && getABIKind() == AAPCS16_VFP) {
- llvm::Type *Int32Ty = llvm::Type::getInt32Ty(getVMContext());
- llvm::Type *CoerceTy =
- llvm::ArrayType::get(Int32Ty, llvm::alignTo(Size, 32) / 32);
- return ABIArgInfo::getDirect(CoerceTy);
- }
-
- return getNaturalAlignIndirect(RetTy);
-}
-
-/// isIllegalVector - check whether Ty is an illegal vector type.
-bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
- if (const VectorType *VT = Ty->getAs<VectorType> ()) {
- // On targets that don't support FP16, FP16 is expanded into float, and we
- // don't want the ABI to depend on whether or not FP16 is supported in
- // hardware. Thus return false to coerce FP16 vectors into integer vectors.
- if (!getTarget().hasLegalHalfType() &&
- (VT->getElementType()->isFloat16Type() ||
- VT->getElementType()->isHalfType()))
- return true;
- if (isAndroid()) {
- // Android shipped using Clang 3.1, which supported a slightly different
- // vector ABI. The primary differences were that 3-element vector types
- // were legal, and so were sub 32-bit vectors (i.e. <2 x i8>). This path
- // accepts that legacy behavior for Android only.
- // Check whether VT is legal.
- unsigned NumElements = VT->getNumElements();
- // NumElements should be power of 2 or equal to 3.
- if (!llvm::isPowerOf2_32(NumElements) && NumElements != 3)
- return true;
- } else {
- // Check whether VT is legal.
- unsigned NumElements = VT->getNumElements();
- uint64_t Size = getContext().getTypeSize(VT);
- // NumElements should be power of 2.
- if (!llvm::isPowerOf2_32(NumElements))
- return true;
- // Size should be greater than 32 bits.
- return Size <= 32;
- }
- }
- return false;
-}
-
-bool ARMABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize,
- llvm::Type *eltTy,
- unsigned numElts) const {
- if (!llvm::isPowerOf2_32(numElts))
- return false;
- unsigned size = getDataLayout().getTypeStoreSizeInBits(eltTy);
- if (size > 64)
- return false;
- if (vectorSize.getQuantity() != 8 &&
- (vectorSize.getQuantity() != 16 || numElts == 1))
- return false;
- return true;
-}
-
-bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
- // Homogeneous aggregates for AAPCS-VFP must have base types of float,
- // double, or 64-bit or 128-bit vectors.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::Float ||
- BT->getKind() == BuiltinType::Double ||
- BT->getKind() == BuiltinType::LongDouble)
- return true;
- } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
- unsigned VecSize = getContext().getTypeSize(VT);
- if (VecSize == 64 || VecSize == 128)
- return true;
- }
- return false;
-}
-
-bool ARMABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base,
- uint64_t Members) const {
- return Members <= 4;
-}
-
-Address ARMABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- CharUnits SlotSize = CharUnits::fromQuantity(4);
-
- // Empty records are ignored for parameter passing purposes.
- if (isEmptyRecord(getContext(), Ty, true)) {
- Address Addr(CGF.Builder.CreateLoad(VAListAddr), SlotSize);
- Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty));
- return Addr;
- }
-
- auto TyInfo = getContext().getTypeInfoInChars(Ty);
- CharUnits TyAlignForABI = TyInfo.second;
-
- // Use indirect if size of the illegal vector is bigger than 16 bytes.
- bool IsIndirect = false;
- const Type *Base = nullptr;
- uint64_t Members = 0;
- if (TyInfo.first > CharUnits::fromQuantity(16) && isIllegalVectorType(Ty)) {
- IsIndirect = true;
-
- // ARMv7k passes structs bigger than 16 bytes indirectly, in space
- // allocated by the caller.
- } else if (TyInfo.first > CharUnits::fromQuantity(16) &&
- getABIKind() == ARMABIInfo::AAPCS16_VFP &&
- !isHomogeneousAggregate(Ty, Base, Members)) {
- IsIndirect = true;
-
- // Otherwise, bound the type's ABI alignment.
- // The ABI alignment for 64-bit or 128-bit vectors is 8 for AAPCS and 4 for
- // APCS. For AAPCS, the ABI alignment is at least 4-byte and at most 8-byte.
- // Our callers should be prepared to handle an under-aligned address.
- } else if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
- getABIKind() == ARMABIInfo::AAPCS) {
- TyAlignForABI = std::max(TyAlignForABI, CharUnits::fromQuantity(4));
- TyAlignForABI = std::min(TyAlignForABI, CharUnits::fromQuantity(8));
- } else if (getABIKind() == ARMABIInfo::AAPCS16_VFP) {
- // ARMv7k allows type alignment up to 16 bytes.
- TyAlignForABI = std::max(TyAlignForABI, CharUnits::fromQuantity(4));
- TyAlignForABI = std::min(TyAlignForABI, CharUnits::fromQuantity(16));
- } else {
- TyAlignForABI = CharUnits::fromQuantity(4);
- }
- TyInfo.second = TyAlignForABI;
-
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TyInfo,
- SlotSize, /*AllowHigherAlign*/ true);
-}
-
-//===----------------------------------------------------------------------===//
-// NVPTX ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class NVPTXABIInfo : public ABIInfo {
-public:
- NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType Ty) const;
-
- void computeInfo(CGFunctionInfo &FI) const override;
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-};
-
-class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- NVPTXTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
- bool shouldEmitStaticExternCAliases() const override;
-
-private:
- // Adds a NamedMDNode with F, Name, and Operand as operands, and adds the
- // resulting MDNode to the nvvm.annotations MDNode.
- static void addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand);
-};
-
-ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- // note: this is different from default ABI
- if (!RetTy->isScalarType())
- return ABIArgInfo::getDirect();
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
-}
-
-ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- // Return aggregates type as indirect by value
- if (isAggregateTypeForABI(Ty))
- return getNaturalAlignIndirect(Ty, /* byval */ true);
-
- return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
-}
-
-void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
-
- // Always honor user-specified calling convention.
- if (FI.getCallingConvention() != llvm::CallingConv::C)
- return;
-
- FI.setEffectiveCallingConvention(getRuntimeCC());
-}
-
-Address NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- llvm_unreachable("NVPTX does not support varargs");
-}
-
-void NVPTXTargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
- if (GV->isDeclaration())
- return;
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD) return;
-
- llvm::Function *F = cast<llvm::Function>(GV);
-
- // Perform special handling in OpenCL mode
- if (M.getLangOpts().OpenCL) {
- // Use OpenCL function attributes to check for kernel functions
- // By default, all functions are device functions
- if (FD->hasAttr<OpenCLKernelAttr>()) {
- // OpenCL __kernel functions get kernel metadata
- // Create !{<func-ref>, metadata !"kernel", i32 1} node
- addNVVMMetadata(F, "kernel", 1);
- // And kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attribute::NoInline);
- }
- }
-
- // Perform special handling in CUDA mode.
- if (M.getLangOpts().CUDA) {
- // CUDA __global__ functions get a kernel metadata entry. Since
- // __global__ functions cannot be called from the device, we do not
- // need to set the noinline attribute.
- if (FD->hasAttr<CUDAGlobalAttr>()) {
- // Create !{<func-ref>, metadata !"kernel", i32 1} node
- addNVVMMetadata(F, "kernel", 1);
- }
- if (CUDALaunchBoundsAttr *Attr = FD->getAttr<CUDALaunchBoundsAttr>()) {
- // Create !{<func-ref>, metadata !"maxntidx", i32 <val>} node
- llvm::APSInt MaxThreads(32);
- MaxThreads = Attr->getMaxThreads()->EvaluateKnownConstInt(M.getContext());
- if (MaxThreads > 0)
- addNVVMMetadata(F, "maxntidx", MaxThreads.getExtValue());
-
- // min blocks is an optional argument for CUDALaunchBoundsAttr. If it was
- // not specified in __launch_bounds__ or if the user specified a 0 value,
- // we don't have to add a PTX directive.
- if (Attr->getMinBlocks()) {
- llvm::APSInt MinBlocks(32);
- MinBlocks = Attr->getMinBlocks()->EvaluateKnownConstInt(M.getContext());
- if (MinBlocks > 0)
- // Create !{<func-ref>, metadata !"minctasm", i32 <val>} node
- addNVVMMetadata(F, "minctasm", MinBlocks.getExtValue());
- }
- }
- }
-}
-
-void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name,
- int Operand) {
- llvm::Module *M = F->getParent();
- llvm::LLVMContext &Ctx = M->getContext();
-
- // Get "nvvm.annotations" metadata node
- llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
-
- llvm::Metadata *MDVals[] = {
- llvm::ConstantAsMetadata::get(F), llvm::MDString::get(Ctx, Name),
- llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))};
- // Append metadata to nvvm.annotations
- MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
-}
-
-bool NVPTXTargetCodeGenInfo::shouldEmitStaticExternCAliases() const {
- return false;
-}
-}
-
-//===----------------------------------------------------------------------===//
-// SystemZ ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class SystemZABIInfo : public SwiftABIInfo {
- bool HasVector;
-
-public:
- SystemZABIInfo(CodeGenTypes &CGT, bool HV)
- : SwiftABIInfo(CGT), HasVector(HV) {}
-
- bool isPromotableIntegerType(QualType Ty) const;
- bool isCompoundType(QualType Ty) const;
- bool isVectorArgumentType(QualType Ty) const;
- bool isFPArgumentType(QualType Ty) const;
- QualType GetSingleElementType(QualType Ty) const;
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType ArgTy) const;
-
- void computeInfo(CGFunctionInfo &FI) const override {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
- }
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return false;
- }
-};
-
-class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector)
- : TargetCodeGenInfo(new SystemZABIInfo(CGT, HasVector)) {}
-};
-
-}
-
-bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- // Promotable integer types are required to be promoted by the ABI.
- if (Ty->isPromotableIntegerType())
- return true;
-
- // 32-bit values must also be promoted.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Int:
- case BuiltinType::UInt:
- return true;
- default:
- return false;
- }
- return false;
-}
-
-bool SystemZABIInfo::isCompoundType(QualType Ty) const {
- return (Ty->isAnyComplexType() ||
- Ty->isVectorType() ||
- isAggregateTypeForABI(Ty));
-}
-
-bool SystemZABIInfo::isVectorArgumentType(QualType Ty) const {
- return (HasVector &&
- Ty->isVectorType() &&
- getContext().getTypeSize(Ty) <= 128);
-}
-
-bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Float:
- case BuiltinType::Double:
- return true;
- default:
- return false;
- }
-
- return false;
-}
-
-QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const {
- if (const RecordType *RT = Ty->getAsStructureType()) {
- const RecordDecl *RD = RT->getDecl();
- QualType Found;
-
- // If this is a C++ record, check the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- for (const auto &I : CXXRD->bases()) {
- QualType Base = I.getType();
-
- // Empty bases don't affect things either way.
- if (isEmptyRecord(getContext(), Base, true))
- continue;
-
- if (!Found.isNull())
- return Ty;
- Found = GetSingleElementType(Base);
- }
-
- // Check the fields.
- for (const auto *FD : RD->fields()) {
- // For compatibility with GCC, ignore empty bitfields in C++ mode.
- // Unlike isSingleElementStruct(), empty structure and array fields
- // do count. So do anonymous bitfields that aren't zero-sized.
- if (getContext().getLangOpts().CPlusPlus &&
- FD->isZeroLengthBitField(getContext()))
- continue;
-
- // Unlike isSingleElementStruct(), arrays do not count.
- // Nested structures still do though.
- if (!Found.isNull())
- return Ty;
- Found = GetSingleElementType(FD->getType());
- }
-
- // Unlike isSingleElementStruct(), trailing padding is allowed.
- // An 8-byte aligned struct s { float f; } is passed as a double.
- if (!Found.isNull())
- return Found;
- }
-
- return Ty;
-}
-
-Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- // Assume that va_list type is correct; should be pointer to LLVM type:
- // struct {
- // i64 __gpr;
- // i64 __fpr;
- // i8 *__overflow_arg_area;
- // i8 *__reg_save_area;
- // };
-
- // Every non-vector argument occupies 8 bytes and is passed by preference
- // in either GPRs or FPRs. Vector arguments occupy 8 or 16 bytes and are
- // always passed on the stack.
- Ty = getContext().getCanonicalType(Ty);
- auto TyInfo = getContext().getTypeInfoInChars(Ty);
- llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty);
- llvm::Type *DirectTy = ArgTy;
- ABIArgInfo AI = classifyArgumentType(Ty);
- bool IsIndirect = AI.isIndirect();
- bool InFPRs = false;
- bool IsVector = false;
- CharUnits UnpaddedSize;
- CharUnits DirectAlign;
- if (IsIndirect) {
- DirectTy = llvm::PointerType::getUnqual(DirectTy);
- UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8);
- } else {
- if (AI.getCoerceToType())
- ArgTy = AI.getCoerceToType();
- InFPRs = ArgTy->isFloatTy() || ArgTy->isDoubleTy();
- IsVector = ArgTy->isVectorTy();
- UnpaddedSize = TyInfo.first;
- DirectAlign = TyInfo.second;
- }
- CharUnits PaddedSize = CharUnits::fromQuantity(8);
- if (IsVector && UnpaddedSize > PaddedSize)
- PaddedSize = CharUnits::fromQuantity(16);
- assert((UnpaddedSize <= PaddedSize) && "Invalid argument size.");
-
- CharUnits Padding = (PaddedSize - UnpaddedSize);
-
- llvm::Type *IndexTy = CGF.Int64Ty;
- llvm::Value *PaddedSizeV =
- llvm::ConstantInt::get(IndexTy, PaddedSize.getQuantity());
-
- if (IsVector) {
- // Work out the address of a vector argument on the stack.
- // Vector arguments are always passed in the high bits of a
- // single (8 byte) or double (16 byte) stack slot.
- Address OverflowArgAreaPtr =
- CGF.Builder.CreateStructGEP(VAListAddr, 2, CharUnits::fromQuantity(16),
- "overflow_arg_area_ptr");
- Address OverflowArgArea =
- Address(CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"),
- TyInfo.second);
- Address MemAddr =
- CGF.Builder.CreateElementBitCast(OverflowArgArea, DirectTy, "mem_addr");
-
- // Update overflow_arg_area_ptr pointer
- llvm::Value *NewOverflowArgArea =
- CGF.Builder.CreateGEP(OverflowArgArea.getPointer(), PaddedSizeV,
- "overflow_arg_area");
- CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr);
-
- return MemAddr;
- }
-
- assert(PaddedSize.getQuantity() == 8);
-
- unsigned MaxRegs, RegCountField, RegSaveIndex;
- CharUnits RegPadding;
- if (InFPRs) {
- MaxRegs = 4; // Maximum of 4 FPR arguments
- RegCountField = 1; // __fpr
- RegSaveIndex = 16; // save offset for f0
- RegPadding = CharUnits(); // floats are passed in the high bits of an FPR
- } else {
- MaxRegs = 5; // Maximum of 5 GPR arguments
- RegCountField = 0; // __gpr
- RegSaveIndex = 2; // save offset for r2
- RegPadding = Padding; // values are passed in the low bits of a GPR
- }
-
- Address RegCountPtr = CGF.Builder.CreateStructGEP(
- VAListAddr, RegCountField, RegCountField * CharUnits::fromQuantity(8),
- "reg_count_ptr");
- llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count");
- llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs);
- llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV,
- "fits_in_regs");
-
- llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
- llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
- CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock);
-
- // Emit code to load the value if it was passed in registers.
- CGF.EmitBlock(InRegBlock);
-
- // Work out the address of an argument register.
- llvm::Value *ScaledRegCount =
- CGF.Builder.CreateMul(RegCount, PaddedSizeV, "scaled_reg_count");
- llvm::Value *RegBase =
- llvm::ConstantInt::get(IndexTy, RegSaveIndex * PaddedSize.getQuantity()
- + RegPadding.getQuantity());
- llvm::Value *RegOffset =
- CGF.Builder.CreateAdd(ScaledRegCount, RegBase, "reg_offset");
- Address RegSaveAreaPtr =
- CGF.Builder.CreateStructGEP(VAListAddr, 3, CharUnits::fromQuantity(24),
- "reg_save_area_ptr");
- llvm::Value *RegSaveArea =
- CGF.Builder.CreateLoad(RegSaveAreaPtr, "reg_save_area");
- Address RawRegAddr(CGF.Builder.CreateGEP(RegSaveArea, RegOffset,
- "raw_reg_addr"),
- PaddedSize);
- Address RegAddr =
- CGF.Builder.CreateElementBitCast(RawRegAddr, DirectTy, "reg_addr");
-
- // Update the register count
- llvm::Value *One = llvm::ConstantInt::get(IndexTy, 1);
- llvm::Value *NewRegCount =
- CGF.Builder.CreateAdd(RegCount, One, "reg_count");
- CGF.Builder.CreateStore(NewRegCount, RegCountPtr);
- CGF.EmitBranch(ContBlock);
-
- // Emit code to load the value if it was passed in memory.
- CGF.EmitBlock(InMemBlock);
-
- // Work out the address of a stack argument.
- Address OverflowArgAreaPtr = CGF.Builder.CreateStructGEP(
- VAListAddr, 2, CharUnits::fromQuantity(16), "overflow_arg_area_ptr");
- Address OverflowArgArea =
- Address(CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"),
- PaddedSize);
- Address RawMemAddr =
- CGF.Builder.CreateConstByteGEP(OverflowArgArea, Padding, "raw_mem_addr");
- Address MemAddr =
- CGF.Builder.CreateElementBitCast(RawMemAddr, DirectTy, "mem_addr");
-
- // Update overflow_arg_area_ptr pointer
- llvm::Value *NewOverflowArgArea =
- CGF.Builder.CreateGEP(OverflowArgArea.getPointer(), PaddedSizeV,
- "overflow_arg_area");
- CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr);
- CGF.EmitBranch(ContBlock);
-
- // Return the appropriate result.
- CGF.EmitBlock(ContBlock);
- Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock,
- MemAddr, InMemBlock, "va_arg.addr");
-
- if (IsIndirect)
- ResAddr = Address(CGF.Builder.CreateLoad(ResAddr, "indirect_arg"),
- TyInfo.second);
-
- return ResAddr;
-}
-
-ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
- if (isVectorArgumentType(RetTy))
- return ABIArgInfo::getDirect();
- if (isCompoundType(RetTy) || getContext().getTypeSize(RetTy) > 64)
- return getNaturalAlignIndirect(RetTy);
- return (isPromotableIntegerType(RetTy) ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
-}
-
-ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
- // Handle the generic C++ ABI.
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
- // Integers and enums are extended to full register width.
- if (isPromotableIntegerType(Ty))
- return ABIArgInfo::getExtend(Ty);
-
- // Handle vector types and vector-like structure types. Note that
- // as opposed to float-like structure types, we do not allow any
- // padding for vector-like structures, so verify the sizes match.
- uint64_t Size = getContext().getTypeSize(Ty);
- QualType SingleElementTy = GetSingleElementType(Ty);
- if (isVectorArgumentType(SingleElementTy) &&
- getContext().getTypeSize(SingleElementTy) == Size)
- return ABIArgInfo::getDirect(CGT.ConvertType(SingleElementTy));
-
- // Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly.
- if (Size != 8 && Size != 16 && Size != 32 && Size != 64)
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-
- // Handle small structures.
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- // Structures with flexible arrays have variable length, so really
- // fail the size test above.
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-
- // The structure is passed as an unextended integer, a float, or a double.
- llvm::Type *PassTy;
- if (isFPArgumentType(SingleElementTy)) {
- assert(Size == 32 || Size == 64);
- if (Size == 32)
- PassTy = llvm::Type::getFloatTy(getVMContext());
- else
- PassTy = llvm::Type::getDoubleTy(getVMContext());
- } else
- PassTy = llvm::IntegerType::get(getVMContext(), Size);
- return ABIArgInfo::getDirect(PassTy);
- }
-
- // Non-structure compounds are passed indirectly.
- if (isCompoundType(Ty))
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-
- return ABIArgInfo::getDirect(nullptr);
-}
-
-//===----------------------------------------------------------------------===//
-// MSP430 ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class MSP430TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- MSP430TargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
-};
-
-}
-
-void MSP430TargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
- if (GV->isDeclaration())
- return;
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- const auto *InterruptAttr = FD->getAttr<MSP430InterruptAttr>();
- if (!InterruptAttr)
- return;
-
- // Handle 'interrupt' attribute:
- llvm::Function *F = cast<llvm::Function>(GV);
-
- // Step 1: Set ISR calling convention.
- F->setCallingConv(llvm::CallingConv::MSP430_INTR);
-
- // Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attribute::NoInline);
- F->addFnAttr("interrupt", llvm::utostr(InterruptAttr->getNumber()));
- }
-}
-
-//===----------------------------------------------------------------------===//
-// MIPS ABI Implementation. This works for both little-endian and
-// big-endian variants.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class MipsABIInfo : public ABIInfo {
- bool IsO32;
- unsigned MinABIStackAlignInBytes, StackAlignInBytes;
- void CoerceToIntArgs(uint64_t TySize,
- SmallVectorImpl<llvm::Type *> &ArgList) const;
- llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const;
- llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const;
- llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;
-public:
- MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) :
- ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8),
- StackAlignInBytes(IsO32 ? 8 : 16) {}
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
- void computeInfo(CGFunctionInfo &FI) const override;
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
- ABIArgInfo extendType(QualType Ty) const;
-};
-
-class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
- unsigned SizeOfUnwindException;
-public:
- MIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32)
- : TargetCodeGenInfo(new MipsABIInfo(CGT, IsO32)),
- SizeOfUnwindException(IsO32 ? 24 : 32) {}
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
- return 29;
- }
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD) return;
- llvm::Function *Fn = cast<llvm::Function>(GV);
-
- if (FD->hasAttr<MipsLongCallAttr>())
- Fn->addFnAttr("long-call");
- else if (FD->hasAttr<MipsShortCallAttr>())
- Fn->addFnAttr("short-call");
-
- // Other attributes do not have a meaning for declarations.
- if (GV->isDeclaration())
- return;
-
- if (FD->hasAttr<Mips16Attr>()) {
- Fn->addFnAttr("mips16");
- }
- else if (FD->hasAttr<NoMips16Attr>()) {
- Fn->addFnAttr("nomips16");
- }
-
- if (FD->hasAttr<MicroMipsAttr>())
- Fn->addFnAttr("micromips");
- else if (FD->hasAttr<NoMicroMipsAttr>())
- Fn->addFnAttr("nomicromips");
-
- const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>();
- if (!Attr)
- return;
-
- const char *Kind;
- switch (Attr->getInterrupt()) {
- case MipsInterruptAttr::eic: Kind = "eic"; break;
- case MipsInterruptAttr::sw0: Kind = "sw0"; break;
- case MipsInterruptAttr::sw1: Kind = "sw1"; break;
- case MipsInterruptAttr::hw0: Kind = "hw0"; break;
- case MipsInterruptAttr::hw1: Kind = "hw1"; break;
- case MipsInterruptAttr::hw2: Kind = "hw2"; break;
- case MipsInterruptAttr::hw3: Kind = "hw3"; break;
- case MipsInterruptAttr::hw4: Kind = "hw4"; break;
- case MipsInterruptAttr::hw5: Kind = "hw5"; break;
- }
-
- Fn->addFnAttr("interrupt", Kind);
-
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override;
-
- unsigned getSizeOfUnwindException() const override {
- return SizeOfUnwindException;
- }
-};
-}
-
-void MipsABIInfo::CoerceToIntArgs(
- uint64_t TySize, SmallVectorImpl<llvm::Type *> &ArgList) const {
- llvm::IntegerType *IntTy =
- llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8);
-
- // Add (TySize / MinABIStackAlignInBytes) args of IntTy.
- for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N)
- ArgList.push_back(IntTy);
-
- // If necessary, add one more integer type to ArgList.
- unsigned R = TySize % (MinABIStackAlignInBytes * 8);
-
- if (R)
- ArgList.push_back(llvm::IntegerType::get(getVMContext(), R));
-}
-
-// In N32/64, an aligned double precision floating point field is passed in
-// a register.
-llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {
- SmallVector<llvm::Type*, 8> ArgList, IntArgList;
-
- if (IsO32) {
- CoerceToIntArgs(TySize, ArgList);
- return llvm::StructType::get(getVMContext(), ArgList);
- }
-
- if (Ty->isComplexType())
- return CGT.ConvertType(Ty);
-
- const RecordType *RT = Ty->getAs<RecordType>();
-
- // Unions/vectors are passed in integer registers.
- if (!RT || !RT->isStructureOrClassType()) {
- CoerceToIntArgs(TySize, ArgList);
- return llvm::StructType::get(getVMContext(), ArgList);
- }
-
- const RecordDecl *RD = RT->getDecl();
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
- assert(!(TySize % 8) && "Size of structure must be multiple of 8.");
-
- uint64_t LastOffset = 0;
- unsigned idx = 0;
- llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64);
-
- // Iterate over fields in the struct/class and check if there are any aligned
- // double fields.
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i, ++idx) {
- const QualType Ty = i->getType();
- const BuiltinType *BT = Ty->getAs<BuiltinType>();
-
- if (!BT || BT->getKind() != BuiltinType::Double)
- continue;
-
- uint64_t Offset = Layout.getFieldOffset(idx);
- if (Offset % 64) // Ignore doubles that are not aligned.
- continue;
-
- // Add ((Offset - LastOffset) / 64) args of type i64.
- for (unsigned j = (Offset - LastOffset) / 64; j > 0; --j)
- ArgList.push_back(I64);
-
- // Add double type.
- ArgList.push_back(llvm::Type::getDoubleTy(getVMContext()));
- LastOffset = Offset + 64;
- }
-
- CoerceToIntArgs(TySize - LastOffset, IntArgList);
- ArgList.append(IntArgList.begin(), IntArgList.end());
-
- return llvm::StructType::get(getVMContext(), ArgList);
-}
-
-llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset,
- uint64_t Offset) const {
- if (OrigOffset + MinABIStackAlignInBytes > Offset)
- return nullptr;
-
- return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8);
-}
-
-ABIArgInfo
-MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- uint64_t OrigOffset = Offset;
- uint64_t TySize = getContext().getTypeSize(Ty);
- uint64_t Align = getContext().getTypeAlign(Ty) / 8;
-
- Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes),
- (uint64_t)StackAlignInBytes);
- unsigned CurrOffset = llvm::alignTo(Offset, Align);
- Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8;
-
- if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) {
- // Ignore empty aggregates.
- if (TySize == 0)
- return ABIArgInfo::getIgnore();
-
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
- Offset = OrigOffset + MinABIStackAlignInBytes;
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
- }
-
- // If we have reached here, aggregates are passed directly by coercing to
- // another structure type. Padding is inserted if the offset of the
- // aggregate is unaligned.
- ABIArgInfo ArgInfo =
- ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0,
- getPaddingType(OrigOffset, CurrOffset));
- ArgInfo.setInReg(true);
- return ArgInfo;
- }
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- // All integral types are promoted to the GPR width.
- if (Ty->isIntegralOrEnumerationType())
- return extendType(Ty);
-
- return ABIArgInfo::getDirect(
- nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset));
-}
-
-llvm::Type*
-MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const {
- const RecordType *RT = RetTy->getAs<RecordType>();
- SmallVector<llvm::Type*, 8> RTList;
-
- if (RT && RT->isStructureOrClassType()) {
- const RecordDecl *RD = RT->getDecl();
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
- unsigned FieldCnt = Layout.getFieldCount();
-
- // N32/64 returns struct/classes in floating point registers if the
- // following conditions are met:
- // 1. The size of the struct/class is no larger than 128-bit.
- // 2. The struct/class has one or two fields all of which are floating
- // point types.
- // 3. The offset of the first field is zero (this follows what gcc does).
- //
- // Any other composite results are returned in integer registers.
- //
- if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) {
- RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end();
- for (; b != e; ++b) {
- const BuiltinType *BT = b->getType()->getAs<BuiltinType>();
-
- if (!BT || !BT->isFloatingPoint())
- break;
-
- RTList.push_back(CGT.ConvertType(b->getType()));
- }
-
- if (b == e)
- return llvm::StructType::get(getVMContext(), RTList,
- RD->hasAttr<PackedAttr>());
-
- RTList.clear();
- }
- }
-
- CoerceToIntArgs(Size, RTList);
- return llvm::StructType::get(getVMContext(), RTList);
-}
-
-ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
- uint64_t Size = getContext().getTypeSize(RetTy);
-
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- // O32 doesn't treat zero-sized structs differently from other structs.
- // However, N32/N64 ignores zero sized return values.
- if (!IsO32 && Size == 0)
- return ABIArgInfo::getIgnore();
-
- if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) {
- if (Size <= 128) {
- if (RetTy->isAnyComplexType())
- return ABIArgInfo::getDirect();
-
- // O32 returns integer vectors in registers and N32/N64 returns all small
- // aggregates in registers.
- if (!IsO32 ||
- (RetTy->isVectorType() && !RetTy->hasFloatingRepresentation())) {
- ABIArgInfo ArgInfo =
- ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size));
- ArgInfo.setInReg(true);
- return ArgInfo;
- }
- }
-
- return getNaturalAlignIndirect(RetTy);
- }
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- if (RetTy->isPromotableIntegerType())
- return ABIArgInfo::getExtend(RetTy);
-
- if ((RetTy->isUnsignedIntegerOrEnumerationType() ||
- RetTy->isSignedIntegerOrEnumerationType()) && Size == 32 && !IsO32)
- return ABIArgInfo::getSignExtend(RetTy);
-
- return ABIArgInfo::getDirect();
-}
-
-void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
- ABIArgInfo &RetInfo = FI.getReturnInfo();
- if (!getCXXABI().classifyReturnType(FI))
- RetInfo = classifyReturnType(FI.getReturnType());
-
- // Check if a pointer to an aggregate is passed as a hidden argument.
- uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0;
-
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type, Offset);
-}
-
-Address MipsABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType OrigTy) const {
- QualType Ty = OrigTy;
-
- // Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64.
- // Pointers are also promoted in the same way but this only matters for N32.
- unsigned SlotSizeInBits = IsO32 ? 32 : 64;
- unsigned PtrWidth = getTarget().getPointerWidth(0);
- bool DidPromote = false;
- if ((Ty->isIntegerType() &&
- getContext().getIntWidth(Ty) < SlotSizeInBits) ||
- (Ty->isPointerType() && PtrWidth < SlotSizeInBits)) {
- DidPromote = true;
- Ty = getContext().getIntTypeForBitwidth(SlotSizeInBits,
- Ty->isSignedIntegerType());
- }
-
- auto TyInfo = getContext().getTypeInfoInChars(Ty);
-
- // The alignment of things in the argument area is never larger than
- // StackAlignInBytes.
- TyInfo.second =
- std::min(TyInfo.second, CharUnits::fromQuantity(StackAlignInBytes));
-
- // MinABIStackAlignInBytes is the size of argument slots on the stack.
- CharUnits ArgSlotSize = CharUnits::fromQuantity(MinABIStackAlignInBytes);
-
- Address Addr = emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
- TyInfo, ArgSlotSize, /*AllowHigherAlign*/ true);
-
-
- // If there was a promotion, "unpromote" into a temporary.
- // TODO: can we just use a pointer into a subset of the original slot?
- if (DidPromote) {
- Address Temp = CGF.CreateMemTemp(OrigTy, "vaarg.promotion-temp");
- llvm::Value *Promoted = CGF.Builder.CreateLoad(Addr);
-
- // Truncate down to the right width.
- llvm::Type *IntTy = (OrigTy->isIntegerType() ? Temp.getElementType()
- : CGF.IntPtrTy);
- llvm::Value *V = CGF.Builder.CreateTrunc(Promoted, IntTy);
- if (OrigTy->isPointerType())
- V = CGF.Builder.CreateIntToPtr(V, Temp.getElementType());
-
- CGF.Builder.CreateStore(V, Temp);
- Addr = Temp;
- }
-
- return Addr;
-}
-
-ABIArgInfo MipsABIInfo::extendType(QualType Ty) const {
- int TySize = getContext().getTypeSize(Ty);
-
- // MIPS64 ABI requires unsigned 32 bit integers to be sign extended.
- if (Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
- return ABIArgInfo::getSignExtend(Ty);
-
- return ABIArgInfo::getExtend(Ty);
-}
-
-bool
-MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- // This information comes from gcc's implementation, which seems to
- // as canonical as it gets.
-
- // Everything on MIPS is 4 bytes. Double-precision FP registers
- // are aliased to pairs of single-precision FP registers.
- llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);
-
- // 0-31 are the general purpose registers, $0 - $31.
- // 32-63 are the floating-point registers, $f0 - $f31.
- // 64 and 65 are the multiply/divide registers, $hi and $lo.
- // 66 is the (notional, I think) register for signal-handler return.
- AssignToArrayRange(CGF.Builder, Address, Four8, 0, 65);
-
- // 67-74 are the floating-point status registers, $fcc0 - $fcc7.
- // They are one bit wide and ignored here.
-
- // 80-111 are the coprocessor 0 registers, $c0r0 - $c0r31.
- // (coprocessor 1 is the FP unit)
- // 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31.
- // 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31.
- // 176-181 are the DSP accumulator registers.
- AssignToArrayRange(CGF.Builder, Address, Four8, 80, 181);
- return false;
-}
-
-//===----------------------------------------------------------------------===//
-// AVR ABI Implementation.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class AVRTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- AVRTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new DefaultABIInfo(CGT)) { }
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
- if (GV->isDeclaration())
- return;
- const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD) return;
- auto *Fn = cast<llvm::Function>(GV);
-
- if (FD->getAttr<AVRInterruptAttr>())
- Fn->addFnAttr("interrupt");
-
- if (FD->getAttr<AVRSignalAttr>())
- Fn->addFnAttr("signal");
- }
-};
-}
-
-//===----------------------------------------------------------------------===//
-// TCE ABI Implementation (see http://tce.cs.tut.fi). Uses mostly the defaults.
-// Currently subclassed only to implement custom OpenCL C function attribute
-// handling.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class TCETargetCodeGenInfo : public DefaultTargetCodeGenInfo {
-public:
- TCETargetCodeGenInfo(CodeGenTypes &CGT)
- : DefaultTargetCodeGenInfo(CGT) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
-};
-
-void TCETargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
- if (GV->isDeclaration())
- return;
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD) return;
-
- llvm::Function *F = cast<llvm::Function>(GV);
-
- if (M.getLangOpts().OpenCL) {
- if (FD->hasAttr<OpenCLKernelAttr>()) {
- // OpenCL C Kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attribute::NoInline);
- const ReqdWorkGroupSizeAttr *Attr = FD->getAttr<ReqdWorkGroupSizeAttr>();
- if (Attr) {
- // Convert the reqd_work_group_size() attributes to metadata.
- llvm::LLVMContext &Context = F->getContext();
- llvm::NamedMDNode *OpenCLMetadata =
- M.getModule().getOrInsertNamedMetadata(
- "opencl.kernel_wg_size_info");
-
- SmallVector<llvm::Metadata *, 5> Operands;
- Operands.push_back(llvm::ConstantAsMetadata::get(F));
-
- Operands.push_back(
- llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue(
- M.Int32Ty, llvm::APInt(32, Attr->getXDim()))));
- Operands.push_back(
- llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue(
- M.Int32Ty, llvm::APInt(32, Attr->getYDim()))));
- Operands.push_back(
- llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue(
- M.Int32Ty, llvm::APInt(32, Attr->getZDim()))));
-
- // Add a boolean constant operand for "required" (true) or "hint"
- // (false) for implementing the work_group_size_hint attr later.
- // Currently always true as the hint is not yet implemented.
- Operands.push_back(
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::getTrue(Context)));
- OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Operands));
- }
- }
- }
-}
-
-}
-
-//===----------------------------------------------------------------------===//
-// Hexagon ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class HexagonABIInfo : public ABIInfo {
-
-
-public:
- HexagonABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
-private:
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
-
- void computeInfo(CGFunctionInfo &FI) const override;
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-};
-
-class HexagonTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- HexagonTargetCodeGenInfo(CodeGenTypes &CGT)
- :TargetCodeGenInfo(new HexagonABIInfo(CGT)) {}
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
- return 29;
- }
-};
-
-}
-
-void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
-}
-
-ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const {
- if (!isAggregateTypeForABI(Ty)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty)
- : ABIArgInfo::getDirect());
- }
-
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
- // Ignore empty records.
- if (isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
-
- uint64_t Size = getContext().getTypeSize(Ty);
- if (Size > 64)
- return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
- // Pass in the smallest viable integer type.
- else if (Size > 32)
- return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext()));
- else if (Size > 16)
- return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
- else if (Size > 8)
- return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
- else
- return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
-}
-
-ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- // Large vector types should be returned via memory.
- if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 64)
- return getNaturalAlignIndirect(RetTy);
-
- if (!isAggregateTypeForABI(RetTy)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
- RetTy = EnumTy->getDecl()->getIntegerType();
-
- return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy)
- : ABIArgInfo::getDirect());
- }
-
- if (isEmptyRecord(getContext(), RetTy, true))
- return ABIArgInfo::getIgnore();
-
- // Aggregates <= 8 bytes are returned in r0; other aggregates
- // are returned indirectly.
- uint64_t Size = getContext().getTypeSize(RetTy);
- if (Size <= 64) {
- // Return in the smallest viable integer type.
- if (Size <= 8)
- return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
- if (Size <= 16)
- return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
- if (Size <= 32)
- return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
- return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext()));
- }
-
- return getNaturalAlignIndirect(RetTy, /*ByVal=*/true);
-}
-
-Address HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- // FIXME: Someone needs to audit that this handle alignment correctly.
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
- getContext().getTypeInfoInChars(Ty),
- CharUnits::fromQuantity(4),
- /*AllowHigherAlign*/ true);
-}
-
-//===----------------------------------------------------------------------===//
-// Lanai ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-class LanaiABIInfo : public DefaultABIInfo {
-public:
- LanaiABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
-
- bool shouldUseInReg(QualType Ty, CCState &State) const;
-
- void computeInfo(CGFunctionInfo &FI) const override {
- CCState State(FI.getCallingConvention());
- // Lanai uses 4 registers to pass arguments unless the function has the
- // regparm attribute set.
- if (FI.getHasRegParm()) {
- State.FreeRegs = FI.getRegParm();
- } else {
- State.FreeRegs = 4;
- }
-
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type, State);
- }
-
- ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
-};
-} // end anonymous namespace
-
-bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const {
- unsigned Size = getContext().getTypeSize(Ty);
- unsigned SizeInRegs = llvm::alignTo(Size, 32U) / 32U;
-
- if (SizeInRegs == 0)
- return false;
-
- if (SizeInRegs > State.FreeRegs) {
- State.FreeRegs = 0;
- return false;
- }
-
- State.FreeRegs -= SizeInRegs;
-
- return true;
-}
-
-ABIArgInfo LanaiABIInfo::getIndirectResult(QualType Ty, bool ByVal,
- CCState &State) const {
- if (!ByVal) {
- if (State.FreeRegs) {
- --State.FreeRegs; // Non-byval indirects just use one pointer.
- return getNaturalAlignIndirectInReg(Ty);
- }
- return getNaturalAlignIndirect(Ty, false);
- }
-
- // Compute the byval alignment.
- const unsigned MinABIStackAlignInBytes = 4;
- unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true,
- /*Realign=*/TypeAlign >
- MinABIStackAlignInBytes);
-}
-
-ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty,
- CCState &State) const {
- // Check with the C++ ABI first.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (RT) {
- CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
- if (RAA == CGCXXABI::RAA_Indirect) {
- return getIndirectResult(Ty, /*ByVal=*/false, State);
- } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
- return getNaturalAlignIndirect(Ty, /*ByRef=*/true);
- }
- }
-
- if (isAggregateTypeForABI(Ty)) {
- // Structures with flexible arrays are always indirect.
- if (RT && RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectResult(Ty, /*ByVal=*/true, State);
-
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
-
- llvm::LLVMContext &LLVMContext = getVMContext();
- unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
- if (SizeInRegs <= State.FreeRegs) {
- llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
- SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
- llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
- State.FreeRegs -= SizeInRegs;
- return ABIArgInfo::getDirectInReg(Result);
- } else {
- State.FreeRegs = 0;
- }
- return getIndirectResult(Ty, true, State);
- }
-
- // Treat an enum type as its underlying type.
- if (const auto *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- bool InReg = shouldUseInReg(Ty, State);
- if (Ty->isPromotableIntegerType()) {
- if (InReg)
- return ABIArgInfo::getDirectInReg();
- return ABIArgInfo::getExtend(Ty);
- }
- if (InReg)
- return ABIArgInfo::getDirectInReg();
- return ABIArgInfo::getDirect();
-}
-
-namespace {
-class LanaiTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- LanaiTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(new LanaiABIInfo(CGT)) {}
-};
-}
-
-//===----------------------------------------------------------------------===//
-// AMDGPU ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class AMDGPUABIInfo final : public DefaultABIInfo {
-private:
- static const unsigned MaxNumRegsForArgsRet = 16;
-
- unsigned numRegsForType(QualType Ty) const;
-
- bool isHomogeneousAggregateBaseType(QualType Ty) const override;
- bool isHomogeneousAggregateSmallEnough(const Type *Base,
- uint64_t Members) const override;
-
-public:
- explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) :
- DefaultABIInfo(CGT) {}
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyKernelArgumentType(QualType Ty) const;
- ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const;
-
- void computeInfo(CGFunctionInfo &FI) const override;
-};
-
-bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
- return true;
-}
-
-bool AMDGPUABIInfo::isHomogeneousAggregateSmallEnough(
- const Type *Base, uint64_t Members) const {
- uint32_t NumRegs = (getContext().getTypeSize(Base) + 31) / 32;
-
- // Homogeneous Aggregates may occupy at most 16 registers.
- return Members * NumRegs <= MaxNumRegsForArgsRet;
-}
-
-/// Estimate number of registers the type will use when passed in registers.
-unsigned AMDGPUABIInfo::numRegsForType(QualType Ty) const {
- unsigned NumRegs = 0;
-
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- // Compute from the number of elements. The reported size is based on the
- // in-memory size, which includes the padding 4th element for 3-vectors.
- QualType EltTy = VT->getElementType();
- unsigned EltSize = getContext().getTypeSize(EltTy);
-
- // 16-bit element vectors should be passed as packed.
- if (EltSize == 16)
- return (VT->getNumElements() + 1) / 2;
-
- unsigned EltNumRegs = (EltSize + 31) / 32;
- return EltNumRegs * VT->getNumElements();
- }
-
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- assert(!RD->hasFlexibleArrayMember());
-
- for (const FieldDecl *Field : RD->fields()) {
- QualType FieldTy = Field->getType();
- NumRegs += numRegsForType(FieldTy);
- }
-
- return NumRegs;
- }
-
- return (getContext().getTypeSize(Ty) + 31) / 32;
-}
-
-void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const {
- llvm::CallingConv::ID CC = FI.getCallingConvention();
-
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
-
- unsigned NumRegsLeft = MaxNumRegsForArgsRet;
- for (auto &Arg : FI.arguments()) {
- if (CC == llvm::CallingConv::AMDGPU_KERNEL) {
- Arg.info = classifyKernelArgumentType(Arg.type);
- } else {
- Arg.info = classifyArgumentType(Arg.type, NumRegsLeft);
- }
- }
-}
-
-ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const {
- if (isAggregateTypeForABI(RetTy)) {
- // Records with non-trivial destructors/copy-constructors should not be
- // returned by value.
- if (!getRecordArgABI(RetTy, getCXXABI())) {
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), RetTy, true))
- return ABIArgInfo::getIgnore();
-
- // Lower single-element structs to just return a regular value.
- if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
- return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
-
- if (const RecordType *RT = RetTy->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return DefaultABIInfo::classifyReturnType(RetTy);
- }
-
- // Pack aggregates <= 4 bytes into single VGPR or pair.
- uint64_t Size = getContext().getTypeSize(RetTy);
- if (Size <= 16)
- return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
-
- if (Size <= 32)
- return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
-
- if (Size <= 64) {
- llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
- return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
- }
-
- if (numRegsForType(RetTy) <= MaxNumRegsForArgsRet)
- return ABIArgInfo::getDirect();
- }
- }
-
- // Otherwise just do the default thing.
- return DefaultABIInfo::classifyReturnType(RetTy);
-}
-
-/// For kernels all parameters are really passed in a special buffer. It doesn't
-/// make sense to pass anything byval, so everything must be direct.
-ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const {
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- // TODO: Can we omit empty structs?
-
- // Coerce single element structs to its element.
- if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
- return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
-
- // If we set CanBeFlattened to true, CodeGen will expand the struct to its
- // individual elements, which confuses the Clover OpenCL backend; therefore we
- // have to set it to false here. Other args of getDirect() are just defaults.
- return ABIArgInfo::getDirect(nullptr, 0, nullptr, false);
-}
-
-ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty,
- unsigned &NumRegsLeft) const {
- assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow");
-
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- if (isAggregateTypeForABI(Ty)) {
- // Records with non-trivial destructors/copy-constructors should not be
- // passed by value.
- if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
-
- // Lower single-element structs to just pass a regular value. TODO: We
- // could do reasonable-size multiple-element structs too, using getExpand(),
- // though watch out for things like bitfields.
- if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
- return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
-
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return DefaultABIInfo::classifyArgumentType(Ty);
- }
-
- // Pack aggregates <= 8 bytes into single VGPR or pair.
- uint64_t Size = getContext().getTypeSize(Ty);
- if (Size <= 64) {
- unsigned NumRegs = (Size + 31) / 32;
- NumRegsLeft -= std::min(NumRegsLeft, NumRegs);
-
- if (Size <= 16)
- return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
-
- if (Size <= 32)
- return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
-
- // XXX: Should this be i64 instead, and should the limit increase?
- llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
- return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
- }
-
- if (NumRegsLeft > 0) {
- unsigned NumRegs = numRegsForType(Ty);
- if (NumRegsLeft >= NumRegs) {
- NumRegsLeft -= NumRegs;
- return ABIArgInfo::getDirect();
- }
- }
- }
-
- // Otherwise just do the default thing.
- ABIArgInfo ArgInfo = DefaultABIInfo::classifyArgumentType(Ty);
- if (!ArgInfo.isIndirect()) {
- unsigned NumRegs = numRegsForType(Ty);
- NumRegsLeft -= std::min(NumRegs, NumRegsLeft);
- }
-
- return ArgInfo;
-}
-
-class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new AMDGPUABIInfo(CGT)) {}
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
- unsigned getOpenCLKernelCallingConv() const override;
-
- llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
- llvm::PointerType *T, QualType QT) const override;
-
- LangAS getASTAllocaAddressSpace() const override {
- return getLangASFromTargetAS(
- getABIInfo().getDataLayout().getAllocaAddrSpace());
- }
- LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
- const VarDecl *D) const override;
- llvm::SyncScope::ID getLLVMSyncScopeID(SyncScope S,
- llvm::LLVMContext &C) const override;
- llvm::Function *
- createEnqueuedBlockKernel(CodeGenFunction &CGF,
- llvm::Function *BlockInvokeFunc,
- llvm::Value *BlockLiteral) const override;
- bool shouldEmitStaticExternCAliases() const override;
- void setCUDAKernelCallingConvention(const FunctionType *&FT) const override;
-};
-}
-
-void AMDGPUTargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
- if (GV->isDeclaration())
- return;
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD)
- return;
-
- llvm::Function *F = cast<llvm::Function>(GV);
-
- const auto *ReqdWGS = M.getLangOpts().OpenCL ?
- FD->getAttr<ReqdWorkGroupSizeAttr>() : nullptr;
-
- if (M.getLangOpts().OpenCL && FD->hasAttr<OpenCLKernelAttr>() &&
- (M.getTriple().getOS() == llvm::Triple::AMDHSA))
- F->addFnAttr("amdgpu-implicitarg-num-bytes", "48");
-
- const auto *FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>();
- if (ReqdWGS || FlatWGS) {
- unsigned Min = FlatWGS ? FlatWGS->getMin() : 0;
- unsigned Max = FlatWGS ? FlatWGS->getMax() : 0;
- if (ReqdWGS && Min == 0 && Max == 0)
- Min = Max = ReqdWGS->getXDim() * ReqdWGS->getYDim() * ReqdWGS->getZDim();
-
- if (Min != 0) {
- assert(Min <= Max && "Min must be less than or equal Max");
-
- std::string AttrVal = llvm::utostr(Min) + "," + llvm::utostr(Max);
- F->addFnAttr("amdgpu-flat-work-group-size", AttrVal);
- } else
- assert(Max == 0 && "Max must be zero");
- }
-
- if (const auto *Attr = FD->getAttr<AMDGPUWavesPerEUAttr>()) {
- unsigned Min = Attr->getMin();
- unsigned Max = Attr->getMax();
-
- if (Min != 0) {
- assert((Max == 0 || Min <= Max) && "Min must be less than or equal Max");
-
- std::string AttrVal = llvm::utostr(Min);
- if (Max != 0)
- AttrVal = AttrVal + "," + llvm::utostr(Max);
- F->addFnAttr("amdgpu-waves-per-eu", AttrVal);
- } else
- assert(Max == 0 && "Max must be zero");
- }
-
- if (const auto *Attr = FD->getAttr<AMDGPUNumSGPRAttr>()) {
- unsigned NumSGPR = Attr->getNumSGPR();
-
- if (NumSGPR != 0)
- F->addFnAttr("amdgpu-num-sgpr", llvm::utostr(NumSGPR));
- }
-
- if (const auto *Attr = FD->getAttr<AMDGPUNumVGPRAttr>()) {
- uint32_t NumVGPR = Attr->getNumVGPR();
-
- if (NumVGPR != 0)
- F->addFnAttr("amdgpu-num-vgpr", llvm::utostr(NumVGPR));
- }
-}
-
-unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
- return llvm::CallingConv::AMDGPU_KERNEL;
-}
-
-// Currently LLVM assumes null pointers always have value 0,
-// which results in incorrectly transformed IR. Therefore, instead of
-// emitting null pointers in private and local address spaces, a null
-// pointer in generic address space is emitted which is casted to a
-// pointer in local or private address space.
-llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer(
- const CodeGen::CodeGenModule &CGM, llvm::PointerType *PT,
- QualType QT) const {
- if (CGM.getContext().getTargetNullPointerValue(QT) == 0)
- return llvm::ConstantPointerNull::get(PT);
-
- auto &Ctx = CGM.getContext();
- auto NPT = llvm::PointerType::get(PT->getElementType(),
- Ctx.getTargetAddressSpace(LangAS::opencl_generic));
- return llvm::ConstantExpr::getAddrSpaceCast(
- llvm::ConstantPointerNull::get(NPT), PT);
-}
-
-LangAS
-AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
- const VarDecl *D) const {
- assert(!CGM.getLangOpts().OpenCL &&
- !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
- "Address space agnostic languages only");
- LangAS DefaultGlobalAS = getLangASFromTargetAS(
- CGM.getContext().getTargetAddressSpace(LangAS::opencl_global));
- if (!D)
- return DefaultGlobalAS;
-
- LangAS AddrSpace = D->getType().getAddressSpace();
- assert(AddrSpace == LangAS::Default || isTargetAddressSpace(AddrSpace));
- if (AddrSpace != LangAS::Default)
- return AddrSpace;
-
- if (CGM.isTypeConstant(D->getType(), false)) {
- if (auto ConstAS = CGM.getTarget().getConstantAddressSpace())
- return ConstAS.getValue();
- }
- return DefaultGlobalAS;
-}
-
-llvm::SyncScope::ID
-AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(SyncScope S,
- llvm::LLVMContext &C) const {
- StringRef Name;
- switch (S) {
- case SyncScope::OpenCLWorkGroup:
- Name = "workgroup";
- break;
- case SyncScope::OpenCLDevice:
- Name = "agent";
- break;
- case SyncScope::OpenCLAllSVMDevices:
- Name = "";
- break;
- case SyncScope::OpenCLSubGroup:
- Name = "subgroup";
- }
- return C.getOrInsertSyncScopeID(Name);
-}
-
-bool AMDGPUTargetCodeGenInfo::shouldEmitStaticExternCAliases() const {
- return false;
-}
-
-void AMDGPUTargetCodeGenInfo::setCUDAKernelCallingConvention(
- const FunctionType *&FT) const {
- FT = getABIInfo().getContext().adjustFunctionType(
- FT, FT->getExtInfo().withCallingConv(CC_OpenCLKernel));
-}
-
-//===----------------------------------------------------------------------===//
-// SPARC v8 ABI Implementation.
-// Based on the SPARC Compliance Definition version 2.4.1.
-//
-// Ensures that complex values are passed in registers.
-//
-namespace {
-class SparcV8ABIInfo : public DefaultABIInfo {
-public:
- SparcV8ABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
-
-private:
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- void computeInfo(CGFunctionInfo &FI) const override;
-};
-} // end anonymous namespace
-
-
-ABIArgInfo
-SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
- if (Ty->isAnyComplexType()) {
- return ABIArgInfo::getDirect();
- }
- else {
- return DefaultABIInfo::classifyReturnType(Ty);
- }
-}
-
-void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const {
-
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &Arg : FI.arguments())
- Arg.info = classifyArgumentType(Arg.type);
-}
-
-namespace {
-class SparcV8TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- SparcV8TargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new SparcV8ABIInfo(CGT)) {}
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// SPARC v9 ABI Implementation.
-// Based on the SPARC Compliance Definition version 2.4.1.
-//
-// Function arguments a mapped to a nominal "parameter array" and promoted to
-// registers depending on their type. Each argument occupies 8 or 16 bytes in
-// the array, structs larger than 16 bytes are passed indirectly.
-//
-// One case requires special care:
-//
-// struct mixed {
-// int i;
-// float f;
-// };
-//
-// When a struct mixed is passed by value, it only occupies 8 bytes in the
-// parameter array, but the int is passed in an integer register, and the float
-// is passed in a floating point register. This is represented as two arguments
-// with the LLVM IR inreg attribute:
-//
-// declare void f(i32 inreg %i, float inreg %f)
-//
-// The code generator will only allocate 4 bytes from the parameter array for
-// the inreg arguments. All other arguments are allocated a multiple of 8
-// bytes.
-//
-namespace {
-class SparcV9ABIInfo : public ABIInfo {
-public:
- SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
-private:
- ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
- void computeInfo(CGFunctionInfo &FI) const override;
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- // Coercion type builder for structs passed in registers. The coercion type
- // serves two purposes:
- //
- // 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned'
- // in registers.
- // 2. Expose aligned floating point elements as first-level elements, so the
- // code generator knows to pass them in floating point registers.
- //
- // We also compute the InReg flag which indicates that the struct contains
- // aligned 32-bit floats.
- //
- struct CoerceBuilder {
- llvm::LLVMContext &Context;
- const llvm::DataLayout &DL;
- SmallVector<llvm::Type*, 8> Elems;
- uint64_t Size;
- bool InReg;
-
- CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl)
- : Context(c), DL(dl), Size(0), InReg(false) {}
-
- // Pad Elems with integers until Size is ToSize.
- void pad(uint64_t ToSize) {
- assert(ToSize >= Size && "Cannot remove elements");
- if (ToSize == Size)
- return;
-
- // Finish the current 64-bit word.
- uint64_t Aligned = llvm::alignTo(Size, 64);
- if (Aligned > Size && Aligned <= ToSize) {
- Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size));
- Size = Aligned;
- }
-
- // Add whole 64-bit words.
- while (Size + 64 <= ToSize) {
- Elems.push_back(llvm::Type::getInt64Ty(Context));
- Size += 64;
- }
-
- // Final in-word padding.
- if (Size < ToSize) {
- Elems.push_back(llvm::IntegerType::get(Context, ToSize - Size));
- Size = ToSize;
- }
- }
-
- // Add a floating point element at Offset.
- void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) {
- // Unaligned floats are treated as integers.
- if (Offset % Bits)
- return;
- // The InReg flag is only required if there are any floats < 64 bits.
- if (Bits < 64)
- InReg = true;
- pad(Offset);
- Elems.push_back(Ty);
- Size = Offset + Bits;
- }
-
- // Add a struct type to the coercion type, starting at Offset (in bits).
- void addStruct(uint64_t Offset, llvm::StructType *StrTy) {
- const llvm::StructLayout *Layout = DL.getStructLayout(StrTy);
- for (unsigned i = 0, e = StrTy->getNumElements(); i != e; ++i) {
- llvm::Type *ElemTy = StrTy->getElementType(i);
- uint64_t ElemOffset = Offset + Layout->getElementOffsetInBits(i);
- switch (ElemTy->getTypeID()) {
- case llvm::Type::StructTyID:
- addStruct(ElemOffset, cast<llvm::StructType>(ElemTy));
- break;
- case llvm::Type::FloatTyID:
- addFloat(ElemOffset, ElemTy, 32);
- break;
- case llvm::Type::DoubleTyID:
- addFloat(ElemOffset, ElemTy, 64);
- break;
- case llvm::Type::FP128TyID:
- addFloat(ElemOffset, ElemTy, 128);
- break;
- case llvm::Type::PointerTyID:
- if (ElemOffset % 64 == 0) {
- pad(ElemOffset);
- Elems.push_back(ElemTy);
- Size += 64;
- }
- break;
- default:
- break;
- }
- }
- }
-
- // Check if Ty is a usable substitute for the coercion type.
- bool isUsableType(llvm::StructType *Ty) const {
- return llvm::makeArrayRef(Elems) == Ty->elements();
- }
-
- // Get the coercion type as a literal struct type.
- llvm::Type *getType() const {
- if (Elems.size() == 1)
- return Elems.front();
- else
- return llvm::StructType::get(Context, Elems);
- }
- };
-};
-} // end anonymous namespace
-
-ABIArgInfo
-SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
- if (Ty->isVoidType())
- return ABIArgInfo::getIgnore();
-
- uint64_t Size = getContext().getTypeSize(Ty);
-
- // Anything too big to fit in registers is passed with an explicit indirect
- // pointer / sret pointer.
- if (Size > SizeLimit)
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- // Integer types smaller than a register are extended.
- if (Size < 64 && Ty->isIntegerType())
- return ABIArgInfo::getExtend(Ty);
-
- // Other non-aggregates go in registers.
- if (!isAggregateTypeForABI(Ty))
- return ABIArgInfo::getDirect();
-
- // If a C++ object has either a non-trivial copy constructor or a non-trivial
- // destructor, it is passed with an explicit indirect pointer / sret pointer.
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
- // This is a small aggregate type that should be passed in registers.
- // Build a coercion type from the LLVM struct type.
- llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
- if (!StrTy)
- return ABIArgInfo::getDirect();
-
- CoerceBuilder CB(getVMContext(), getDataLayout());
- CB.addStruct(0, StrTy);
- CB.pad(llvm::alignTo(CB.DL.getTypeSizeInBits(StrTy), 64));
-
- // Try to use the original type for coercion.
- llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
-
- if (CB.InReg)
- return ABIArgInfo::getDirectInReg(CoerceTy);
- else
- return ABIArgInfo::getDirect(CoerceTy);
-}
-
-Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- ABIArgInfo AI = classifyType(Ty, 16 * 8);
- llvm::Type *ArgTy = CGT.ConvertType(Ty);
- if (AI.canHaveCoerceToType() && !AI.getCoerceToType())
- AI.setCoerceToType(ArgTy);
-
- CharUnits SlotSize = CharUnits::fromQuantity(8);
-
- CGBuilderTy &Builder = CGF.Builder;
- Address Addr(Builder.CreateLoad(VAListAddr, "ap.cur"), SlotSize);
- llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy);
-
- auto TypeInfo = getContext().getTypeInfoInChars(Ty);
-
- Address ArgAddr = Address::invalid();
- CharUnits Stride;
- switch (AI.getKind()) {
- case ABIArgInfo::Expand:
- case ABIArgInfo::CoerceAndExpand:
- case ABIArgInfo::InAlloca:
- llvm_unreachable("Unsupported ABI kind for va_arg");
-
- case ABIArgInfo::Extend: {
- Stride = SlotSize;
- CharUnits Offset = SlotSize - TypeInfo.first;
- ArgAddr = Builder.CreateConstInBoundsByteGEP(Addr, Offset, "extend");
- break;
- }
-
- case ABIArgInfo::Direct: {
- auto AllocSize = getDataLayout().getTypeAllocSize(AI.getCoerceToType());
- Stride = CharUnits::fromQuantity(AllocSize).alignTo(SlotSize);
- ArgAddr = Addr;
- break;
- }
-
- case ABIArgInfo::Indirect:
- Stride = SlotSize;
- ArgAddr = Builder.CreateElementBitCast(Addr, ArgPtrTy, "indirect");
- ArgAddr = Address(Builder.CreateLoad(ArgAddr, "indirect.arg"),
- TypeInfo.second);
- break;
-
- case ABIArgInfo::Ignore:
- return Address(llvm::UndefValue::get(ArgPtrTy), TypeInfo.second);
- }
-
- // Update VAList.
- llvm::Value *NextPtr =
- Builder.CreateConstInBoundsByteGEP(Addr.getPointer(), Stride, "ap.next");
- Builder.CreateStore(NextPtr, VAListAddr);
-
- return Builder.CreateBitCast(ArgAddr, ArgPtrTy, "arg.addr");
-}
-
-void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8);
- for (auto &I : FI.arguments())
- I.info = classifyType(I.type, 16 * 8);
-}
-
-namespace {
-class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {}
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
- return 14;
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const override;
-};
-} // end anonymous namespace
-
-bool
-SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- // This is calculated from the LLVM and GCC tables and verified
- // against gcc output. AFAIK all ABIs use the same encoding.
-
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
-
- llvm::IntegerType *i8 = CGF.Int8Ty;
- llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
- llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
-
- // 0-31: the 8-byte general-purpose registers
- AssignToArrayRange(Builder, Address, Eight8, 0, 31);
-
- // 32-63: f0-31, the 4-byte floating-point registers
- AssignToArrayRange(Builder, Address, Four8, 32, 63);
-
- // Y = 64
- // PSR = 65
- // WIM = 66
- // TBR = 67
- // PC = 68
- // NPC = 69
- // FSR = 70
- // CSR = 71
- AssignToArrayRange(Builder, Address, Eight8, 64, 71);
-
- // 72-87: d0-15, the 8-byte floating-point registers
- AssignToArrayRange(Builder, Address, Eight8, 72, 87);
-
- return false;
-}
-
-// ARC ABI implementation.
-namespace {
-
-class ARCABIInfo : public DefaultABIInfo {
-public:
- using DefaultABIInfo::DefaultABIInfo;
-
-private:
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const {
- if (!State.FreeRegs)
- return;
- if (Info.isIndirect() && Info.getInReg())
- State.FreeRegs--;
- else if (Info.isDirect() && Info.getInReg()) {
- unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32;
- if (sz < State.FreeRegs)
- State.FreeRegs -= sz;
- else
- State.FreeRegs = 0;
- }
- }
-
- void computeInfo(CGFunctionInfo &FI) const override {
- CCState State(FI.getCallingConvention());
- // ARC uses 8 registers to pass arguments.
- State.FreeRegs = 8;
-
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- updateState(FI.getReturnInfo(), FI.getReturnType(), State);
- for (auto &I : FI.arguments()) {
- I.info = classifyArgumentType(I.type, State.FreeRegs);
- updateState(I.info, I.type, State);
- }
- }
-
- ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const;
- ABIArgInfo getIndirectByValue(QualType Ty) const;
- ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const;
- ABIArgInfo classifyReturnType(QualType RetTy) const;
-};
-
-class ARCTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- ARCTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new ARCABIInfo(CGT)) {}
-};
-
-
-ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const {
- return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) :
- getNaturalAlignIndirect(Ty, false);
-}
-
-ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const {
- // Compute the byval alignment.
- const unsigned MinABIStackAlignInBytes = 4;
- unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true,
- TypeAlign > MinABIStackAlignInBytes);
-}
-
-Address ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
- getContext().getTypeInfoInChars(Ty),
- CharUnits::fromQuantity(4), true);
-}
-
-ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty,
- uint8_t FreeRegs) const {
- // Handle the generic C++ ABI.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (RT) {
- CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
- if (RAA == CGCXXABI::RAA_Indirect)
- return getIndirectByRef(Ty, FreeRegs > 0);
-
- if (RAA == CGCXXABI::RAA_DirectInMemory)
- return getIndirectByValue(Ty);
- }
-
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32;
-
- if (isAggregateTypeForABI(Ty)) {
- // Structures with flexible arrays are always indirect.
- if (RT && RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectByValue(Ty);
-
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
-
- llvm::LLVMContext &LLVMContext = getVMContext();
-
- llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
- SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
- llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
-
- return FreeRegs >= SizeInRegs ?
- ABIArgInfo::getDirectInReg(Result) :
- ABIArgInfo::getDirect(Result, 0, nullptr, false);
- }
-
- return Ty->isPromotableIntegerType() ?
- (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) :
- ABIArgInfo::getExtend(Ty)) :
- (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() :
- ABIArgInfo::getDirect());
-}
-
-ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isAnyComplexType())
- return ABIArgInfo::getDirectInReg();
-
- // Arguments of size > 4 registers are indirect.
- auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32;
- if (RetSize > 4)
- return getIndirectByRef(RetTy, /*HasFreeRegs*/ true);
-
- return DefaultABIInfo::classifyReturnType(RetTy);
-}
-
-} // End anonymous namespace.
-
-//===----------------------------------------------------------------------===//
-// XCore ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-/// A SmallStringEnc instance is used to build up the TypeString by passing
-/// it by reference between functions that append to it.
-typedef llvm::SmallString<128> SmallStringEnc;
-
-/// TypeStringCache caches the meta encodings of Types.
-///
-/// The reason for caching TypeStrings is two fold:
-/// 1. To cache a type's encoding for later uses;
-/// 2. As a means to break recursive member type inclusion.
-///
-/// A cache Entry can have a Status of:
-/// NonRecursive: The type encoding is not recursive;
-/// Recursive: The type encoding is recursive;
-/// Incomplete: An incomplete TypeString;
-/// IncompleteUsed: An incomplete TypeString that has been used in a
-/// Recursive type encoding.
-///
-/// A NonRecursive entry will have all of its sub-members expanded as fully
-/// as possible. Whilst it may contain types which are recursive, the type
-/// itself is not recursive and thus its encoding may be safely used whenever
-/// the type is encountered.
-///
-/// A Recursive entry will have all of its sub-members expanded as fully as
-/// possible. The type itself is recursive and it may contain other types which
-/// are recursive. The Recursive encoding must not be used during the expansion
-/// of a recursive type's recursive branch. For simplicity the code uses
-/// IncompleteCount to reject all usage of Recursive encodings for member types.
-///
-/// An Incomplete entry is always a RecordType and only encodes its
-/// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and
-/// are placed into the cache during type expansion as a means to identify and
-/// handle recursive inclusion of types as sub-members. If there is recursion
-/// the entry becomes IncompleteUsed.
-///
-/// During the expansion of a RecordType's members:
-///
-/// If the cache contains a NonRecursive encoding for the member type, the
-/// cached encoding is used;
-///
-/// If the cache contains a Recursive encoding for the member type, the
-/// cached encoding is 'Swapped' out, as it may be incorrect, and...
-///
-/// If the member is a RecordType, an Incomplete encoding is placed into the
-/// cache to break potential recursive inclusion of itself as a sub-member;
-///
-/// Once a member RecordType has been expanded, its temporary incomplete
-/// entry is removed from the cache. If a Recursive encoding was swapped out
-/// it is swapped back in;
-///
-/// If an incomplete entry is used to expand a sub-member, the incomplete
-/// entry is marked as IncompleteUsed. The cache keeps count of how many
-/// IncompleteUsed entries it currently contains in IncompleteUsedCount;
-///
-/// If a member's encoding is found to be a NonRecursive or Recursive viz:
-/// IncompleteUsedCount==0, the member's encoding is added to the cache.
-/// Else the member is part of a recursive type and thus the recursion has
-/// been exited too soon for the encoding to be correct for the member.
-///
-class TypeStringCache {
- enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed};
- struct Entry {
- std::string Str; // The encoded TypeString for the type.
- enum Status State; // Information about the encoding in 'Str'.
- std::string Swapped; // A temporary place holder for a Recursive encoding
- // during the expansion of RecordType's members.
- };
- std::map<const IdentifierInfo *, struct Entry> Map;
- unsigned IncompleteCount; // Number of Incomplete entries in the Map.
- unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map.
-public:
- TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {}
- void addIncomplete(const IdentifierInfo *ID, std::string StubEnc);
- bool removeIncomplete(const IdentifierInfo *ID);
- void addIfComplete(const IdentifierInfo *ID, StringRef Str,
- bool IsRecursive);
- StringRef lookupStr(const IdentifierInfo *ID);
-};
-
-/// TypeString encodings for enum & union fields must be order.
-/// FieldEncoding is a helper for this ordering process.
-class FieldEncoding {
- bool HasName;
- std::string Enc;
-public:
- FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {}
- StringRef str() { return Enc; }
- bool operator<(const FieldEncoding &rhs) const {
- if (HasName != rhs.HasName) return HasName;
- return Enc < rhs.Enc;
- }
-};
-
-class XCoreABIInfo : public DefaultABIInfo {
-public:
- XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-};
-
-class XCoreTargetCodeGenInfo : public TargetCodeGenInfo {
- mutable TypeStringCache TSC;
-public:
- XCoreTargetCodeGenInfo(CodeGenTypes &CGT)
- :TargetCodeGenInfo(new XCoreABIInfo(CGT)) {}
- void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
-};
-
-} // End anonymous namespace.
-
-// TODO: this implementation is likely now redundant with the default
-// EmitVAArg.
-Address XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- CGBuilderTy &Builder = CGF.Builder;
-
- // Get the VAList.
- CharUnits SlotSize = CharUnits::fromQuantity(4);
- Address AP(Builder.CreateLoad(VAListAddr), SlotSize);
-
- // Handle the argument.
- ABIArgInfo AI = classifyArgumentType(Ty);
- CharUnits TypeAlign = getContext().getTypeAlignInChars(Ty);
- llvm::Type *ArgTy = CGT.ConvertType(Ty);
- if (AI.canHaveCoerceToType() && !AI.getCoerceToType())
- AI.setCoerceToType(ArgTy);
- llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy);
-
- Address Val = Address::invalid();
- CharUnits ArgSize = CharUnits::Zero();
- switch (AI.getKind()) {
- case ABIArgInfo::Expand:
- case ABIArgInfo::CoerceAndExpand:
- case ABIArgInfo::InAlloca:
- llvm_unreachable("Unsupported ABI kind for va_arg");
- case ABIArgInfo::Ignore:
- Val = Address(llvm::UndefValue::get(ArgPtrTy), TypeAlign);
- ArgSize = CharUnits::Zero();
- break;
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct:
- Val = Builder.CreateBitCast(AP, ArgPtrTy);
- ArgSize = CharUnits::fromQuantity(
- getDataLayout().getTypeAllocSize(AI.getCoerceToType()));
- ArgSize = ArgSize.alignTo(SlotSize);
- break;
- case ABIArgInfo::Indirect:
- Val = Builder.CreateElementBitCast(AP, ArgPtrTy);
- Val = Address(Builder.CreateLoad(Val), TypeAlign);
- ArgSize = SlotSize;
- break;
- }
-
- // Increment the VAList.
- if (!ArgSize.isZero()) {
- llvm::Value *APN =
- Builder.CreateConstInBoundsByteGEP(AP.getPointer(), ArgSize);
- Builder.CreateStore(APN, VAListAddr);
- }
-
- return Val;
-}
-
-/// During the expansion of a RecordType, an incomplete TypeString is placed
-/// into the cache as a means to identify and break recursion.
-/// If there is a Recursive encoding in the cache, it is swapped out and will
-/// be reinserted by removeIncomplete().
-/// All other types of encoding should have been used rather than arriving here.
-void TypeStringCache::addIncomplete(const IdentifierInfo *ID,
- std::string StubEnc) {
- if (!ID)
- return;
- Entry &E = Map[ID];
- assert( (E.Str.empty() || E.State == Recursive) &&
- "Incorrectly use of addIncomplete");
- assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()");
- E.Swapped.swap(E.Str); // swap out the Recursive
- E.Str.swap(StubEnc);
- E.State = Incomplete;
- ++IncompleteCount;
-}
-
-/// Once the RecordType has been expanded, the temporary incomplete TypeString
-/// must be removed from the cache.
-/// If a Recursive was swapped out by addIncomplete(), it will be replaced.
-/// Returns true if the RecordType was defined recursively.
-bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) {
- if (!ID)
- return false;
- auto I = Map.find(ID);
- assert(I != Map.end() && "Entry not present");
- Entry &E = I->second;
- assert( (E.State == Incomplete ||
- E.State == IncompleteUsed) &&
- "Entry must be an incomplete type");
- bool IsRecursive = false;
- if (E.State == IncompleteUsed) {
- // We made use of our Incomplete encoding, thus we are recursive.
- IsRecursive = true;
- --IncompleteUsedCount;
- }
- if (E.Swapped.empty())
- Map.erase(I);
- else {
- // Swap the Recursive back.
- E.Swapped.swap(E.Str);
- E.Swapped.clear();
- E.State = Recursive;
- }
- --IncompleteCount;
- return IsRecursive;
-}
-
-/// Add the encoded TypeString to the cache only if it is NonRecursive or
-/// Recursive (viz: all sub-members were expanded as fully as possible).
-void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str,
- bool IsRecursive) {
- if (!ID || IncompleteUsedCount)
- return; // No key or it is is an incomplete sub-type so don't add.
- Entry &E = Map[ID];
- if (IsRecursive && !E.Str.empty()) {
- assert(E.State==Recursive && E.Str.size() == Str.size() &&
- "This is not the same Recursive entry");
- // The parent container was not recursive after all, so we could have used
- // this Recursive sub-member entry after all, but we assumed the worse when
- // we started viz: IncompleteCount!=0.
- return;
- }
- assert(E.Str.empty() && "Entry already present");
- E.Str = Str.str();
- E.State = IsRecursive? Recursive : NonRecursive;
-}
-
-/// Return a cached TypeString encoding for the ID. If there isn't one, or we
-/// are recursively expanding a type (IncompleteCount != 0) and the cached
-/// encoding is Recursive, return an empty StringRef.
-StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) {
- if (!ID)
- return StringRef(); // We have no key.
- auto I = Map.find(ID);
- if (I == Map.end())
- return StringRef(); // We have no encoding.
- Entry &E = I->second;
- if (E.State == Recursive && IncompleteCount)
- return StringRef(); // We don't use Recursive encodings for member types.
-
- if (E.State == Incomplete) {
- // The incomplete type is being used to break out of recursion.
- E.State = IncompleteUsed;
- ++IncompleteUsedCount;
- }
- return E.Str;
-}
-
-/// The XCore ABI includes a type information section that communicates symbol
-/// type information to the linker. The linker uses this information to verify
-/// safety/correctness of things such as array bound and pointers et al.
-/// The ABI only requires C (and XC) language modules to emit TypeStrings.
-/// This type information (TypeString) is emitted into meta data for all global
-/// symbols: definitions, declarations, functions & variables.
-///
-/// The TypeString carries type, qualifier, name, size & value details.
-/// Please see 'Tools Development Guide' section 2.16.2 for format details:
-/// https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf
-/// The output is tested by test/CodeGen/xcore-stringtype.c.
-///
-static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
- CodeGen::CodeGenModule &CGM, TypeStringCache &TSC);
-
-/// XCore uses emitTargetMD to emit TypeString metadata for global symbols.
-void XCoreTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
- SmallStringEnc Enc;
- if (getTypeString(Enc, D, CGM, TSC)) {
- llvm::LLVMContext &Ctx = CGM.getModule().getContext();
- llvm::Metadata *MDVals[] = {llvm::ConstantAsMetadata::get(GV),
- llvm::MDString::get(Ctx, Enc.str())};
- llvm::NamedMDNode *MD =
- CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings");
- MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
- }
-}
-
-//===----------------------------------------------------------------------===//
-// SPIR ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-class SPIRTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- SPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
- unsigned getOpenCLKernelCallingConv() const override;
-};
-
-} // End anonymous namespace.
-
-namespace clang {
-namespace CodeGen {
-void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) {
- DefaultABIInfo SPIRABI(CGM.getTypes());
- SPIRABI.computeInfo(FI);
-}
-}
-}
-
-unsigned SPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
- return llvm::CallingConv::SPIR_KERNEL;
-}
-
-static bool appendType(SmallStringEnc &Enc, QualType QType,
- const CodeGen::CodeGenModule &CGM,
- TypeStringCache &TSC);
-
-/// Helper function for appendRecordType().
-/// Builds a SmallVector containing the encoded field types in declaration
-/// order.
-static bool extractFieldType(SmallVectorImpl<FieldEncoding> &FE,
- const RecordDecl *RD,
- const CodeGen::CodeGenModule &CGM,
- TypeStringCache &TSC) {
- for (const auto *Field : RD->fields()) {
- SmallStringEnc Enc;
- Enc += "m(";
- Enc += Field->getName();
- Enc += "){";
- if (Field->isBitField()) {
- Enc += "b(";
- llvm::raw_svector_ostream OS(Enc);
- OS << Field->getBitWidthValue(CGM.getContext());
- Enc += ':';
- }
- if (!appendType(Enc, Field->getType(), CGM, TSC))
- return false;
- if (Field->isBitField())
- Enc += ')';
- Enc += '}';
- FE.emplace_back(!Field->getName().empty(), Enc);
- }
- return true;
-}
-
-/// Appends structure and union types to Enc and adds encoding to cache.
-/// Recursively calls appendType (via extractFieldType) for each field.
-/// Union types have their fields ordered according to the ABI.
-static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT,
- const CodeGen::CodeGenModule &CGM,
- TypeStringCache &TSC, const IdentifierInfo *ID) {
- // Append the cached TypeString if we have one.
- StringRef TypeString = TSC.lookupStr(ID);
- if (!TypeString.empty()) {
- Enc += TypeString;
- return true;
- }
-
- // Start to emit an incomplete TypeString.
- size_t Start = Enc.size();
- Enc += (RT->isUnionType()? 'u' : 's');
- Enc += '(';
- if (ID)
- Enc += ID->getName();
- Enc += "){";
-
- // We collect all encoded fields and order as necessary.
- bool IsRecursive = false;
- const RecordDecl *RD = RT->getDecl()->getDefinition();
- if (RD && !RD->field_empty()) {
- // An incomplete TypeString stub is placed in the cache for this RecordType
- // so that recursive calls to this RecordType will use it whilst building a
- // complete TypeString for this RecordType.
- SmallVector<FieldEncoding, 16> FE;
- std::string StubEnc(Enc.substr(Start).str());
- StubEnc += '}'; // StubEnc now holds a valid incomplete TypeString.
- TSC.addIncomplete(ID, std::move(StubEnc));
- if (!extractFieldType(FE, RD, CGM, TSC)) {
- (void) TSC.removeIncomplete(ID);
- return false;
- }
- IsRecursive = TSC.removeIncomplete(ID);
- // The ABI requires unions to be sorted but not structures.
- // See FieldEncoding::operator< for sort algorithm.
- if (RT->isUnionType())
- llvm::sort(FE);
- // We can now complete the TypeString.
- unsigned E = FE.size();
- for (unsigned I = 0; I != E; ++I) {
- if (I)
- Enc += ',';
- Enc += FE[I].str();
- }
- }
- Enc += '}';
- TSC.addIfComplete(ID, Enc.substr(Start), IsRecursive);
- return true;
-}
-
-/// Appends enum types to Enc and adds the encoding to the cache.
-static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET,
- TypeStringCache &TSC,
- const IdentifierInfo *ID) {
- // Append the cached TypeString if we have one.
- StringRef TypeString = TSC.lookupStr(ID);
- if (!TypeString.empty()) {
- Enc += TypeString;
- return true;
- }
-
- size_t Start = Enc.size();
- Enc += "e(";
- if (ID)
- Enc += ID->getName();
- Enc += "){";
-
- // We collect all encoded enumerations and order them alphanumerically.
- if (const EnumDecl *ED = ET->getDecl()->getDefinition()) {
- SmallVector<FieldEncoding, 16> FE;
- for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E;
- ++I) {
- SmallStringEnc EnumEnc;
- EnumEnc += "m(";
- EnumEnc += I->getName();
- EnumEnc += "){";
- I->getInitVal().toString(EnumEnc);
- EnumEnc += '}';
- FE.push_back(FieldEncoding(!I->getName().empty(), EnumEnc));
- }
- llvm::sort(FE);
- unsigned E = FE.size();
- for (unsigned I = 0; I != E; ++I) {
- if (I)
- Enc += ',';
- Enc += FE[I].str();
- }
- }
- Enc += '}';
- TSC.addIfComplete(ID, Enc.substr(Start), false);
- return true;
-}
-
-/// Appends type's qualifier to Enc.
-/// This is done prior to appending the type's encoding.
-static void appendQualifier(SmallStringEnc &Enc, QualType QT) {
- // Qualifiers are emitted in alphabetical order.
- static const char *const Table[]={"","c:","r:","cr:","v:","cv:","rv:","crv:"};
- int Lookup = 0;
- if (QT.isConstQualified())
- Lookup += 1<<0;
- if (QT.isRestrictQualified())
- Lookup += 1<<1;
- if (QT.isVolatileQualified())
- Lookup += 1<<2;
- Enc += Table[Lookup];
-}
-
-/// Appends built-in types to Enc.
-static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) {
- const char *EncType;
- switch (BT->getKind()) {
- case BuiltinType::Void:
- EncType = "0";
- break;
- case BuiltinType::Bool:
- EncType = "b";
- break;
- case BuiltinType::Char_U:
- EncType = "uc";
- break;
- case BuiltinType::UChar:
- EncType = "uc";
- break;
- case BuiltinType::SChar:
- EncType = "sc";
- break;
- case BuiltinType::UShort:
- EncType = "us";
- break;
- case BuiltinType::Short:
- EncType = "ss";
- break;
- case BuiltinType::UInt:
- EncType = "ui";
- break;
- case BuiltinType::Int:
- EncType = "si";
- break;
- case BuiltinType::ULong:
- EncType = "ul";
- break;
- case BuiltinType::Long:
- EncType = "sl";
- break;
- case BuiltinType::ULongLong:
- EncType = "ull";
- break;
- case BuiltinType::LongLong:
- EncType = "sll";
- break;
- case BuiltinType::Float:
- EncType = "ft";
- break;
- case BuiltinType::Double:
- EncType = "d";
- break;
- case BuiltinType::LongDouble:
- EncType = "ld";
- break;
- default:
- return false;
- }
- Enc += EncType;
- return true;
-}
-
-/// Appends a pointer encoding to Enc before calling appendType for the pointee.
-static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT,
- const CodeGen::CodeGenModule &CGM,
- TypeStringCache &TSC) {
- Enc += "p(";
- if (!appendType(Enc, PT->getPointeeType(), CGM, TSC))
- return false;
- Enc += ')';
- return true;
-}
-
-/// Appends array encoding to Enc before calling appendType for the element.
-static bool appendArrayType(SmallStringEnc &Enc, QualType QT,
- const ArrayType *AT,
- const CodeGen::CodeGenModule &CGM,
- TypeStringCache &TSC, StringRef NoSizeEnc) {
- if (AT->getSizeModifier() != ArrayType::Normal)
- return false;
- Enc += "a(";
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
- CAT->getSize().toStringUnsigned(Enc);
- else
- Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "".
- Enc += ':';
- // The Qualifiers should be attached to the type rather than the array.
- appendQualifier(Enc, QT);
- if (!appendType(Enc, AT->getElementType(), CGM, TSC))
- return false;
- Enc += ')';
- return true;
-}
-
-/// Appends a function encoding to Enc, calling appendType for the return type
-/// and the arguments.
-static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT,
- const CodeGen::CodeGenModule &CGM,
- TypeStringCache &TSC) {
- Enc += "f{";
- if (!appendType(Enc, FT->getReturnType(), CGM, TSC))
- return false;
- Enc += "}(";
- if (const FunctionProtoType *FPT = FT->getAs<FunctionProtoType>()) {
- // N.B. we are only interested in the adjusted param types.
- auto I = FPT->param_type_begin();
- auto E = FPT->param_type_end();
- if (I != E) {
- do {
- if (!appendType(Enc, *I, CGM, TSC))
- return false;
- ++I;
- if (I != E)
- Enc += ',';
- } while (I != E);
- if (FPT->isVariadic())
- Enc += ",va";
- } else {
- if (FPT->isVariadic())
- Enc += "va";
- else
- Enc += '0';
- }
- }
- Enc += ')';
- return true;
-}
-
-/// Handles the type's qualifier before dispatching a call to handle specific
-/// type encodings.
-static bool appendType(SmallStringEnc &Enc, QualType QType,
- const CodeGen::CodeGenModule &CGM,
- TypeStringCache &TSC) {
-
- QualType QT = QType.getCanonicalType();
-
- if (const ArrayType *AT = QT->getAsArrayTypeUnsafe())
- // The Qualifiers should be attached to the type rather than the array.
- // Thus we don't call appendQualifier() here.
- return appendArrayType(Enc, QT, AT, CGM, TSC, "");
-
- appendQualifier(Enc, QT);
-
- if (const BuiltinType *BT = QT->getAs<BuiltinType>())
- return appendBuiltinType(Enc, BT);
-
- if (const PointerType *PT = QT->getAs<PointerType>())
- return appendPointerType(Enc, PT, CGM, TSC);
-
- if (const EnumType *ET = QT->getAs<EnumType>())
- return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier());
-
- if (const RecordType *RT = QT->getAsStructureType())
- return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
-
- if (const RecordType *RT = QT->getAsUnionType())
- return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
-
- if (const FunctionType *FT = QT->getAs<FunctionType>())
- return appendFunctionType(Enc, FT, CGM, TSC);
-
- return false;
-}
-
-static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
- CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) {
- if (!D)
- return false;
-
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->getLanguageLinkage() != CLanguageLinkage)
- return false;
- return appendType(Enc, FD->getType(), CGM, TSC);
- }
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (VD->getLanguageLinkage() != CLanguageLinkage)
- return false;
- QualType QT = VD->getType().getCanonicalType();
- if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) {
- // Global ArrayTypes are given a size of '*' if the size is unknown.
- // The Qualifiers should be attached to the type rather than the array.
- // Thus we don't call appendQualifier() here.
- return appendArrayType(Enc, QT, AT, CGM, TSC, "*");
- }
- return appendType(Enc, QT, CGM, TSC);
- }
- return false;
-}
-
-//===----------------------------------------------------------------------===//
-// RISCV ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-class RISCVABIInfo : public DefaultABIInfo {
-private:
- unsigned XLen; // Size of the integer ('x') registers in bits.
- static const int NumArgGPRs = 8;
-
-public:
- RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen)
- : DefaultABIInfo(CGT), XLen(XLen) {}
-
- // DefaultABIInfo's classifyReturnType and classifyArgumentType are
- // non-virtual, but computeInfo is virtual, so we overload it.
- void computeInfo(CGFunctionInfo &FI) const override;
-
- ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed,
- int &ArgGPRsLeft) const;
- ABIArgInfo classifyReturnType(QualType RetTy) const;
-
- Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const override;
-
- ABIArgInfo extendType(QualType Ty) const;
-};
-} // end anonymous namespace
-
-void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
- QualType RetTy = FI.getReturnType();
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(RetTy);
-
- // IsRetIndirect is true if classifyArgumentType indicated the value should
- // be passed indirect or if the type size is greater than 2*xlen. e.g. fp128
- // is passed direct in LLVM IR, relying on the backend lowering code to
- // rewrite the argument list and pass indirectly on RV32.
- bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect ||
- getContext().getTypeSize(RetTy) > (2 * XLen);
-
- // We must track the number of GPRs used in order to conform to the RISC-V
- // ABI, as integer scalars passed in registers should have signext/zeroext
- // when promoted, but are anyext if passed on the stack. As GPR usage is
- // different for variadic arguments, we must also track whether we are
- // examining a vararg or not.
- int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
- int NumFixedArgs = FI.getNumRequiredArgs();
-
- int ArgNum = 0;
- for (auto &ArgInfo : FI.arguments()) {
- bool IsFixed = ArgNum < NumFixedArgs;
- ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft);
- ArgNum++;
- }
-}
-
-ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
- int &ArgGPRsLeft) const {
- assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
- Ty = useFirstFieldIfTransparentUnion(Ty);
-
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always passed indirectly.
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
- if (ArgGPRsLeft)
- ArgGPRsLeft -= 1;
- return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
- CGCXXABI::RAA_DirectInMemory);
- }
-
- // Ignore empty structs/unions.
- if (isEmptyRecord(getContext(), Ty, true))
- return ABIArgInfo::getIgnore();
-
- uint64_t Size = getContext().getTypeSize(Ty);
- uint64_t NeededAlign = getContext().getTypeAlign(Ty);
- bool MustUseStack = false;
- // Determine the number of GPRs needed to pass the current argument
- // according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
- // register pairs, so may consume 3 registers.
- int NeededArgGPRs = 1;
- if (!IsFixed && NeededAlign == 2 * XLen)
- NeededArgGPRs = 2 + (ArgGPRsLeft % 2);
- else if (Size > XLen && Size <= 2 * XLen)
- NeededArgGPRs = 2;
-
- if (NeededArgGPRs > ArgGPRsLeft) {
- MustUseStack = true;
- NeededArgGPRs = ArgGPRsLeft;
- }
-
- ArgGPRsLeft -= NeededArgGPRs;
-
- if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- // All integral types are promoted to XLen width, unless passed on the
- // stack.
- if (Size < XLen && Ty->isIntegralOrEnumerationType() && !MustUseStack) {
- return extendType(Ty);
- }
-
- return ABIArgInfo::getDirect();
- }
-
- // Aggregates which are <= 2*XLen will be passed in registers if possible,
- // so coerce to integers.
- if (Size <= 2 * XLen) {
- unsigned Alignment = getContext().getTypeAlign(Ty);
-
- // Use a single XLen int if possible, 2*XLen if 2*XLen alignment is
- // required, and a 2-element XLen array if only XLen alignment is required.
- if (Size <= XLen) {
- return ABIArgInfo::getDirect(
- llvm::IntegerType::get(getVMContext(), XLen));
- } else if (Alignment == 2 * XLen) {
- return ABIArgInfo::getDirect(
- llvm::IntegerType::get(getVMContext(), 2 * XLen));
- } else {
- return ABIArgInfo::getDirect(llvm::ArrayType::get(
- llvm::IntegerType::get(getVMContext(), XLen), 2));
- }
- }
- return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
-}
-
-ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- int ArgGPRsLeft = 2;
-
- // The rules for return and argument types are the same, so defer to
- // classifyArgumentType.
- return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft);
-}
-
-Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
- QualType Ty) const {
- CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
-
- // Empty records are ignored for parameter passing purposes.
- if (isEmptyRecord(getContext(), Ty, true)) {
- Address Addr(CGF.Builder.CreateLoad(VAListAddr), SlotSize);
- Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty));
- return Addr;
- }
-
- std::pair<CharUnits, CharUnits> SizeAndAlign =
- getContext().getTypeInfoInChars(Ty);
-
- // Arguments bigger than 2*Xlen bytes are passed indirectly.
- bool IsIndirect = SizeAndAlign.first > 2 * SlotSize;
-
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, SizeAndAlign,
- SlotSize, /*AllowHigherAlign=*/true);
-}
-
-ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const {
- int TySize = getContext().getTypeSize(Ty);
- // RV64 ABI requires unsigned 32 bit integers to be sign extended.
- if (XLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
- return ABIArgInfo::getSignExtend(Ty);
- return ABIArgInfo::getExtend(Ty);
-}
-
-namespace {
-class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen)
- : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen)) {}
-
- void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
- const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
- if (!FD) return;
-
- const auto *Attr = FD->getAttr<RISCVInterruptAttr>();
- if (!Attr)
- return;
-
- const char *Kind;
- switch (Attr->getInterrupt()) {
- case RISCVInterruptAttr::user: Kind = "user"; break;
- case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break;
- case RISCVInterruptAttr::machine: Kind = "machine"; break;
- }
-
- auto *Fn = cast<llvm::Function>(GV);
-
- Fn->addFnAttr("interrupt", Kind);
- }
-};
-} // namespace
-
-//===----------------------------------------------------------------------===//
-// Driver code
-//===----------------------------------------------------------------------===//
-
-bool CodeGenModule::supportsCOMDAT() const {
- return getTriple().supportsCOMDAT();
-}
-
-const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
- if (TheTargetCodeGenInfo)
- return *TheTargetCodeGenInfo;
-
- // Helper to set the unique_ptr while still keeping the return value.
- auto SetCGInfo = [&](TargetCodeGenInfo *P) -> const TargetCodeGenInfo & {
- this->TheTargetCodeGenInfo.reset(P);
- return *P;
- };
-
- const llvm::Triple &Triple = getTarget().getTriple();
- switch (Triple.getArch()) {
- default:
- return SetCGInfo(new DefaultTargetCodeGenInfo(Types));
-
- case llvm::Triple::le32:
- return SetCGInfo(new PNaClTargetCodeGenInfo(Types));
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- if (Triple.getOS() == llvm::Triple::NaCl)
- return SetCGInfo(new PNaClTargetCodeGenInfo(Types));
- return SetCGInfo(new MIPSTargetCodeGenInfo(Types, true));
-
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- return SetCGInfo(new MIPSTargetCodeGenInfo(Types, false));
-
- case llvm::Triple::avr:
- return SetCGInfo(new AVRTargetCodeGenInfo(Types));
-
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be: {
- AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS;
- if (getTarget().getABI() == "darwinpcs")
- Kind = AArch64ABIInfo::DarwinPCS;
- else if (Triple.isOSWindows())
- return SetCGInfo(
- new WindowsAArch64TargetCodeGenInfo(Types, AArch64ABIInfo::Win64));
-
- return SetCGInfo(new AArch64TargetCodeGenInfo(Types, Kind));
- }
-
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- return SetCGInfo(new WebAssemblyTargetCodeGenInfo(Types));
-
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb: {
- if (Triple.getOS() == llvm::Triple::Win32) {
- return SetCGInfo(
- new WindowsARMTargetCodeGenInfo(Types, ARMABIInfo::AAPCS_VFP));
- }
-
- ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS;
- StringRef ABIStr = getTarget().getABI();
- if (ABIStr == "apcs-gnu")
- Kind = ARMABIInfo::APCS;
- else if (ABIStr == "aapcs16")
- Kind = ARMABIInfo::AAPCS16_VFP;
- else if (CodeGenOpts.FloatABI == "hard" ||
- (CodeGenOpts.FloatABI != "soft" &&
- (Triple.getEnvironment() == llvm::Triple::GNUEABIHF ||
- Triple.getEnvironment() == llvm::Triple::MuslEABIHF ||
- Triple.getEnvironment() == llvm::Triple::EABIHF)))
- Kind = ARMABIInfo::AAPCS_VFP;
-
- return SetCGInfo(new ARMTargetCodeGenInfo(Types, Kind));
- }
-
- case llvm::Triple::ppc: {
- bool RetSmallStructInRegABI =
- PPC32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts);
- return SetCGInfo(
- new PPC32TargetCodeGenInfo(Types, CodeGenOpts.FloatABI == "soft",
- RetSmallStructInRegABI));
- }
- case llvm::Triple::ppc64:
- if (Triple.isOSBinFormatELF()) {
- PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
- if (getTarget().getABI() == "elfv2")
- Kind = PPC64_SVR4_ABIInfo::ELFv2;
- bool HasQPX = getTarget().getABI() == "elfv1-qpx";
- bool IsSoftFloat = CodeGenOpts.FloatABI == "soft";
-
- return SetCGInfo(new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX,
- IsSoftFloat));
- } else
- return SetCGInfo(new PPC64TargetCodeGenInfo(Types));
- case llvm::Triple::ppc64le: {
- assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!");
- PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv2;
- if (getTarget().getABI() == "elfv1" || getTarget().getABI() == "elfv1-qpx")
- Kind = PPC64_SVR4_ABIInfo::ELFv1;
- bool HasQPX = getTarget().getABI() == "elfv1-qpx";
- bool IsSoftFloat = CodeGenOpts.FloatABI == "soft";
-
- return SetCGInfo(new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX,
- IsSoftFloat));
- }
-
- case llvm::Triple::nvptx:
- case llvm::Triple::nvptx64:
- return SetCGInfo(new NVPTXTargetCodeGenInfo(Types));
-
- case llvm::Triple::msp430:
- return SetCGInfo(new MSP430TargetCodeGenInfo(Types));
-
- case llvm::Triple::riscv32:
- return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 32));
- case llvm::Triple::riscv64:
- return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 64));
-
- case llvm::Triple::systemz: {
- bool HasVector = getTarget().getABI() == "vector";
- return SetCGInfo(new SystemZTargetCodeGenInfo(Types, HasVector));
- }
-
- case llvm::Triple::tce:
- case llvm::Triple::tcele:
- return SetCGInfo(new TCETargetCodeGenInfo(Types));
-
- case llvm::Triple::x86: {
- bool IsDarwinVectorABI = Triple.isOSDarwin();
- bool RetSmallStructInRegABI =
- X86_32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts);
- bool IsWin32FloatStructABI = Triple.isOSWindows() && !Triple.isOSCygMing();
-
- if (Triple.getOS() == llvm::Triple::Win32) {
- return SetCGInfo(new WinX86_32TargetCodeGenInfo(
- Types, IsDarwinVectorABI, RetSmallStructInRegABI,
- IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters));
- } else {
- return SetCGInfo(new X86_32TargetCodeGenInfo(
- Types, IsDarwinVectorABI, RetSmallStructInRegABI,
- IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters,
- CodeGenOpts.FloatABI == "soft"));
- }
- }
-
- case llvm::Triple::x86_64: {
- StringRef ABI = getTarget().getABI();
- X86AVXABILevel AVXLevel =
- (ABI == "avx512"
- ? X86AVXABILevel::AVX512
- : ABI == "avx" ? X86AVXABILevel::AVX : X86AVXABILevel::None);
-
- switch (Triple.getOS()) {
- case llvm::Triple::Win32:
- return SetCGInfo(new WinX86_64TargetCodeGenInfo(Types, AVXLevel));
- case llvm::Triple::PS4:
- return SetCGInfo(new PS4TargetCodeGenInfo(Types, AVXLevel));
- default:
- return SetCGInfo(new X86_64TargetCodeGenInfo(Types, AVXLevel));
- }
- }
- case llvm::Triple::hexagon:
- return SetCGInfo(new HexagonTargetCodeGenInfo(Types));
- case llvm::Triple::lanai:
- return SetCGInfo(new LanaiTargetCodeGenInfo(Types));
- case llvm::Triple::r600:
- return SetCGInfo(new AMDGPUTargetCodeGenInfo(Types));
- case llvm::Triple::amdgcn:
- return SetCGInfo(new AMDGPUTargetCodeGenInfo(Types));
- case llvm::Triple::sparc:
- return SetCGInfo(new SparcV8TargetCodeGenInfo(Types));
- case llvm::Triple::sparcv9:
- return SetCGInfo(new SparcV9TargetCodeGenInfo(Types));
- case llvm::Triple::xcore:
- return SetCGInfo(new XCoreTargetCodeGenInfo(Types));
- case llvm::Triple::arc:
- return SetCGInfo(new ARCTargetCodeGenInfo(Types));
- case llvm::Triple::spir:
- case llvm::Triple::spir64:
- return SetCGInfo(new SPIRTargetCodeGenInfo(Types));
- }
-}
-
-/// Create an OpenCL kernel for an enqueued block.
-///
-/// The kernel has the same function type as the block invoke function. Its
-/// name is the name of the block invoke function postfixed with "_kernel".
-/// It simply calls the block invoke function then returns.
-llvm::Function *
-TargetCodeGenInfo::createEnqueuedBlockKernel(CodeGenFunction &CGF,
- llvm::Function *Invoke,
- llvm::Value *BlockLiteral) const {
- auto *InvokeFT = Invoke->getFunctionType();
- llvm::SmallVector<llvm::Type *, 2> ArgTys;
- for (auto &P : InvokeFT->params())
- ArgTys.push_back(P);
- auto &C = CGF.getLLVMContext();
- std::string Name = Invoke->getName().str() + "_kernel";
- auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false);
- auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name,
- &CGF.CGM.getModule());
- auto IP = CGF.Builder.saveIP();
- auto *BB = llvm::BasicBlock::Create(C, "entry", F);
- auto &Builder = CGF.Builder;
- Builder.SetInsertPoint(BB);
- llvm::SmallVector<llvm::Value *, 2> Args;
- for (auto &A : F->args())
- Args.push_back(&A);
- Builder.CreateCall(Invoke, Args);
- Builder.CreateRetVoid();
- Builder.restoreIP(IP);
- return F;
-}
-
-/// Create an OpenCL kernel for an enqueued block.
-///
-/// The type of the first argument (the block literal) is the struct type
-/// of the block literal instead of a pointer type. The first argument
-/// (block literal) is passed directly by value to the kernel. The kernel
-/// allocates the same type of struct on stack and stores the block literal
-/// to it and passes its pointer to the block invoke function. The kernel
-/// has "enqueued-block" function attribute and kernel argument metadata.
-llvm::Function *AMDGPUTargetCodeGenInfo::createEnqueuedBlockKernel(
- CodeGenFunction &CGF, llvm::Function *Invoke,
- llvm::Value *BlockLiteral) const {
- auto &Builder = CGF.Builder;
- auto &C = CGF.getLLVMContext();
-
- auto *BlockTy = BlockLiteral->getType()->getPointerElementType();
- auto *InvokeFT = Invoke->getFunctionType();
- llvm::SmallVector<llvm::Type *, 2> ArgTys;
- llvm::SmallVector<llvm::Metadata *, 8> AddressQuals;
- llvm::SmallVector<llvm::Metadata *, 8> AccessQuals;
- llvm::SmallVector<llvm::Metadata *, 8> ArgTypeNames;
- llvm::SmallVector<llvm::Metadata *, 8> ArgBaseTypeNames;
- llvm::SmallVector<llvm::Metadata *, 8> ArgTypeQuals;
- llvm::SmallVector<llvm::Metadata *, 8> ArgNames;
-
- ArgTys.push_back(BlockTy);
- ArgTypeNames.push_back(llvm::MDString::get(C, "__block_literal"));
- AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(0)));
- ArgBaseTypeNames.push_back(llvm::MDString::get(C, "__block_literal"));
- ArgTypeQuals.push_back(llvm::MDString::get(C, ""));
- AccessQuals.push_back(llvm::MDString::get(C, "none"));
- ArgNames.push_back(llvm::MDString::get(C, "block_literal"));
- for (unsigned I = 1, E = InvokeFT->getNumParams(); I < E; ++I) {
- ArgTys.push_back(InvokeFT->getParamType(I));
- ArgTypeNames.push_back(llvm::MDString::get(C, "void*"));
- AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(3)));
- AccessQuals.push_back(llvm::MDString::get(C, "none"));
- ArgBaseTypeNames.push_back(llvm::MDString::get(C, "void*"));
- ArgTypeQuals.push_back(llvm::MDString::get(C, ""));
- ArgNames.push_back(
- llvm::MDString::get(C, (Twine("local_arg") + Twine(I)).str()));
- }
- std::string Name = Invoke->getName().str() + "_kernel";
- auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false);
- auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name,
- &CGF.CGM.getModule());
- F->addFnAttr("enqueued-block");
- auto IP = CGF.Builder.saveIP();
- auto *BB = llvm::BasicBlock::Create(C, "entry", F);
- Builder.SetInsertPoint(BB);
- unsigned BlockAlign = CGF.CGM.getDataLayout().getPrefTypeAlignment(BlockTy);
- auto *BlockPtr = Builder.CreateAlloca(BlockTy, nullptr);
- BlockPtr->setAlignment(BlockAlign);
- Builder.CreateAlignedStore(F->arg_begin(), BlockPtr, BlockAlign);
- auto *Cast = Builder.CreatePointerCast(BlockPtr, InvokeFT->getParamType(0));
- llvm::SmallVector<llvm::Value *, 2> Args;
- Args.push_back(Cast);
- for (auto I = F->arg_begin() + 1, E = F->arg_end(); I != E; ++I)
- Args.push_back(I);
- Builder.CreateCall(Invoke, Args);
- Builder.CreateRetVoid();
- Builder.restoreIP(IP);
-
- F->setMetadata("kernel_arg_addr_space", llvm::MDNode::get(C, AddressQuals));
- F->setMetadata("kernel_arg_access_qual", llvm::MDNode::get(C, AccessQuals));
- F->setMetadata("kernel_arg_type", llvm::MDNode::get(C, ArgTypeNames));
- F->setMetadata("kernel_arg_base_type",
- llvm::MDNode::get(C, ArgBaseTypeNames));
- F->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(C, ArgTypeQuals));
- if (CGF.CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
- F->setMetadata("kernel_arg_name", llvm::MDNode::get(C, ArgNames));
-
- return F;
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.h b/gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.h
deleted file mode 100644
index b530260ea48..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/TargetInfo.h
+++ /dev/null
@@ -1,311 +0,0 @@
-//===---- TargetInfo.h - Encapsulate target details -------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes wrap the information about a call or function
-// definition used to handle ABI compliancy.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
-#define LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
-
-#include "CodeGenModule.h"
-#include "CGValue.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SyncScope.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
-
-namespace llvm {
-class Constant;
-class GlobalValue;
-class Type;
-class Value;
-}
-
-namespace clang {
-class Decl;
-
-namespace CodeGen {
-class ABIInfo;
-class CallArgList;
-class CodeGenFunction;
-class CGBlockInfo;
-class CGFunctionInfo;
-
-/// TargetCodeGenInfo - This class organizes various target-specific
-/// codegeneration issues, like target-specific attributes, builtins and so
-/// on.
-class TargetCodeGenInfo {
- ABIInfo *Info;
-
-public:
- // WARNING: Acquires the ownership of ABIInfo.
- TargetCodeGenInfo(ABIInfo *info = nullptr) : Info(info) {}
- virtual ~TargetCodeGenInfo();
-
- /// getABIInfo() - Returns ABI info helper for the target.
- const ABIInfo &getABIInfo() const { return *Info; }
-
- /// setTargetAttributes - Provides a convenient hook to handle extra
- /// target-specific attributes for the given global.
- virtual void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const {}
-
- /// emitTargetMD - Provides a convenient hook to handle extra
- /// target-specific metadata for the given global.
- virtual void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const {}
-
- /// Determines the size of struct _Unwind_Exception on this platform,
- /// in 8-bit units. The Itanium ABI defines this as:
- /// struct _Unwind_Exception {
- /// uint64 exception_class;
- /// _Unwind_Exception_Cleanup_Fn exception_cleanup;
- /// uint64 private_1;
- /// uint64 private_2;
- /// };
- virtual unsigned getSizeOfUnwindException() const;
-
- /// Controls whether __builtin_extend_pointer should sign-extend
- /// pointers to uint64_t or zero-extend them (the default). Has
- /// no effect for targets:
- /// - that have 64-bit pointers, or
- /// - that cannot address through registers larger than pointers, or
- /// - that implicitly ignore/truncate the top bits when addressing
- /// through such registers.
- virtual bool extendPointerWithSExt() const { return false; }
-
- /// Determines the DWARF register number for the stack pointer, for
- /// exception-handling purposes. Implements __builtin_dwarf_sp_column.
- ///
- /// Returns -1 if the operation is unsupported by this target.
- virtual int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
- return -1;
- }
-
- /// Initializes the given DWARF EH register-size table, a char*.
- /// Implements __builtin_init_dwarf_reg_size_table.
- ///
- /// Returns true if the operation is unsupported by this target.
- virtual bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- return true;
- }
-
- /// Performs the code-generation required to convert a return
- /// address as stored by the system into the actual address of the
- /// next instruction that will be executed.
- ///
- /// Used by __builtin_extract_return_addr().
- virtual llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- return Address;
- }
-
- /// Performs the code-generation required to convert the address
- /// of an instruction into a return address suitable for storage
- /// by the system in a return slot.
- ///
- /// Used by __builtin_frob_return_addr().
- virtual llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- return Address;
- }
-
- /// Corrects the low-level LLVM type for a given constraint and "usual"
- /// type.
- ///
- /// \returns A pointer to a new LLVM type, possibly the same as the original
- /// on success; 0 on failure.
- virtual llvm::Type *adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- StringRef Constraint,
- llvm::Type *Ty) const {
- return Ty;
- }
-
- /// Adds constraints and types for result registers.
- virtual void addReturnRegisterOutputs(
- CodeGen::CodeGenFunction &CGF, CodeGen::LValue ReturnValue,
- std::string &Constraints, std::vector<llvm::Type *> &ResultRegTypes,
- std::vector<llvm::Type *> &ResultTruncRegTypes,
- std::vector<CodeGen::LValue> &ResultRegDests, std::string &AsmString,
- unsigned NumOutputs) const {}
-
- /// doesReturnSlotInterfereWithArgs - Return true if the target uses an
- /// argument slot for an 'sret' type.
- virtual bool doesReturnSlotInterfereWithArgs() const { return true; }
-
- /// Retrieve the address of a function to call immediately before
- /// calling objc_retainAutoreleasedReturnValue. The
- /// implementation of objc_autoreleaseReturnValue sniffs the
- /// instruction stream following its return address to decide
- /// whether it's a call to objc_retainAutoreleasedReturnValue.
- /// This can be prohibitively expensive, depending on the
- /// relocation model, and so on some targets it instead sniffs for
- /// a particular instruction sequence. This functions returns
- /// that instruction sequence in inline assembly, which will be
- /// empty if none is required.
- virtual StringRef getARCRetainAutoreleasedReturnValueMarker() const {
- return "";
- }
-
- /// Return a constant used by UBSan as a signature to identify functions
- /// possessing type information, or 0 if the platform is unsupported.
- virtual llvm::Constant *
- getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const {
- return nullptr;
- }
-
- /// Determine whether a call to an unprototyped functions under
- /// the given calling convention should use the variadic
- /// convention or the non-variadic convention.
- ///
- /// There's a good reason to make a platform's variadic calling
- /// convention be different from its non-variadic calling
- /// convention: the non-variadic arguments can be passed in
- /// registers (better for performance), and the variadic arguments
- /// can be passed on the stack (also better for performance). If
- /// this is done, however, unprototyped functions *must* use the
- /// non-variadic convention, because C99 states that a call
- /// through an unprototyped function type must succeed if the
- /// function was defined with a non-variadic prototype with
- /// compatible parameters. Therefore, splitting the conventions
- /// makes it impossible to call a variadic function through an
- /// unprototyped type. Since function prototypes came out in the
- /// late 1970s, this is probably an acceptable trade-off.
- /// Nonetheless, not all platforms are willing to make it, and in
- /// particularly x86-64 bends over backwards to make the
- /// conventions compatible.
- ///
- /// The default is false. This is correct whenever:
- /// - the conventions are exactly the same, because it does not
- /// matter and the resulting IR will be somewhat prettier in
- /// certain cases; or
- /// - the conventions are substantively different in how they pass
- /// arguments, because in this case using the variadic convention
- /// will lead to C99 violations.
- ///
- /// However, some platforms make the conventions identical except
- /// for passing additional out-of-band information to a variadic
- /// function: for example, x86-64 passes the number of SSE
- /// arguments in %al. On these platforms, it is desirable to
- /// call unprototyped functions using the variadic convention so
- /// that unprototyped calls to varargs functions still succeed.
- ///
- /// Relatedly, platforms which pass the fixed arguments to this:
- /// A foo(B, C, D);
- /// differently than they would pass them to this:
- /// A foo(B, C, D, ...);
- /// may need to adjust the debugger-support code in Sema to do the
- /// right thing when calling a function with no know signature.
- virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
- const FunctionNoProtoType *fnType) const;
-
- /// Gets the linker options necessary to link a dependent library on this
- /// platform.
- virtual void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const;
-
- /// Gets the linker options necessary to detect object file mismatches on
- /// this platform.
- virtual void getDetectMismatchOption(llvm::StringRef Name,
- llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const {}
-
- /// Get LLVM calling convention for OpenCL kernel.
- virtual unsigned getOpenCLKernelCallingConv() const;
-
- /// Get target specific null pointer.
- /// \param T is the LLVM type of the null pointer.
- /// \param QT is the clang QualType of the null pointer.
- /// \return ConstantPointerNull with the given type \p T.
- /// Each target can override it to return its own desired constant value.
- virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
- llvm::PointerType *T, QualType QT) const;
-
- /// Get target favored AST address space of a global variable for languages
- /// other than OpenCL and CUDA.
- /// If \p D is nullptr, returns the default target favored address space
- /// for global variable.
- virtual LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
- const VarDecl *D) const;
-
- /// Get the AST address space for alloca.
- virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; }
-
- /// Perform address space cast of an expression of pointer type.
- /// \param V is the LLVM value to be casted to another address space.
- /// \param SrcAddr is the language address space of \p V.
- /// \param DestAddr is the targeted language address space.
- /// \param DestTy is the destination LLVM pointer type.
- /// \param IsNonNull is the flag indicating \p V is known to be non null.
- virtual llvm::Value *performAddrSpaceCast(CodeGen::CodeGenFunction &CGF,
- llvm::Value *V, LangAS SrcAddr,
- LangAS DestAddr, llvm::Type *DestTy,
- bool IsNonNull = false) const;
-
- /// Perform address space cast of a constant expression of pointer type.
- /// \param V is the LLVM constant to be casted to another address space.
- /// \param SrcAddr is the language address space of \p V.
- /// \param DestAddr is the targeted language address space.
- /// \param DestTy is the destination LLVM pointer type.
- virtual llvm::Constant *performAddrSpaceCast(CodeGenModule &CGM,
- llvm::Constant *V,
- LangAS SrcAddr, LangAS DestAddr,
- llvm::Type *DestTy) const;
-
- /// Get the syncscope used in LLVM IR.
- virtual llvm::SyncScope::ID getLLVMSyncScopeID(SyncScope S,
- llvm::LLVMContext &C) const;
-
- /// Interface class for filling custom fields of a block literal for OpenCL.
- class TargetOpenCLBlockHelper {
- public:
- typedef std::pair<llvm::Value *, StringRef> ValueTy;
- TargetOpenCLBlockHelper() {}
- virtual ~TargetOpenCLBlockHelper() {}
- /// Get the custom field types for OpenCL blocks.
- virtual llvm::SmallVector<llvm::Type *, 1> getCustomFieldTypes() = 0;
- /// Get the custom field values for OpenCL blocks.
- virtual llvm::SmallVector<ValueTy, 1>
- getCustomFieldValues(CodeGenFunction &CGF, const CGBlockInfo &Info) = 0;
- virtual bool areAllCustomFieldValuesConstant(const CGBlockInfo &Info) = 0;
- /// Get the custom field values for OpenCL blocks if all values are LLVM
- /// constants.
- virtual llvm::SmallVector<llvm::Constant *, 1>
- getCustomFieldValues(CodeGenModule &CGM, const CGBlockInfo &Info) = 0;
- };
- virtual TargetOpenCLBlockHelper *getTargetOpenCLBlockHelper() const {
- return nullptr;
- }
-
- /// Create an OpenCL kernel for an enqueued block. The kernel function is
- /// a wrapper for the block invoke function with target-specific calling
- /// convention and ABI as an OpenCL kernel. The wrapper function accepts
- /// block context and block arguments in target-specific way and calls
- /// the original block invoke function.
- virtual llvm::Function *
- createEnqueuedBlockKernel(CodeGenFunction &CGF,
- llvm::Function *BlockInvokeFunc,
- llvm::Value *BlockLiteral) const;
-
- /// \return true if the target supports alias from the unmangled name to the
- /// mangled name of functions declared within an extern "C" region and marked
- /// as 'used', and having internal linkage.
- virtual bool shouldEmitStaticExternCAliases() const { return true; }
-
- virtual void setCUDAKernelCallingConvention(const FunctionType *&FT) const {}
-};
-
-} // namespace CodeGen
-} // namespace clang
-
-#endif // LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.cpp b/gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.cpp
deleted file mode 100644
index 859cdd4282c..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-//===--- VarBypassDetector.h - Bypass jumps detector --------------*- C++ -*-=//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "VarBypassDetector.h"
-
-#include "clang/AST/Decl.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/Stmt.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-/// Clear the object and pre-process for the given statement, usually function
-/// body statement.
-void VarBypassDetector::Init(const Stmt *Body) {
- FromScopes.clear();
- ToScopes.clear();
- Bypasses.clear();
- Scopes = {{~0U, nullptr}};
- unsigned ParentScope = 0;
- AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
- if (!AlwaysBypassed)
- Detect();
-}
-
-/// Build scope information for a declaration that is part of a DeclStmt.
-/// Returns false if we failed to build scope information and can't tell for
-/// which vars are being bypassed.
-bool VarBypassDetector::BuildScopeInformation(const Decl *D,
- unsigned &ParentScope) {
- const VarDecl *VD = dyn_cast<VarDecl>(D);
- if (VD && VD->hasLocalStorage()) {
- Scopes.push_back({ParentScope, VD});
- ParentScope = Scopes.size() - 1;
- }
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(D))
- if (const Expr *Init = VD->getInit())
- return BuildScopeInformation(Init, ParentScope);
-
- return true;
-}
-
-/// Walk through the statements, adding any labels or gotos to
-/// LabelAndGotoScopes and recursively walking the AST as needed.
-/// Returns false if we failed to build scope information and can't tell for
-/// which vars are being bypassed.
-bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
- unsigned &origParentScope) {
- // If this is a statement, rather than an expression, scopes within it don't
- // propagate out into the enclosing scope. Otherwise we have to worry about
- // block literals, which have the lifetime of their enclosing statement.
- unsigned independentParentScope = origParentScope;
- unsigned &ParentScope =
- ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope
- : independentParentScope);
-
- unsigned StmtsToSkip = 0u;
-
- switch (S->getStmtClass()) {
- case Stmt::IndirectGotoStmtClass:
- return false;
-
- case Stmt::SwitchStmtClass:
- if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
- if (!BuildScopeInformation(Init, ParentScope))
- return false;
- ++StmtsToSkip;
- }
- if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
- if (!BuildScopeInformation(Var, ParentScope))
- return false;
- ++StmtsToSkip;
- }
- LLVM_FALLTHROUGH;
-
- case Stmt::GotoStmtClass:
- FromScopes.push_back({S, ParentScope});
- break;
-
- case Stmt::DeclStmtClass: {
- const DeclStmt *DS = cast<DeclStmt>(S);
- for (auto *I : DS->decls())
- if (!BuildScopeInformation(I, origParentScope))
- return false;
- return true;
- }
-
- case Stmt::CaseStmtClass:
- case Stmt::DefaultStmtClass:
- case Stmt::LabelStmtClass:
- llvm_unreachable("the loop below handles labels and cases");
- break;
-
- default:
- break;
- }
-
- for (const Stmt *SubStmt : S->children()) {
- if (!SubStmt)
- continue;
- if (StmtsToSkip) {
- --StmtsToSkip;
- continue;
- }
-
- // Cases, labels, and defaults aren't "scope parents". It's also
- // important to handle these iteratively instead of recursively in
- // order to avoid blowing out the stack.
- while (true) {
- const Stmt *Next;
- if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
- Next = SC->getSubStmt();
- else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
- Next = LS->getSubStmt();
- else
- break;
-
- ToScopes[SubStmt] = ParentScope;
- SubStmt = Next;
- }
-
- // Recursively walk the AST.
- if (!BuildScopeInformation(SubStmt, ParentScope))
- return false;
- }
- return true;
-}
-
-/// Checks each jump and stores each variable declaration they bypass.
-void VarBypassDetector::Detect() {
- for (const auto &S : FromScopes) {
- const Stmt *St = S.first;
- unsigned from = S.second;
- if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
- if (const LabelStmt *LS = GS->getLabel()->getStmt())
- Detect(from, ToScopes[LS]);
- } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
- for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
- SC = SC->getNextSwitchCase()) {
- Detect(from, ToScopes[SC]);
- }
- } else {
- llvm_unreachable("goto or switch was expected");
- }
- }
-}
-
-/// Checks the jump and stores each variable declaration it bypasses.
-void VarBypassDetector::Detect(unsigned From, unsigned To) {
- while (From != To) {
- if (From < To) {
- assert(Scopes[To].first < To);
- const auto &ScopeTo = Scopes[To];
- To = ScopeTo.first;
- Bypasses.insert(ScopeTo.second);
- } else {
- assert(Scopes[From].first < From);
- From = Scopes[From].first;
- }
- }
-}
diff --git a/gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.h b/gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.h
deleted file mode 100644
index 47fe13cfacd..00000000000
--- a/gnu/llvm/tools/clang/lib/CodeGen/VarBypassDetector.h
+++ /dev/null
@@ -1,71 +0,0 @@
-//===--- VarBypassDetector.cpp - Bypass jumps detector ------------*- C++ -*-=//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains VarBypassDetector class, which is used to detect
-// local variable declarations which can be bypassed by jumps.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_VARBYPASSDETECTOR_H
-#define LLVM_CLANG_LIB_CODEGEN_VARBYPASSDETECTOR_H
-
-#include "clang/AST/Decl.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallVector.h"
-
-namespace clang {
-
-class Decl;
-class Stmt;
-class VarDecl;
-
-namespace CodeGen {
-
-/// The class detects jumps which bypass local variables declaration:
-/// goto L;
-/// int a;
-/// L:
-///
-/// This is simplified version of JumpScopeChecker. Primary differences:
-/// * Detects only jumps into the scope local variables.
-/// * Does not detect jumps out of the scope of local variables.
-/// * Not limited to variables with initializers, JumpScopeChecker is limited.
-class VarBypassDetector {
- // Scope information. Contains a parent scope and related variable
- // declaration.
- llvm::SmallVector<std::pair<unsigned, const VarDecl *>, 48> Scopes;
- // List of jumps with scopes.
- llvm::SmallVector<std::pair<const Stmt *, unsigned>, 16> FromScopes;
- // Lookup map to find scope for destinations.
- llvm::DenseMap<const Stmt *, unsigned> ToScopes;
- // Set of variables which were bypassed by some jump.
- llvm::DenseSet<const VarDecl *> Bypasses;
- // If true assume that all variables are being bypassed.
- bool AlwaysBypassed = false;
-
-public:
- void Init(const Stmt *Body);
-
- /// Returns true if the variable declaration was by bypassed by any goto or
- /// switch statement.
- bool IsBypassed(const VarDecl *D) const {
- return AlwaysBypassed || Bypasses.find(D) != Bypasses.end();
- }
-
-private:
- bool BuildScopeInformation(const Decl *D, unsigned &ParentScope);
- bool BuildScopeInformation(const Stmt *S, unsigned &origParentScope);
- void Detect();
- void Detect(unsigned From, unsigned To);
-};
-}
-}
-
-#endif