40#define DEBUG_TYPE "arm64eccalllowering"
42STATISTIC(Arm64ECCallsLowered,
"Number of Arm64EC calls lowered");
51enum ThunkArgTranslation :
uint8_t {
60 ThunkArgTranslation Translation;
63class AArch64Arm64ECCallLowering :
public ModulePass {
66 AArch64Arm64ECCallLowering() : ModulePass(ID) {}
68 Function *buildExitThunk(FunctionType *FnTy, AttributeList Attrs);
70 void lowerCall(CallBase *CB);
71 Function *buildGuestExitThunk(Function *
F);
72 Function *buildPatchableThunk(GlobalAlias *UnmangledAlias,
73 GlobalAlias *MangledAlias);
75 DenseMap<GlobalAlias *, GlobalAlias *> &FnsMap);
76 bool runOnModule(
Module &M)
override;
80 FunctionType *GuardFnType =
nullptr;
81 FunctionType *DispatchFnType =
nullptr;
84 Constant *DispatchFnGlobal =
nullptr;
91 void getThunkType(FunctionType *FT, AttributeList AttrList,
93 FunctionType *&Arm64Ty, FunctionType *&X64Ty,
95 void getThunkRetType(FunctionType *FT, AttributeList AttrList,
96 raw_ostream &Out,
Type *&Arm64RetTy,
Type *&X64RetTy,
97 SmallVectorImpl<Type *> &Arm64ArgTypes,
98 SmallVectorImpl<Type *> &X64ArgTypes,
101 void getThunkArgTypes(FunctionType *FT, AttributeList AttrList,
103 SmallVectorImpl<Type *> &Arm64ArgTypes,
104 SmallVectorImpl<Type *> &X64ArgTypes,
105 SmallVectorImpl<ThunkArgTranslation> &ArgTranslations,
107 ThunkArgInfo canonicalizeThunkType(
Type *
T, Align Alignment,
bool Ret,
108 uint64_t ArgSizeBytes, raw_ostream &Out);
113void AArch64Arm64ECCallLowering::getThunkType(
117 Out << (
TT == Arm64ECThunkType::Entry ?
"$ientry_thunk$cdecl$"
118 :
"$iexit_thunk$cdecl$");
129 if (TT == Arm64ECThunkType::Exit)
133 bool HasSretPtr =
false;
134 getThunkRetType(FT, AttrList, Out, Arm64RetTy, X64RetTy, Arm64ArgTypes,
135 X64ArgTypes, ArgTranslations, HasSretPtr);
137 getThunkArgTypes(FT, AttrList, TT, Out, Arm64ArgTypes, X64ArgTypes,
138 ArgTranslations, HasSretPtr);
140 Arm64Ty = FunctionType::get(Arm64RetTy, Arm64ArgTypes,
false);
142 X64Ty = FunctionType::get(X64RetTy, X64ArgTypes,
false);
145void AArch64Arm64ECCallLowering::getThunkArgTypes(
147 raw_ostream &Out, SmallVectorImpl<Type *> &Arm64ArgTypes,
148 SmallVectorImpl<Type *> &X64ArgTypes,
149 SmallVectorImpl<ThunkArgTranslation> &ArgTranslations,
bool HasSretPtr) {
152 if (FT->isVarArg()) {
175 for (
int i = HasSretPtr ? 1 : 0; i < 4; i++) {
178 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
184 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
187 if (TT != Arm64ECThunkType::Entry) {
191 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
200 if (
I == FT->getNumParams()) {
205 for (
unsigned E = FT->getNumParams();
I !=
E; ++
I) {
209 uint64_t ArgSizeBytes = AttrList.getParamArm64ECArgSizeBytes(
I);
210 Align ParamAlign = AttrList.getParamAlignment(
I).valueOrOne();
212 uint64_t ArgSizeBytes = 0;
215 auto [Arm64Ty, X64Ty, ArgTranslation] =
216 canonicalizeThunkType(FT->getParamType(
I), ParamAlign,
217 false, ArgSizeBytes, Out);
220 ArgTranslations.
push_back(ArgTranslation);
224void AArch64Arm64ECCallLowering::getThunkRetType(
225 FunctionType *FT, AttributeList AttrList, raw_ostream &Out,
226 Type *&Arm64RetTy,
Type *&X64RetTy, SmallVectorImpl<Type *> &Arm64ArgTypes,
227 SmallVectorImpl<Type *> &X64ArgTypes,
229 Type *
T = FT->getReturnType();
233 uint64_t ArgSizeBytes = AttrList.getRetArm64ECArgSizeBytes();
235 int64_t ArgSizeBytes = 0;
238 if (FT->getNumParams()) {
239 Attribute SRetAttr0 = AttrList.getParamAttr(0, Attribute::StructRet);
240 Attribute InRegAttr0 = AttrList.getParamAttr(0, Attribute::InReg);
242 if (FT->getNumParams() > 1) {
246 SRetAttr1 = AttrList.getParamAttr(1, Attribute::StructRet);
247 InRegAttr1 = AttrList.getParamAttr(1, Attribute::InReg);
269 Align SRetAlign = AttrList.getParamAlignment(0).valueOrOne();
270 canonicalizeThunkType(SRetType, SRetAlign,
true, ArgSizeBytes,
274 Arm64ArgTypes.
push_back(FT->getParamType(0));
275 X64ArgTypes.
push_back(FT->getParamType(0));
276 ArgTranslations.
push_back(ThunkArgTranslation::Direct);
289 canonicalizeThunkType(
T,
Align(),
true, ArgSizeBytes, Out);
290 Arm64RetTy =
info.Arm64Ty;
291 X64RetTy =
info.X64Ty;
301ThunkArgInfo AArch64Arm64ECCallLowering::canonicalizeThunkType(
302 Type *
T, Align Alignment,
bool Ret, uint64_t ArgSizeBytes,
305 auto direct = [](
Type *
T) {
306 return ThunkArgInfo{
T,
T, ThunkArgTranslation::Direct};
309 auto bitcast = [
this](
Type *Arm64Ty, uint64_t SizeInBytes) {
310 return ThunkArgInfo{Arm64Ty,
312 ThunkArgTranslation::Bitcast};
315 auto pointerIndirection = [
this](
Type *Arm64Ty) {
316 return ThunkArgInfo{Arm64Ty, PtrTy,
317 ThunkArgTranslation::PointerIndirection};
326 if (
T->isFloatTy()) {
331 if (
T->isDoubleTy()) {
336 if (
T->isFloatingPointTy()) {
338 "for ARM64EC thunks");
344 if (StructTy->getNumElements() == 1)
345 T = StructTy->getElementType(0);
347 if (
T->isArrayTy()) {
348 Type *ElementTy =
T->getArrayElementType();
349 uint64_t ElementCnt =
T->getArrayNumElements();
350 uint64_t ElementSizePerBytes =
DL.getTypeSizeInBits(ElementTy) / 8;
351 uint64_t TotalSizeBytes = ElementCnt * ElementSizePerBytes;
361 Out << TotalSizeBytes;
362 if (Alignment.
value() >= 16 && !Ret)
363 Out <<
"a" << Alignment.
value();
364 if (TotalSizeBytes <= 8) {
367 return bitcast(
T, TotalSizeBytes);
370 return pointerIndirection(
T);
372 }
else if (
T->isFloatingPointTy()) {
374 "Only 16, 32, and 64 bit floating points are supported "
375 "for ARM64EC thunks");
379 if ((
T->isIntegerTy() ||
T->isPointerTy()) &&
DL.getTypeSizeInBits(
T) <= 64) {
381 return direct(I64Ty);
384 unsigned TypeSize = ArgSizeBytes;
386 TypeSize =
DL.getTypeSizeInBits(
T) / 8;
390 if (Alignment.
value() >= 16 && !Ret)
391 Out <<
"a" << Alignment.
value();
393 if (TypeSize == 1 || TypeSize == 2 || TypeSize == 4 || TypeSize == 8) {
395 return bitcast(
T, TypeSize);
398 return pointerIndirection(
T);
404Function *AArch64Arm64ECCallLowering::buildExitThunk(FunctionType *FT,
405 AttributeList Attrs) {
406 SmallString<256> ExitThunkName;
407 llvm::raw_svector_ostream ExitThunkStream(ExitThunkName);
408 FunctionType *Arm64Ty, *X64Ty;
410 getThunkType(FT, Attrs, Arm64ECThunkType::Exit, ExitThunkStream, Arm64Ty,
411 X64Ty, ArgTranslations);
417 F->setCallingConv(CallingConv::ARM64EC_Thunk_Native);
418 F->setSection(
".wowthk$aa");
421 F->addFnAttr(
"frame-pointer",
"all");
425 if (FT->getNumParams()) {
426 auto SRet =
Attrs.getParamAttr(0, Attribute::StructRet);
427 auto InReg =
Attrs.getParamAttr(0, Attribute::InReg);
428 if (SRet.isValid() && !InReg.isValid())
429 F->addParamAttr(1, SRet);
442 auto X64TyOffset = 1;
443 Args.push_back(
F->arg_begin());
445 Type *RetTy = Arm64Ty->getReturnType();
446 if (RetTy != X64Ty->getReturnType()) {
450 if (
DL.getTypeStoreSize(RetTy) > 8) {
451 Args.push_back(IRB.CreateAlloca(RetTy));
458 make_range(X64Ty->param_begin() + X64TyOffset, X64Ty->param_end()),
474 if (ArgTranslation != ThunkArgTranslation::Direct) {
475 Value *Mem = IRB.CreateAlloca(Arg.getType());
476 IRB.CreateStore(&Arg, Mem);
477 if (ArgTranslation == ThunkArgTranslation::Bitcast) {
478 Type *IntTy = IRB.getIntNTy(
DL.getTypeStoreSizeInBits(Arg.getType()));
479 Args.push_back(IRB.CreateLoad(IntTy, Mem));
481 assert(ArgTranslation == ThunkArgTranslation::PointerIndirection);
485 Args.push_back(&Arg);
491 CallInst *
Call = IRB.CreateCall(X64Ty, Callee, Args);
495 if (RetTy != X64Ty->getReturnType()) {
498 if (
DL.getTypeStoreSize(RetTy) > 8) {
499 RetVal = IRB.CreateLoad(RetTy, Args[1]);
501 Value *CastAlloca = IRB.CreateAlloca(RetTy);
502 IRB.CreateStore(
Call, CastAlloca);
503 RetVal = IRB.CreateLoad(RetTy, CastAlloca);
510 IRB.CreateRet(RetVal);
516Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *
F) {
517 SmallString<256> EntryThunkName;
518 llvm::raw_svector_ostream EntryThunkStream(EntryThunkName);
519 FunctionType *Arm64Ty, *X64Ty;
521 getThunkType(
F->getFunctionType(),
F->getAttributes(),
522 Arm64ECThunkType::Entry, EntryThunkStream, Arm64Ty, X64Ty,
529 Thunk->setCallingConv(CallingConv::ARM64EC_Thunk_X64);
530 Thunk->setSection(
".wowthk$aa");
533 Thunk->addFnAttr(
"frame-pointer",
"all");
538 Type *RetTy = Arm64Ty->getReturnType();
539 Type *X64RetType = X64Ty->getReturnType();
542 unsigned ThunkArgOffset = TransformDirectToSRet ? 2 : 1;
543 unsigned PassthroughArgSize =
544 (
F->isVarArg() ? 5 :
Thunk->arg_size()) - ThunkArgOffset;
545 assert(ArgTranslations.
size() == (
F->isVarArg() ? 5 : PassthroughArgSize));
549 for (
unsigned i = 0; i != PassthroughArgSize; ++i) {
550 Value *Arg =
Thunk->getArg(i + ThunkArgOffset);
551 Type *ArgTy = Arm64Ty->getParamType(i);
552 ThunkArgTranslation ArgTranslation = ArgTranslations[i];
553 if (ArgTranslation != ThunkArgTranslation::Direct) {
555 if (ArgTranslation == ThunkArgTranslation::Bitcast) {
556 Value *CastAlloca = IRB.CreateAlloca(ArgTy);
557 IRB.CreateStore(Arg, CastAlloca);
558 Arg = IRB.CreateLoad(ArgTy, CastAlloca);
560 assert(ArgTranslation == ThunkArgTranslation::PointerIndirection);
561 Arg = IRB.CreateLoad(ArgTy, Arg);
575 Thunk->addParamAttr(5, Attribute::InReg);
577 Arg = IRB.CreatePtrAdd(Arg, IRB.getInt64(0x20));
581 Args.push_back(IRB.getInt64(0));
586 CallInst *
Call = IRB.CreateCall(Arm64Ty, Callee, Args);
588 auto SRetAttr =
F->
getAttributes().getParamAttr(0, Attribute::StructRet);
589 auto InRegAttr =
F->getAttributes().getParamAttr(0, Attribute::InReg);
590 if (SRetAttr.isValid() && !InRegAttr.isValid()) {
591 Thunk->addParamAttr(1, SRetAttr);
596 if (TransformDirectToSRet) {
601 1, Attribute::getWithStructRetType(M->
getContext(), RetTy));
602 IRB.CreateStore(RetVal,
Thunk->getArg(1));
603 }
else if (X64RetType != RetTy) {
604 Value *CastAlloca = IRB.CreateAlloca(X64RetType);
605 IRB.CreateStore(
Call, CastAlloca);
606 RetVal = IRB.CreateLoad(X64RetType, CastAlloca);
616 IRB.CreateRet(RetVal);
633Function *AArch64Arm64ECCallLowering::buildGuestExitThunk(Function *
F) {
634 llvm::raw_null_ostream NullThunkName;
635 FunctionType *Arm64Ty, *X64Ty;
637 getThunkType(
F->getFunctionType(),
F->getAttributes(),
638 Arm64ECThunkType::GuestExit, NullThunkName, Arm64Ty, X64Ty,
641 assert(MangledName &&
"Can't guest exit to function that's already native");
642 std::string ThunkName = *MangledName;
643 if (ThunkName[0] ==
'?' && ThunkName.find(
"@") != std::string::npos) {
644 ThunkName.insert(ThunkName.find(
"@"),
"$exit_thunk");
646 ThunkName.append(
"$exit_thunk");
653 "arm64ec_unmangled_name",
657 "arm64ec_ecmangled_name",
667 LoadInst *GuardCheckLoad =
B.CreateLoad(PtrTy, GuardFnGlobal);
668 Function *
Thunk = buildExitThunk(
F->getFunctionType(),
F->getAttributes());
669 CallInst *GuardCheck =
B.CreateCall(
670 GuardFnType, GuardCheckLoad, {
F,
Thunk});
671 Value *GuardCheckDest =
B.CreateExtractValue(GuardCheck, 0);
672 Value *GuardFinalDest =
B.CreateExtractValue(GuardCheck, 1);
679 CallInst *
Call =
B.CreateCall(Arm64Ty, GuardCheckDest, Args, OB);
687 auto SRetAttr =
F->getAttributes().getParamAttr(0, Attribute::StructRet);
688 auto InRegAttr =
F->getAttributes().getParamAttr(0, Attribute::InReg);
689 if (SRetAttr.isValid() && !InRegAttr.isValid()) {
698AArch64Arm64ECCallLowering::buildPatchableThunk(GlobalAlias *UnmangledAlias,
699 GlobalAlias *MangledAlias) {
700 llvm::raw_null_ostream NullThunkName;
701 FunctionType *Arm64Ty, *X64Ty;
704 getThunkType(
F->getFunctionType(),
F->getAttributes(),
705 Arm64ECThunkType::GuestExit, NullThunkName, Arm64Ty, X64Ty,
707 std::string ThunkName(MangledAlias->
getName());
708 if (ThunkName[0] ==
'?' && ThunkName.find(
"@") != std::string::npos) {
709 ThunkName.insert(ThunkName.find(
"@"),
"$hybpatch_thunk");
711 ThunkName.append(
"$hybpatch_thunk");
722 LoadInst *DispatchLoad =
B.CreateLoad(PtrTy, DispatchFnGlobal);
726 buildExitThunk(
F->getFunctionType(),
F->getAttributes());
728 B.CreateCall(DispatchFnType, DispatchLoad,
729 {UnmangledAlias, ExitThunk, UnmangledAlias->
getAliasee()});
732 Dispatch->setCallingConv(CallingConv::CFGuard_Check);
743 auto SRetAttr =
F->getAttributes().getParamAttr(0, Attribute::StructRet);
744 auto InRegAttr =
F->getAttributes().getParamAttr(0, Attribute::InReg);
745 if (SRetAttr.isValid() && !InRegAttr.isValid()) {
755void AArch64Arm64ECCallLowering::lowerCall(CallBase *CB) {
767 if ((CFGuardModuleFlag == ControlFlowGuardMode::Enabled) &&
769 GuardFn = GuardFnCFGlobal;
771 GuardFn = GuardFnGlobal;
772 LoadInst *GuardCheckLoad =
B.CreateLoad(PtrTy, GuardFn);
777 CallInst *GuardCheck =
778 B.CreateCall(GuardFnType, GuardCheckLoad, {CalledOperand,
Thunk},
780 Value *GuardCheckDest =
B.CreateExtractValue(GuardCheck, 0);
781 Value *GuardFinalDest =
B.CreateExtractValue(GuardCheck, 1);
792 NewCall->copyMetadata(*CB);
797bool AArch64Arm64ECCallLowering::runOnModule(
Module &
Mod) {
807 if (CFGuardModuleFlag == ControlFlowGuardMode::Enabled) {
809 Mod.getModuleFlag(
"cfguard-mechanism"))) {
810 auto MechanismOverride =
812 if (MechanismOverride != ControlFlowGuardMechanism::Automatic &&
813 MechanismOverride != ControlFlowGuardMechanism::Check)
814 Mod.getContext().diagnose(
815 DiagnosticInfoGeneric(
"only the Check Control Flow Guard mechanism "
816 "is supported for Arm64EC",
821 PtrTy = PointerType::getUnqual(M->
getContext());
826 FunctionType::get(
StructType::get(PtrTy, PtrTy), {PtrTy, PtrTy},
false);
827 DispatchFnType = FunctionType::get(PtrTy, {PtrTy, PtrTy, PtrTy},
false);
836 for (GlobalAlias &
A :
Mod.aliases()) {
840 if (std::optional<std::string> MangledName =
842 F->addMetadata(
"arm64ec_unmangled_name",
845 A.setName(MangledName.value());
849 DenseMap<GlobalAlias *, GlobalAlias *> FnsMap;
850 SetVector<GlobalAlias *> PatchableFns;
852 for (Function &
F :
Mod) {
853 if (
F.hasPersonalityFn()) {
854 GlobalValue *PersFn =
857 if (std::optional<std::string> MangledName =
859 PersFn->
setName(MangledName.value());
864 if (!
F.hasFnAttribute(Attribute::HybridPatchable) ||
865 F.isDeclarationForLinker() ||
F.hasLocalLinkage() ||
871 if (std::optional<std::string> MangledName =
873 std::string OrigName(
F.getName());
885 MangledName.value(), &
F);
886 F.replaceUsesWithIf(AM,
888 F.replaceAllUsesWith(
A);
889 F.setMetadata(
"arm64ec_exp_name",
892 "EXP+" + MangledName.value())));
896 if (
F.hasDLLExportStorageClass()) {
906 SetVector<GlobalValue *> DirectCalledFns;
907 for (Function &
F :
Mod)
908 if (!
F.isDeclarationForLinker() &&
909 F.getCallingConv() != CallingConv::ARM64EC_Thunk_Native &&
910 F.getCallingConv() != CallingConv::ARM64EC_Thunk_X64)
919 for (Function &
F :
Mod) {
920 if (!
F.isDeclarationForLinker() &&
921 (!
F.hasLocalLinkage() ||
F.hasAddressTaken()) &&
922 F.getCallingConv() != CallingConv::ARM64EC_Thunk_Native &&
923 F.getCallingConv() != CallingConv::ARM64EC_Thunk_X64) {
925 F.setComdat(
Mod.getOrInsertComdat(
F.getName()));
927 {&
F, buildEntryThunk(&
F), Arm64ECThunkType::Entry});
930 for (GlobalValue *O : DirectCalledFns) {
934 {
O, buildExitThunk(
F->getFunctionType(),
F->getAttributes()),
935 Arm64ECThunkType::Exit});
936 if (!GA && !
F->hasDLLImportStorageClass())
938 {buildGuestExitThunk(
F),
F, Arm64ECThunkType::GuestExit});
940 for (GlobalAlias *
A : PatchableFns) {
945 if (!ThunkMapping.
empty()) {
947 for (ThunkInfo &Thunk : ThunkMapping) {
954 ThunkMappingArrayElems.
size()),
955 ThunkMappingArrayElems);
956 new GlobalVariable(
Mod, ThunkMappingArray->
getType(),
false,
958 "llvm.arm64ec.symbolmap");
964bool AArch64Arm64ECCallLowering::processFunction(
965 Function &
F, SetVector<GlobalValue *> &DirectCalledFns,
966 DenseMap<GlobalAlias *, GlobalAlias *> &FnsMap) {
976 if (!
F.hasLocalLinkage() ||
F.hasAddressTaken()) {
977 if (std::optional<std::string> MangledName =
979 F.addMetadata(
"arm64ec_unmangled_name",
982 if (
F.hasComdat() &&
F.getComdat()->getName() ==
F.getName()) {
986 for (GlobalObject *User : ComdatUsers)
987 User->setComdat(MangledComdat);
989 F.setName(MangledName.value());
997 for (BasicBlock &BB :
F) {
998 for (Instruction &
I : BB) {
1000 if (!CB || CB->
getCallingConv() == CallingConv::ARM64EC_Thunk_X64 ||
1011 F->isIntrinsic() || !
F->isDeclarationForLinker())
1021 if (
I != FnsMap.
end()) {
1023 DirectCalledFns.
insert(
I->first);
1029 ++Arm64ECCallsLowered;
1033 if (IndirectCalls.
empty())
1036 for (CallBase *CB : IndirectCalls)
1042char AArch64Arm64ECCallLowering::ID = 0;
1044 "AArch64Arm64ECCallLowering",
false,
false)
1047 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))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Module.h This file contains the declarations for the Module class.
Machine Check Debug Module
static bool processFunction(Function &F, NVPTXTargetMachine &TM)
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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)
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM_ABI Type * getValueAsType() const
Return the attribute's value as a Type.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
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
static LLVM_ABI CallBase * addOperandBundle(CallBase *CB, uint32_t ID, OperandBundleDef OB, InsertPosition InsertPt=nullptr)
Create a clone of CB with operand bundle OB added.
Value * getCalledOperand() const
FunctionType * getFunctionType() const
void setCalledOperand(Value *V)
AttributeList getAttributes() const
Return the attributes for this call.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
void setTailCallKind(TailCallKind TCK)
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
iterator find(const_arg_type_t< KeyT > Val)
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
LLVM_ABI void setAliasee(Constant *Aliasee)
These methods retrieve and set alias target.
const Constant * getAliasee() const
static LLVM_ABI 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.
Type * getValueType() const
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
LLVMContext & getContext() const
Get the global data context.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
ControlFlowGuardMode getControlFlowGuardMode() const
Gets the Control Flow Guard mode.
Comdat * getOrInsertComdat(StringRef Name)
Return the Comdat in the module with the specified name.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
GlobalVariable * getOrInsertGlobal(StringRef Name, Type *Ty, function_ref< GlobalVariable *()> CreateGlobalCallback)
Look up the specified global in the module symbol table.
A container for an operand bundle being viewed as a set of values rather than a set of uses.
bool insert(const value_type &X)
Insert a new element into the SetVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
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.
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
bool isFunctionTy() const
True if this is an instance of FunctionType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
bool isVoidTy() const
Return true if this is 'void'.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
self_iterator getIterator()
This class implements an extremely fast bulk output stream that can only output to a stream.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ BasicBlock
Various leaf nodes.
@ OB
OB - OneByte - Set if this instruction has a one byte opcode.
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
@ User
could "use" a pointer
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
LLVM_ABI std::optional< std::string > getArm64ECMangledFunctionName(StringRef Name)
Returns the ARM64EC mangled function name unless the input is already mangled.
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
auto dyn_cast_or_null(const Y &Val)
ModulePass * createAArch64Arm64ECCallLoweringPass()
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
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...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
constexpr std::string_view HybridPatchableTargetSuffix
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
OperandBundleDefT< Value * > OperandBundleDef
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
ControlFlowGuardMechanism
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.