40#define DEBUG_TYPE "arm64eccalllowering"
42STATISTIC(Arm64ECCallsLowered,
"Number of Arm64EC calls lowered");
51enum ThunkArgTranslation : uint8_t {
60 ThunkArgTranslation Translation;
63class AArch64Arm64ECCallLowering :
public ModulePass {
81 int cfguard_module_flag = 0;
88 Constant *DispatchFnGlobal =
nullptr;
111 ThunkArgInfo canonicalizeThunkType(
Type *
T,
Align Alignment,
bool Ret,
117void AArch64Arm64ECCallLowering::getThunkType(
121 Out << (
TT == Arm64ECThunkType::Entry ?
"$ientry_thunk$cdecl$"
122 :
"$iexit_thunk$cdecl$");
133 if (TT == Arm64ECThunkType::Exit)
137 bool HasSretPtr =
false;
138 getThunkRetType(FT, AttrList, Out, Arm64RetTy, X64RetTy, Arm64ArgTypes,
139 X64ArgTypes, ArgTranslations, HasSretPtr);
141 getThunkArgTypes(FT, AttrList, TT, Out, Arm64ArgTypes, X64ArgTypes,
142 ArgTranslations, HasSretPtr);
144 Arm64Ty = FunctionType::get(Arm64RetTy, Arm64ArgTypes,
false);
146 X64Ty = FunctionType::get(X64RetTy, X64ArgTypes,
false);
149void AArch64Arm64ECCallLowering::getThunkArgTypes(
156 if (FT->isVarArg()) {
179 for (
int i = HasSretPtr ? 1 : 0; i < 4; i++) {
182 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
188 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
191 if (TT != Arm64ECThunkType::Entry) {
195 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
204 if (
I == FT->getNumParams()) {
209 for (
unsigned E = FT->getNumParams();
I != E; ++
I) {
213 uint64_t ArgSizeBytes = AttrList.getParamArm64ECArgSizeBytes(
I);
219 auto [Arm64Ty, X64Ty, ArgTranslation] =
220 canonicalizeThunkType(FT->getParamType(
I), ParamAlign,
221 false, ArgSizeBytes, Out);
224 ArgTranslations.
push_back(ArgTranslation);
228void AArch64Arm64ECCallLowering::getThunkRetType(
233 Type *
T = FT->getReturnType();
237 uint64_t ArgSizeBytes = AttrList.getRetArm64ECArgSizeBytes();
239 int64_t ArgSizeBytes = 0;
242 if (FT->getNumParams()) {
246 if (FT->getNumParams() > 1) {
250 SRetAttr1 = AttrList.
getParamAttr(1, Attribute::StructRet);
251 InRegAttr1 = AttrList.
getParamAttr(1, Attribute::InReg);
274 canonicalizeThunkType(SRetType, SRetAlign,
true, ArgSizeBytes,
278 Arm64ArgTypes.
push_back(FT->getParamType(0));
279 X64ArgTypes.
push_back(FT->getParamType(0));
280 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
293 canonicalizeThunkType(
T,
Align(),
true, ArgSizeBytes, Out);
294 Arm64RetTy =
info.Arm64Ty;
295 X64RetTy =
info.X64Ty;
305ThunkArgInfo AArch64Arm64ECCallLowering::canonicalizeThunkType(
309 auto direct = [](
Type *
T) {
310 return ThunkArgInfo{
T,
T, ThunkArgTranslation::Direct};
313 auto bitcast = [
this](
Type *Arm64Ty,
uint64_t SizeInBytes) {
314 return ThunkArgInfo{Arm64Ty,
316 ThunkArgTranslation::Bitcast};
319 auto pointerIndirection = [
this](
Type *Arm64Ty) {
320 return ThunkArgInfo{Arm64Ty, PtrTy,
321 ThunkArgTranslation::PointerIndirection};
324 if (
T->isFloatTy()) {
329 if (
T->isDoubleTy()) {
334 if (
T->isFloatingPointTy()) {
336 "Only 32 and 64 bit floating points are supported for ARM64EC thunks");
339 auto &
DL =
M->getDataLayout();
341 if (
auto *StructTy = dyn_cast<StructType>(
T))
342 if (StructTy->getNumElements() == 1)
343 T = StructTy->getElementType(0);
345 if (
T->isArrayTy()) {
346 Type *ElementTy =
T->getArrayElementType();
347 uint64_t ElementCnt =
T->getArrayNumElements();
348 uint64_t ElementSizePerBytes =
DL.getTypeSizeInBits(ElementTy) / 8;
349 uint64_t TotalSizeBytes = ElementCnt * ElementSizePerBytes;
351 Out << (ElementTy->
isFloatTy() ?
"F" :
"D") << TotalSizeBytes;
352 if (Alignment.
value() >= 16 && !
Ret)
353 Out <<
"a" << Alignment.
value();
354 if (TotalSizeBytes <= 8) {
357 return bitcast(
T, TotalSizeBytes);
360 return pointerIndirection(
T);
362 }
else if (
T->isFloatingPointTy()) {
368 if ((
T->isIntegerTy() ||
T->isPointerTy()) &&
DL.getTypeSizeInBits(
T) <= 64) {
370 return direct(I64Ty);
379 if (Alignment.
value() >= 16 && !Ret)
380 Out <<
"a" << Alignment.
value();
387 return pointerIndirection(
T);
399 getThunkType(FT, Attrs, Arm64ECThunkType::Exit, ExitThunkStream, Arm64Ty,
400 X64Ty, ArgTranslations);
401 if (
Function *
F =
M->getFunction(ExitThunkName))
407 F->setSection(
".wowthk$aa");
408 F->setComdat(
M->getOrInsertComdat(ExitThunkName));
410 F->addFnAttr(
"frame-pointer",
"all");
414 if (FT->getNumParams()) {
415 auto SRet =
Attrs.getParamAttr(0, Attribute::StructRet);
416 auto InReg =
Attrs.getParamAttr(0, Attribute::InReg);
417 if (SRet.isValid() && !InReg.isValid())
418 F->addParamAttr(1, SRet);
425 M->getOrInsertGlobal(
"__os_arm64x_dispatch_call_no_redirect", PtrTy);
427 auto &
DL =
M->getDataLayout();
431 auto X64TyOffset = 1;
432 Args.push_back(
F->arg_begin());
435 if (
RetTy != X64Ty->getReturnType()) {
439 if (
DL.getTypeStoreSize(
RetTy) > 8) {
447 make_range(X64Ty->param_begin() + X64TyOffset, X64Ty->param_end()),
463 if (ArgTranslation != ThunkArgTranslation::Direct) {
464 Value *Mem = IRB.CreateAlloca(Arg.getType());
465 IRB.CreateStore(&Arg, Mem);
466 if (ArgTranslation == ThunkArgTranslation::Bitcast) {
468 Args.push_back(IRB.CreateLoad(IntTy, IRB.CreateBitCast(Mem, PtrTy)));
470 assert(ArgTranslation == ThunkArgTranslation::PointerIndirection);
474 Args.push_back(&Arg);
480 Callee = IRB.CreateBitCast(Callee, PtrTy);
485 if (
RetTy != X64Ty->getReturnType()) {
488 if (
DL.getTypeStoreSize(
RetTy) > 8) {
489 RetVal = IRB.CreateLoad(
RetTy, Args[1]);
492 IRB.CreateStore(Call, IRB.CreateBitCast(CastAlloca, PtrTy));
493 RetVal = IRB.CreateLoad(
RetTy, CastAlloca);
497 if (
RetTy->isVoidTy())
500 IRB.CreateRet(RetVal);
511 getThunkType(
F->getFunctionType(),
F->getAttributes(),
512 Arm64ECThunkType::Entry, EntryThunkStream, Arm64Ty, X64Ty,
514 if (
Function *
F =
M->getFunction(EntryThunkName))
520 Thunk->setSection(
".wowthk$aa");
521 Thunk->setComdat(
M->getOrInsertComdat(EntryThunkName));
523 Thunk->addFnAttr(
"frame-pointer",
"all");
529 Type *X64RetType = X64Ty->getReturnType();
531 bool TransformDirectToSRet = X64RetType->
isVoidTy() && !
RetTy->isVoidTy();
532 unsigned ThunkArgOffset = TransformDirectToSRet ? 2 : 1;
533 unsigned PassthroughArgSize =
534 (
F->isVarArg() ? 5 :
Thunk->arg_size()) - ThunkArgOffset;
535 assert(ArgTranslations.
size() == (
F->isVarArg() ? 5 : PassthroughArgSize));
539 for (
unsigned i = 0; i != PassthroughArgSize; ++i) {
540 Value *Arg =
Thunk->getArg(i + ThunkArgOffset);
541 Type *ArgTy = Arm64Ty->getParamType(i);
542 ThunkArgTranslation ArgTranslation = ArgTranslations[i];
543 if (ArgTranslation != ThunkArgTranslation::Direct) {
545 if (ArgTranslation == ThunkArgTranslation::Bitcast) {
546 Value *CastAlloca = IRB.CreateAlloca(ArgTy);
547 IRB.CreateStore(Arg, IRB.CreateBitCast(CastAlloca, PtrTy));
548 Arg = IRB.CreateLoad(ArgTy, CastAlloca);
550 assert(ArgTranslation == ThunkArgTranslation::PointerIndirection);
551 Arg = IRB.CreateLoad(ArgTy, IRB.CreateBitCast(Arg, PtrTy));
565 Thunk->addParamAttr(5, Attribute::InReg);
567 Arg = IRB.CreatePtrAdd(Arg, IRB.getInt64(0x20));
571 Args.push_back(IRB.getInt64(0));
576 Callee = IRB.CreateBitCast(Callee, PtrTy);
579 auto SRetAttr =
F->getAttributes().getParamAttr(0, Attribute::StructRet);
580 auto InRegAttr =
F->getAttributes().getParamAttr(0, Attribute::InReg);
581 if (SRetAttr.isValid() && !InRegAttr.isValid()) {
582 Thunk->addParamAttr(1, SRetAttr);
583 Call->addParamAttr(0, SRetAttr);
587 if (TransformDirectToSRet) {
588 IRB.CreateStore(RetVal, IRB.CreateBitCast(
Thunk->getArg(1), PtrTy));
589 }
else if (X64RetType !=
RetTy) {
590 Value *CastAlloca = IRB.CreateAlloca(X64RetType);
591 IRB.CreateStore(Call, IRB.CreateBitCast(CastAlloca, PtrTy));
592 RetVal = IRB.CreateLoad(X64RetType, CastAlloca);
602 IRB.CreateRet(RetVal);
615 getThunkType(
F->getFunctionType(),
F->getAttributes(),
616 Arm64ECThunkType::GuestExit, NullThunkName, Arm64Ty, X64Ty,
619 assert(MangledName &&
"Can't guest exit to function that's already native");
620 std::string ThunkName = *MangledName;
621 if (ThunkName[0] ==
'?' && ThunkName.find(
"@") != std::string::npos) {
622 ThunkName.insert(ThunkName.find(
"@"),
"$exit_thunk");
624 ThunkName.append(
"$exit_thunk");
628 GuestExit->setComdat(
M->getOrInsertComdat(ThunkName));
631 "arm64ec_unmangled_name",
635 "arm64ec_ecmangled_name",
638 F->setMetadata(
"arm64ec_hasguestexit",
MDNode::get(
M->getContext(), {}));
644 if (cfguard_module_flag == 2 && !
F->hasFnAttribute(
"guard_nocf"))
645 GuardFn = GuardFnCFGlobal;
647 GuardFn = GuardFnGlobal;
648 LoadInst *GuardCheckLoad =
B.CreateLoad(GuardFnPtrType, GuardFn);
652 Function *
Thunk = buildExitThunk(
F->getFunctionType(),
F->getAttributes());
654 GuardFnType, GuardCheckLoad,
655 {
B.CreateBitCast(
F,
B.getPtrTy()),
B.CreateBitCast(Thunk,
B.getPtrTy())});
660 Value *GuardRetVal =
B.CreateBitCast(GuardCheck, PtrTy);
663 Args.push_back(&Arg);
667 if (
Call->getType()->isVoidTy())
672 auto SRetAttr =
F->getAttributes().getParamAttr(0, Attribute::StructRet);
673 auto InRegAttr =
F->getAttributes().getParamAttr(0, Attribute::InReg);
674 if (SRetAttr.isValid() && !InRegAttr.isValid()) {
676 Call->addParamAttr(0, SRetAttr);
683AArch64Arm64ECCallLowering::buildPatchableThunk(
GlobalAlias *UnmangledAlias,
689 getThunkType(
F->getFunctionType(),
F->getAttributes(),
690 Arm64ECThunkType::GuestExit, NullThunkName, Arm64Ty, X64Ty,
692 std::string ThunkName(MangledAlias->
getName());
693 if (ThunkName[0] ==
'?' && ThunkName.find(
"@") != std::string::npos) {
694 ThunkName.insert(ThunkName.find(
"@"),
"$hybpatch_thunk");
696 ThunkName.append(
"$hybpatch_thunk");
701 GuestExit->setComdat(
M->getOrInsertComdat(ThunkName));
707 LoadInst *DispatchLoad =
B.CreateLoad(DispatchFnPtrType, DispatchFnGlobal);
711 buildExitThunk(
F->getFunctionType(),
F->getAttributes());
713 B.CreateCall(DispatchFnType, DispatchLoad,
714 {UnmangledAlias, ExitThunk, UnmangledAlias->
getAliasee()});
719 Value *DispatchRetVal =
B.CreateBitCast(Dispatch, PtrTy);
722 Args.push_back(&Arg);
723 CallInst *
Call =
B.CreateCall(Arm64Ty, DispatchRetVal, Args);
726 if (
Call->getType()->isVoidTy())
731 auto SRetAttr =
F->getAttributes().getParamAttr(0, Attribute::StructRet);
732 auto InRegAttr =
F->getAttributes().getParamAttr(0, Attribute::InReg);
733 if (SRetAttr.isValid() && !InRegAttr.isValid()) {
735 Call->addParamAttr(0, SRetAttr);
743void AArch64Arm64ECCallLowering::lowerCall(
CallBase *CB) {
745 "Only applicable for Windows targets");
758 if (cfguard_module_flag == 2 && !CB->
hasFnAttr(
"guard_nocf"))
759 GuardFn = GuardFnCFGlobal;
761 GuardFn = GuardFnGlobal;
762 LoadInst *GuardCheckLoad =
B.CreateLoad(GuardFnPtrType, GuardFn);
768 B.CreateCall(GuardFnType, GuardCheckLoad,
769 {
B.CreateBitCast(CalledOperand,
B.getPtrTy()),
770 B.CreateBitCast(Thunk,
B.getPtrTy())},
776 Value *GuardRetVal =
B.CreateBitCast(GuardCheck, CalledOperand->
getType());
780bool AArch64Arm64ECCallLowering::runOnModule(
Module &
Mod) {
788 mdconst::extract_or_null<ConstantInt>(
M->getModuleFlag(
"cfguard")))
789 cfguard_module_flag = MD->getZExtValue();
791 PtrTy = PointerType::getUnqual(
M->getContext());
795 GuardFnType = FunctionType::get(PtrTy, {PtrTy, PtrTy},
false);
796 GuardFnPtrType = PointerType::get(GuardFnType, 0);
797 DispatchFnType = FunctionType::get(PtrTy, {PtrTy, PtrTy, PtrTy},
false);
798 DispatchFnPtrType = PointerType::get(DispatchFnType, 0);
800 M->getOrInsertGlobal(
"__os_arm64x_check_icall_cfg", GuardFnPtrType);
802 M->getOrInsertGlobal(
"__os_arm64x_check_icall", GuardFnPtrType);
804 M->getOrInsertGlobal(
"__os_arm64x_dispatch_call", DispatchFnPtrType);
810 if (!
F.hasFnAttribute(Attribute::HybridPatchable) ||
F.isDeclaration() ||
811 F.hasLocalLinkage() ||
F.getName().ends_with(
"$hp_target"))
816 if (std::optional<std::string> MangledName =
818 std::string OrigName(
F.getName());
819 F.setName(MangledName.value() +
"$hp_target");
829 F.replaceAllUsesWith(
A);
830 F.setMetadata(
"arm64ec_exp_name",
833 "EXP+" + MangledName.value())));
836 if (
F.hasDLLExportStorageClass()) {
842 MangledName.value(), &
F);
849 if (!
F.isDeclaration() &&
852 processFunction(
F, DirectCalledFns, FnsMap);
861 if (!
F.isDeclaration() && (!
F.hasLocalLinkage() ||
F.hasAddressTaken()) &&
865 F.setComdat(
Mod.getOrInsertComdat(
F.getName()));
867 {&
F, buildEntryThunk(&
F), Arm64ECThunkType::Entry});
871 auto GA = dyn_cast<GlobalAlias>(O);
872 auto F = dyn_cast<Function>(GA ? GA->getAliasee() : O);
874 {
O, buildExitThunk(
F->getFunctionType(),
F->getAttributes()),
875 Arm64ECThunkType::Exit});
876 if (!GA && !
F->hasDLLImportStorageClass())
878 {buildGuestExitThunk(
F),
F, Arm64ECThunkType::GuestExit});
885 if (!ThunkMapping.
empty()) {
887 for (ThunkInfo &Thunk : ThunkMapping) {
891 ConstantInt::get(
M->getContext(),
APInt(32, uint8_t(
Thunk.Kind)))}));
895 ThunkMappingArrayElems.
size()),
896 ThunkMappingArrayElems);
899 "llvm.arm64ec.symbolmap");
905bool AArch64Arm64ECCallLowering::processFunction(
917 if (!
F.hasLocalLinkage() ||
F.hasAddressTaken()) {
918 if (std::optional<std::string> MangledName =
920 F.setMetadata(
"arm64ec_unmangled_name",
923 if (
F.hasComdat() &&
F.getComdat()->getName() ==
F.getName()) {
924 Comdat *MangledComdat =
M->getOrInsertComdat(MangledName.value());
928 User->setComdat(MangledComdat);
930 F.setName(MangledName.value());
940 auto *CB = dyn_cast<CallBase>(&
I);
952 F->isIntrinsic() || !
F->isDeclaration())
962 if (
I != FnsMap.
end()) {
964 DirectCalledFns.
insert(
I->first);
970 ++Arm64ECCallsLowered;
974 if (IndirectCalls.
empty())
983char AArch64Arm64ECCallLowering::ID = 0;
985 "AArch64Arm64ECCallLowering",
false,
false)
988 return new AArch64Arm64ECCallLowering;
static cl::opt< bool > LowerDirectToIndirect("arm64ec-lower-direct-to-indirect", cl::Hidden, cl::init(true))
static cl::opt< bool > GenerateThunks("arm64ec-generate-thunks", cl::Hidden, cl::init(true))
OperandBundleDefT< Value * > OperandBundleDef
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Module.h This file contains the declarations for the Module class.
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallString class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
Class for arbitrary precision integers.
This class represents an incoming formal argument to a Function.
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
Attribute getParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Return the attribute object that exists at the arg index.
MaybeAlign getParamAlignment(unsigned ArgNo) const
Return the alignment for the specified function parameter.
bool isValid() const
Return true if the attribute is any kind of attribute.
Type * getValueAsType() const
Return the attribute's value as a Type.
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
bool isInlineAsm() const
Check if this call is an inline asm statement.
void setCallingConv(CallingConv::ID CC)
std::optional< OperandBundleUse > getOperandBundle(StringRef Name) const
Return an operand bundle by name, if present.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
CallingConv::ID getCallingConv() const
Value * getCalledOperand() const
FunctionType * getFunctionType() const
void setCalledOperand(Value *V)
AttributeList getAttributes() const
Return the parameter attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
static Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
This is an important base class in LLVM.
iterator find(const_arg_type_t< KeyT > Val)
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
void setAliasee(Constant *Aliasee)
These methods retrieve and set alias target.
const Constant * getAliasee() const
static GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
@ DLLExportStorageClass
Function to be accessible from DLL.
@ WeakODRLinkage
Same, but only replaced by something equivalent.
@ ExternalLinkage
Externally visible function.
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
An instruction for reading from memory.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static MDString * get(LLVMContext &Context, StringRef Str)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
const std::string & getTargetTriple() const
Get the target triple which is a string describing the target host.
A container for an operand bundle being viewed as a set of values rather than a set of uses.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
A vector that has set insertion semantics.
bool insert(const value_type &X)
Insert a new element into the SetVector.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Triple - Helper class for working with autoconf configuration names.
bool isOSWindows() const
Tests whether the OS is Windows.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static Type * getVoidTy(LLVMContext &C)
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
static IntegerType * getInt64Ty(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
StringRef getName() const
Return a constant reference to the value's name.
A raw_ostream that discards all output.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an SmallVector or SmallString.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ ARM64EC_Thunk_Native
Calling convention used in the ARM64EC ABI to implement calls between ARM64 code and thunks.
@ CFGuard_Check
Special calling convention on Windows for calling the Control Guard Check ICall funtion.
@ ARM64EC_Thunk_X64
Calling convention used in the ARM64EC ABI to implement calls between x64 code and thunks.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
std::optional< std::string > getArm64ECMangledFunctionName(StringRef Name)
detail::zippy< detail::zip_first, T, U, Args... > zip_equal(T &&t, U &&u, Args &&...args)
zip iterator that assumes that all iteratees have the same length.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
void initializeAArch64Arm64ECCallLoweringPass(PassRegistry &)
ModulePass * createAArch64Arm64ECCallLoweringPass()
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
SmallVector< ValueTypeFromRangeType< R >, Size > to_vector(R &&Range)
Given a range of type R, iterate the entire range and return a SmallVector with elements of the vecto...
This struct is a compact representation of a valid (non-zero power of two) alignment.
uint64_t value() const
This is a hole in the type system and should not be abused.
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.