81#include <system_error>
86using namespace lowertypetests;
88#define DEBUG_TYPE "lowertypetests"
90STATISTIC(ByteArraySizeBits,
"Byte array size in bits");
91STATISTIC(ByteArraySizeBytes,
"Byte array size in bytes");
92STATISTIC(NumByteArraysCreated,
"Number of byte arrays created");
93STATISTIC(NumTypeTestCallsLowered,
"Number of type test calls lowered");
94STATISTIC(NumTypeIdDisjointSets,
"Number of disjoint sets of type identifiers");
97 "lowertypetests-avoid-reuse",
98 cl::desc(
"Try to avoid reuse of byte array addresses using aliases"),
102 "lowertypetests-summary-action",
103 cl::desc(
"What to do with the summary when running this pass"),
105 clEnumValN(PassSummaryAction::Import,
"import",
106 "Import typeid resolutions from summary and globals"),
107 clEnumValN(PassSummaryAction::Export,
"export",
108 "Export typeid resolutions to summary and globals")),
112 "lowertypetests-read-summary",
113 cl::desc(
"Read summary from given YAML file before running pass"),
117 "lowertypetests-write-summary",
118 cl::desc(
"Write summary to given YAML file after running pass"),
123 cl::desc(
"Simply drop type test assume sequences"),
137 return Bits.count(BitOffset);
191 std::vector<uint64_t> &Fragment =
Fragments.back();
194 for (
auto ObjIndex :
F) {
196 if (OldFragmentIndex == 0) {
199 Fragment.push_back(ObjIndex);
206 std::vector<uint64_t> &OldFragment =
Fragments[OldFragmentIndex];
219 uint8_t &AllocMask) {
229 unsigned ReqSize = AllocByteOffset + BitSize;
231 if (
Bytes.size() < ReqSize)
232 Bytes.resize(ReqSize);
235 AllocMask = 1 << Bit;
237 Bytes[AllocByteOffset +
B] |= AllocMask;
241 if (
F->isDeclarationForLinker())
243 auto *CI = mdconst::extract_or_null<ConstantInt>(
244 F->getParent()->getModuleFlag(
"CFI Canonical Jump Tables"));
245 if (!CI || !CI->isZero())
247 return F->hasFnAttribute(
"cfi-canonical-jump-table");
252struct ByteArrayInfo {
253 std::set<uint64_t> Bits;
257 uint8_t *MaskPtr =
nullptr;
265class GlobalTypeMember final :
TrailingObjects<GlobalTypeMember, MDNode *> {
276 bool IsJumpTableCanonical;
282 size_t numTrailingObjects(OverloadToken<MDNode *>)
const {
return NTypes; }
286 bool IsJumpTableCanonical,
bool IsExported,
288 auto *GTM =
static_cast<GlobalTypeMember *
>(Alloc.
Allocate(
289 totalSizeToAlloc<MDNode *>(
Types.size()),
alignof(GlobalTypeMember)));
291 GTM->NTypes =
Types.size();
292 GTM->IsJumpTableCanonical = IsJumpTableCanonical;
293 GTM->IsExported = IsExported;
294 std::uninitialized_copy(
Types.begin(),
Types.end(),
295 GTM->getTrailingObjects<
MDNode *>());
304 return IsJumpTableCanonical;
307 bool isExported()
const {
312 return ArrayRef(getTrailingObjects<MDNode *>(), NTypes);
316struct ICallBranchFunnel final
321 auto *
Call =
static_cast<ICallBranchFunnel *
>(
322 Alloc.
Allocate(totalSizeToAlloc<GlobalTypeMember *>(Targets.
size()),
323 alignof(ICallBranchFunnel)));
325 Call->UniqueId = UniqueId;
327 std::uninitialized_copy(Targets.
begin(), Targets.
end(),
328 Call->getTrailingObjects<GlobalTypeMember *>());
334 return ArrayRef(getTrailingObjects<GlobalTypeMember *>(), NTargets);
343struct ScopedSaveAliaseesAndUsed {
346 std::vector<std::pair<GlobalAlias *, Function *>> FunctionAliases;
347 std::vector<std::pair<GlobalIFunc *, Function *>> ResolverIFuncs;
349 ScopedSaveAliaseesAndUsed(
Module &M) :
M(
M) {
363 GV->eraseFromParent();
365 GV->eraseFromParent();
367 for (
auto &GA :
M.aliases()) {
370 if (
auto *
F = dyn_cast<Function>(GA.getAliasee()->stripPointerCasts()))
371 FunctionAliases.push_back({&GA,
F});
374 for (
auto &GI :
M.ifuncs())
375 if (
auto *
F = dyn_cast<Function>(GI.getResolver()->stripPointerCasts()))
376 ResolverIFuncs.push_back({&GI,
F});
379 ~ScopedSaveAliaseesAndUsed() {
383 for (
auto P : FunctionAliases)
384 P.first->setAliasee(
P.second);
386 for (
auto P : ResolverIFuncs) {
390 P.first->setResolver(
P.second);
395class LowerTypeTestsModule {
411 bool CanUseArmJumpTable =
false, CanUseThumbBWJumpTable =
false;
414 int HasBranchTargetEnforcement = -1;
422 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
425 PointerType *Int32PtrTy = PointerType::getUnqual(
M.getContext());
427 IntegerType *IntPtrTy =
M.getDataLayout().getIntPtrType(
M.getContext(), 0);
435 struct TypeIdUserInfo {
436 std::vector<CallInst *> CallSites;
437 bool IsExported =
false;
445 struct TypeIdLowering {
469 std::vector<ByteArrayInfo> ByteArrayInfos;
471 Function *WeakInitializerFn =
nullptr;
476 bool shouldExportConstantsAsAbsoluteSymbols();
477 uint8_t *exportTypeId(
StringRef TypeId,
const TypeIdLowering &TIL);
478 TypeIdLowering importTypeId(
StringRef TypeId);
481 std::vector<GlobalAlias *> &AliasesToErase);
486 ByteArrayInfo *createByteArray(
BitSetInfo &BSI);
487 void allocateByteArrays();
490 void lowerTypeTestCalls(
494 const TypeIdLowering &TIL);
500 bool hasBranchTargetEnforcement();
501 unsigned getJumpTableEntrySize();
502 Type *getJumpTableEntryType();
519 bool IsJumpTableCanonical);
521 void findGlobalVariableUsersOf(
Constant *
C,
531 void replaceCfiUses(
Function *Old,
Value *New,
bool IsJumpTableCanonical);
535 void replaceDirectCalls(
Value *Old,
Value *New);
537 bool isFunctionAnnotation(
Value *V)
const {
538 return FunctionAnnotations.
contains(V);
564 for (
const auto &GlobalAndOffset : GlobalLayout) {
565 for (
MDNode *
Type : GlobalAndOffset.first->types()) {
566 if (
Type->getOperand(1) != TypeId)
570 cast<ConstantAsMetadata>(
Type->getOperand(0))->getValue())
583 auto BitsType = cast<IntegerType>(Bits->getType());
584 unsigned BitWidth = BitsType->getBitWidth();
586 BitOffset =
B.CreateZExtOrTrunc(BitOffset, BitsType);
588 B.CreateAnd(BitOffset, ConstantInt::get(BitsType,
BitWidth - 1));
589 Value *BitMask =
B.CreateShl(ConstantInt::get(BitsType, 1), BitIndex);
590 Value *MaskedBits =
B.CreateAnd(Bits, BitMask);
591 return B.CreateICmpNE(MaskedBits, ConstantInt::get(BitsType, 0));
594ByteArrayInfo *LowerTypeTestsModule::createByteArray(
BitSetInfo &BSI) {
603 ByteArrayInfos.emplace_back();
604 ByteArrayInfo *BAI = &ByteArrayInfos.back();
606 BAI->Bits = BSI.
Bits;
608 BAI->ByteArray = ByteArrayGlobal;
609 BAI->MaskGlobal = MaskGlobal;
613void LowerTypeTestsModule::allocateByteArrays() {
615 [](
const ByteArrayInfo &BAI1,
const ByteArrayInfo &BAI2) {
616 return BAI1.BitSize > BAI2.BitSize;
619 std::vector<uint64_t> ByteArrayOffsets(ByteArrayInfos.size());
622 for (
unsigned I = 0;
I != ByteArrayInfos.size(); ++
I) {
623 ByteArrayInfo *BAI = &ByteArrayInfos[
I];
626 BAB.
allocate(BAI->Bits, BAI->BitSize, ByteArrayOffsets[
I], Mask);
628 BAI->MaskGlobal->replaceAllUsesWith(
630 BAI->MaskGlobal->eraseFromParent();
632 *BAI->MaskPtr =
Mask;
640 for (
unsigned I = 0;
I != ByteArrayInfos.size(); ++
I) {
641 ByteArrayInfo *BAI = &ByteArrayInfos[
I];
643 Constant *Idxs[] = {ConstantInt::get(IntPtrTy, 0),
644 ConstantInt::get(IntPtrTy, ByteArrayOffsets[
I])};
646 ByteArrayConst->
getType(), ByteArray, Idxs);
653 BAI->ByteArray->replaceAllUsesWith(Alias);
654 BAI->ByteArray->eraseFromParent();
660 ByteArraySizeBytes = BAB.
Bytes.size();
666 const TypeIdLowering &TIL,
673 Constant *ByteArray = TIL.TheByteArray;
680 "bits_use", ByteArray, &M);
683 Value *ByteAddr =
B.CreateGEP(Int8Ty, ByteArray, BitOffset);
688 return B.CreateICmpNE(ByteAndMask, ConstantInt::get(Int8Ty, 0));
694 if (
auto GV = dyn_cast<GlobalObject>(V)) {
696 GV->getMetadata(LLVMContext::MD_type, Types);
698 if (
Type->getOperand(1) != TypeId)
702 cast<ConstantAsMetadata>(
Type->getOperand(0))->getValue())
710 if (
auto GEP = dyn_cast<GEPOperator>(V)) {
711 APInt APOffset(
DL.getIndexSizeInBits(0), 0);
712 bool Result =
GEP->accumulateConstantOffset(
DL, APOffset);
719 if (
auto Op = dyn_cast<Operator>(V)) {
720 if (
Op->getOpcode() == Instruction::BitCast)
723 if (
Op->getOpcode() == Instruction::Select)
734 const TypeIdLowering &TIL) {
750 Value *PtrAsInt =
B.CreatePtrToInt(
Ptr, IntPtrTy);
755 return B.CreateICmpEQ(PtrAsInt, OffsetedGlobalAsInt);
757 Value *PtrOffset =
B.CreateSub(PtrAsInt, OffsetedGlobalAsInt);
768 B.CreateLShr(PtrOffset,
B.CreateZExt(TIL.AlignLog2, IntPtrTy));
769 Value *OffsetSHL =
B.CreateShl(
770 PtrOffset,
B.CreateZExt(
772 ConstantInt::get(Int8Ty,
DL.getPointerSizeInBits(0)),
775 Value *BitOffset =
B.CreateOr(OffsetSHR, OffsetSHL);
777 Value *OffsetInRange =
B.CreateICmpULE(BitOffset, TIL.SizeM1);
781 return OffsetInRange;
788 if (
auto *Br = dyn_cast<BranchInst>(*CI->
user_begin()))
794 Br->getMetadata(LLVMContext::MD_prof));
798 for (
auto &Phi :
Else->phis())
799 Phi.addIncoming(
Phi.getIncomingValueForBlock(Then), InitialBB);
802 return createBitSetTest(ThenB, TIL, BitOffset);
809 Value *
Bit = createBitSetTest(ThenB, TIL, BitOffset);
814 B.SetInsertPoint(CI);
816 P->addIncoming(ConstantInt::get(Int1Ty, 0), InitialBB);
817 P->addIncoming(Bit, ThenB.GetInsertBlock());
823void LowerTypeTestsModule::buildBitSetsFromGlobalVariables(
830 std::vector<Constant *> GlobalInits;
836 for (GlobalTypeMember *
G : Globals) {
837 auto *GV = cast<GlobalVariable>(
G->getGlobal());
839 DL.getValueOrABITypeAlignment(GV->getAlign(), GV->getValueType());
840 MaxAlign = std::max(MaxAlign, Alignment);
842 GlobalLayout[
G] = GVOffset;
845 GlobalInits.push_back(
849 GlobalInits.push_back(GV->getInitializer());
850 uint64_t InitSize =
DL.getTypeAllocSize(GV->getValueType());
851 CurOffset = GVOffset + InitSize;
860 if (DesiredPadding > 32)
861 DesiredPadding =
alignTo(InitSize, 32) - InitSize;
865 auto *CombinedGlobal =
868 CombinedGlobal->setAlignment(MaxAlign);
871 lowerTypeTestCalls(TypeIds, CombinedGlobal, GlobalLayout);
876 for (
unsigned I = 0;
I != Globals.size(); ++
I) {
880 Constant *CombinedGlobalIdxs[] = {ConstantInt::get(Int32Ty, 0),
881 ConstantInt::get(Int32Ty,
I * 2)};
883 NewInit->
getType(), CombinedGlobal, CombinedGlobalIdxs);
887 "", CombinedGlobalElemPtr, &M);
895bool LowerTypeTestsModule::shouldExportConstantsAsAbsoluteSymbols() {
908uint8_t *LowerTypeTestsModule::exportTypeId(
StringRef TypeId,
909 const TypeIdLowering &TIL) {
917 "__typeid_" + TypeId +
"_" +
Name,
C, &M);
922 if (shouldExportConstantsAsAbsoluteSymbols())
925 Storage = cast<ConstantInt>(
C)->getZExtValue();
929 ExportGlobal(
"global_addr", TIL.OffsetedGlobal);
934 ExportConstant(
"align", TTRes.
AlignLog2, TIL.AlignLog2);
935 ExportConstant(
"size_m1", TTRes.
SizeM1, TIL.SizeM1);
937 uint64_t BitSize = cast<ConstantInt>(TIL.SizeM1)->getZExtValue() + 1;
945 ExportGlobal(
"byte_array", TIL.TheByteArray);
946 if (shouldExportConstantsAsAbsoluteSymbols())
947 ExportGlobal(
"bit_mask", TIL.BitMask);
953 ExportConstant(
"inline_bits", TTRes.
InlineBits, TIL.InlineBits);
958LowerTypeTestsModule::TypeIdLowering
959LowerTypeTestsModule::importTypeId(
StringRef TypeId) {
971 Constant *
C =
M.getOrInsertGlobal((
"__typeid_" + TypeId +
"_" +
Name).str(),
973 if (
auto *GV = dyn_cast<GlobalVariable>(
C))
980 if (!shouldExportConstantsAsAbsoluteSymbols()) {
982 ConstantInt::get(isa<IntegerType>(Ty) ? Ty : Int64Ty, Const);
983 if (!isa<IntegerType>(Ty))
989 auto *GV = cast<GlobalVariable>(
C->stripPointerCasts());
990 if (isa<IntegerType>(Ty))
992 if (GV->
getMetadata(LLVMContext::MD_absolute_symbol))
1002 SetAbsRange(~0ull, ~0ull);
1004 SetAbsRange(0, 1ull << AbsWidth);
1009 TIL.OffsetedGlobal = ImportGlobal(
"global_addr");
1014 TIL.AlignLog2 = ImportConstant(
"align", TTRes.
AlignLog2, 8, Int8Ty);
1020 TIL.TheByteArray = ImportGlobal(
"byte_array");
1021 TIL.BitMask = ImportConstant(
"bit_mask", TTRes.
BitMask, 8, Int8PtrTy);
1025 TIL.InlineBits = ImportConstant(
1032void LowerTypeTestsModule::importTypeTest(
CallInst *CI) {
1033 auto TypeIdMDVal = dyn_cast<MetadataAsValue>(CI->
getArgOperand(1));
1037 auto TypeIdStr = dyn_cast<MDString>(TypeIdMDVal->getMetadata());
1044 TypeIdLowering TIL = importTypeId(TypeIdStr->getString());
1045 Value *Lowered = lowerTypeTestCall(TypeIdStr, CI, TIL);
1054void LowerTypeTestsModule::importFunction(
1056 std::vector<GlobalAlias *> &AliasesToErase) {
1057 assert(
F->getType()->getAddressSpace() == 0);
1060 std::string
Name = std::string(
F->getName());
1065 if (
F->isDSOLocal()) {
1068 F->getAddressSpace(),
1071 replaceDirectCalls(
F, RealF);
1081 F->getAddressSpace(),
Name +
".cfi_jt", &M);
1084 F->setName(
Name +
".cfi");
1087 F->getAddressSpace(),
Name, &M);
1094 for (
auto &U :
F->uses()) {
1095 if (
auto *
A = dyn_cast<GlobalAlias>(
U.getUser())) {
1098 F->getAddressSpace(),
"", &M);
1100 A->replaceAllUsesWith(AliasDecl);
1101 AliasesToErase.push_back(
A);
1106 if (
F->hasExternalWeakLinkage())
1113 F->setVisibility(Visibility);
1116void LowerTypeTestsModule::lowerTypeTestCalls(
1122 BitSetInfo BSI = buildBitSet(TypeId, GlobalLayout);
1124 if (
auto MDS = dyn_cast<MDString>(TypeId))
1125 dbgs() << MDS->getString() <<
": ";
1127 dbgs() <<
"<unnamed>: ";
1131 ByteArrayInfo *BAI =
nullptr;
1134 Int8Ty, CombinedGlobalAddr, ConstantInt::get(IntPtrTy, BSI.
ByteOffset)),
1135 TIL.AlignLog2 = ConstantInt::get(Int8Ty, BSI.
AlignLog2);
1136 TIL.SizeM1 = ConstantInt::get(IntPtrTy, BSI.
BitSize - 1);
1140 }
else if (BSI.
BitSize <= 64) {
1143 for (
auto Bit : BSI.
Bits)
1145 if (InlineBits == 0)
1148 TIL.InlineBits = ConstantInt::get(
1149 (BSI.
BitSize <= 32) ? Int32Ty : Int64Ty, InlineBits);
1152 ++NumByteArraysCreated;
1153 BAI = createByteArray(BSI);
1154 TIL.TheByteArray = BAI->ByteArray;
1155 TIL.BitMask = BAI->MaskGlobal;
1158 TypeIdUserInfo &TIUI = TypeIdUsers[TypeId];
1160 if (TIUI.IsExported) {
1161 uint8_t *MaskPtr = exportTypeId(cast<MDString>(TypeId)->getString(), TIL);
1163 BAI->MaskPtr = MaskPtr;
1167 for (
CallInst *CI : TIUI.CallSites) {
1168 ++NumTypeTestCallsLowered;
1169 Value *Lowered = lowerTypeTestCall(TypeId, CI, TIL);
1179 if (
Type->getNumOperands() != 2)
1184 if (isa<GlobalVariable>(GO) && GO->
hasSection())
1186 "A member of a type identifier may not have an explicit section");
1192 auto OffsetConstMD = dyn_cast<ConstantAsMetadata>(
Type->getOperand(0));
1195 auto OffsetInt = dyn_cast<ConstantInt>(OffsetConstMD->getValue());
1208bool LowerTypeTestsModule::hasBranchTargetEnforcement() {
1209 if (HasBranchTargetEnforcement == -1) {
1212 if (
const auto *BTE = mdconst::extract_or_null<ConstantInt>(
1213 M.getModuleFlag(
"branch-target-enforcement")))
1214 HasBranchTargetEnforcement = (BTE->getZExtValue() != 0);
1216 HasBranchTargetEnforcement = 0;
1218 return HasBranchTargetEnforcement;
1221unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
1222 switch (JumpTableArch) {
1225 if (
const auto *MD = mdconst::extract_or_null<ConstantInt>(
1226 M.getModuleFlag(
"cf-protection-branch")))
1227 if (MD->getZExtValue())
1233 if (CanUseThumbBWJumpTable) {
1234 if (hasBranchTargetEnforcement())
1241 if (hasBranchTargetEnforcement())
1257void LowerTypeTestsModule::createJumpTableEntry(
1261 unsigned ArgIndex = AsmArgs.
size();
1265 if (
const auto *MD = mdconst::extract_or_null<ConstantInt>(
1267 Endbr = !MD->isZero();
1269 AsmOS << (JumpTableArch ==
Triple::x86 ?
"endbr32\n" :
"endbr64\n");
1270 AsmOS <<
"jmp ${" << ArgIndex <<
":c}@plt\n";
1272 AsmOS <<
".balign 16, 0xcc\n";
1274 AsmOS <<
"int3\nint3\nint3\n";
1276 AsmOS <<
"b $" << ArgIndex <<
"\n";
1278 if (hasBranchTargetEnforcement())
1280 AsmOS <<
"b $" << ArgIndex <<
"\n";
1282 if (!CanUseThumbBWJumpTable) {
1298 AsmOS <<
"push {r0,r1}\n"
1300 <<
"0: add r0, r0, pc\n"
1301 <<
"str r0, [sp, #4]\n"
1304 <<
"1: .word $" << ArgIndex <<
" - (0b + 4)\n";
1306 if (hasBranchTargetEnforcement())
1308 AsmOS <<
"b.w $" << ArgIndex <<
"\n";
1312 AsmOS <<
"tail $" << ArgIndex <<
"@plt\n";
1314 AsmOS <<
"pcalau12i $$t0, %pc_hi20($" << ArgIndex <<
")\n"
1315 <<
"jirl $$r0, $$t0, %pc_lo12($" << ArgIndex <<
")\n";
1320 ConstraintOS << (ArgIndex > 0 ?
",s" :
"s");
1324Type *LowerTypeTestsModule::getJumpTableEntryType() {
1330void LowerTypeTestsModule::buildBitSetsFromFunctions(
1336 buildBitSetsFromFunctionsNative(TypeIds, Functions);
1338 buildBitSetsFromFunctionsWASM(TypeIds, Functions);
1343void LowerTypeTestsModule::moveInitializerToModuleConstructor(
1345 if (WeakInitializerFn ==
nullptr) {
1350 M.getDataLayout().getProgramAddressSpace(),
1351 "__cfi_global_var_init", &M);
1355 WeakInitializerFn->setSection(
1357 ?
"__TEXT,__StaticInit,regular,pure_instructions"
1364 IRBuilder<> IRB(WeakInitializerFn->getEntryBlock().getTerminator());
1370void LowerTypeTestsModule::findGlobalVariableUsersOf(
1372 for (
auto *U :
C->users()){
1373 if (
auto *GV = dyn_cast<GlobalVariable>(U))
1375 else if (
auto *C2 = dyn_cast<Constant>(U))
1376 findGlobalVariableUsersOf(C2, Out);
1381void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr(
1386 findGlobalVariableUsersOf(
F, GlobalVarUsers);
1387 for (
auto *GV : GlobalVarUsers) {
1388 if (GV == GlobalAnnotation)
1390 moveInitializerToModuleConstructor(GV);
1398 F->getAddressSpace(),
"", &M);
1399 replaceCfiUses(
F, PlaceholderFn, IsJumpTableCanonical);
1405 auto *InsertPt = dyn_cast<Instruction>(
U.getUser());
1406 assert(InsertPt &&
"Non-instruction users should have been eliminated");
1407 auto *PN = dyn_cast<PHINode>(InsertPt);
1409 InsertPt = PN->getIncomingBlock(U)->getTerminator();
1418 PN->setIncomingValueForBlock(InsertPt->getParent(),
Select);
1426 Attribute TFAttr =
F->getFnAttribute(
"target-features");
1431 if (Feature ==
"-thumb-mode")
1433 else if (Feature ==
"+thumb-mode")
1449 if (!CanUseThumbBWJumpTable && CanUseArmJumpTable) {
1457 unsigned ArmCount = 0, ThumbCount = 0;
1458 for (
const auto GTM : Functions) {
1459 if (!GTM->isJumpTableCanonical()) {
1466 Function *
F = cast<Function>(GTM->getGlobal());
1473void LowerTypeTestsModule::createJumpTable(
1475 std::string AsmStr, ConstraintStr;
1484 bool areAllEntriesNounwind =
true;
1485 for (GlobalTypeMember *GTM : Functions) {
1486 if (!llvm::cast<llvm::Function>(GTM->getGlobal())
1487 ->hasFnAttribute(llvm::Attribute::NoUnwind)) {
1488 areAllEntriesNounwind =
false;
1490 createJumpTableEntry(AsmOS, ConstraintOS, JumpTableArch, AsmArgs,
1491 cast<Function>(GTM->getGlobal()));
1495 F->setAlignment(
Align(getJumpTableEntrySize()));
1501 F->addFnAttr(Attribute::Naked);
1503 F->addFnAttr(
"target-features",
"-thumb-mode");
1505 if (hasBranchTargetEnforcement()) {
1508 F->addFnAttr(
"target-features",
"+thumb-mode,+pacbti");
1510 F->addFnAttr(
"target-features",
"+thumb-mode");
1511 if (CanUseThumbBWJumpTable) {
1514 F->addFnAttr(
"target-cpu",
"cortex-a8");
1522 if (
F->hasFnAttribute(
"branch-target-enforcement"))
1523 F->removeFnAttr(
"branch-target-enforcement");
1524 if (
F->hasFnAttribute(
"sign-return-address"))
1525 F->removeFnAttr(
"sign-return-address");
1530 F->addFnAttr(
"target-features",
"-c,-relax");
1536 F->addFnAttr(Attribute::NoCfCheck);
1539 if (areAllEntriesNounwind)
1540 F->addFnAttr(Attribute::NoUnwind);
1543 F->addFnAttr(Attribute::NoInline);
1550 for (
const auto &Arg : AsmArgs)
1554 AsmOS.str(), ConstraintOS.str(),
1557 IRB.CreateCall(JumpTableAsm, AsmArgs);
1558 IRB.CreateUnreachable();
1563void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
1645 JumpTableArch = selectJumpTableArmEncoding(Functions);
1649 unsigned EntrySize = getJumpTableEntrySize();
1650 for (
unsigned I = 0;
I != Functions.
size(); ++
I)
1651 GlobalLayout[Functions[
I]] =
I * EntrySize;
1657 M.getDataLayout().getProgramAddressSpace(),
1658 ".cfi.jumptable", &M);
1664 lowerTypeTestCalls(TypeIds, JumpTable, GlobalLayout);
1667 ScopedSaveAliaseesAndUsed S(M);
1671 for (
unsigned I = 0;
I != Functions.
size(); ++
I) {
1672 Function *
F = cast<Function>(Functions[
I]->getGlobal());
1673 bool IsJumpTableCanonical = Functions[
I]->isJumpTableCanonical();
1676 JumpTableType, JumpTable,
1678 ConstantInt::get(IntPtrTy,
I)});
1680 const bool IsExported = Functions[
I]->isExported();
1681 if (!IsJumpTableCanonical) {
1686 F->getName() +
".cfi_jt",
1687 CombinedGlobalElemPtr, &M);
1695 if (IsJumpTableCanonical)
1701 if (!IsJumpTableCanonical) {
1702 if (
F->hasExternalWeakLinkage())
1703 replaceWeakDeclarationWithJumpTablePtr(
F, CombinedGlobalElemPtr,
1704 IsJumpTableCanonical);
1706 replaceCfiUses(
F, CombinedGlobalElemPtr, IsJumpTableCanonical);
1708 assert(
F->getType()->getAddressSpace() == 0);
1712 CombinedGlobalElemPtr, &M);
1716 F->setName(FAlias->
getName() +
".cfi");
1717 replaceCfiUses(
F, FAlias, IsJumpTableCanonical);
1718 if (!
F->hasLocalLinkage())
1724 createJumpTable(JumpTableFn, Functions);
1733void LowerTypeTestsModule::buildBitSetsFromFunctionsWASM(
1740 for (GlobalTypeMember *GTM : Functions) {
1741 Function *
F = cast<Function>(GTM->getGlobal());
1744 if (!
F->hasAddressTaken())
1750 ConstantInt::get(Int64Ty, IndirectIndex))));
1751 F->setMetadata(
"wasm.index", MD);
1754 GlobalLayout[GTM] = IndirectIndex++;
1763void LowerTypeTestsModule::buildBitSetsFromDisjointSet(
1767 for (
unsigned I = 0;
I != TypeIds.
size(); ++
I)
1768 TypeIdIndices[TypeIds[
I]] =
I;
1772 std::vector<std::set<uint64_t>> TypeMembers(TypeIds.
size());
1773 unsigned GlobalIndex = 0;
1775 for (GlobalTypeMember *GTM : Globals) {
1778 auto I = TypeIdIndices.
find(
Type->getOperand(1));
1779 if (
I != TypeIdIndices.
end())
1780 TypeMembers[
I->second].insert(GlobalIndex);
1782 GlobalIndices[GTM] = GlobalIndex;
1786 for (ICallBranchFunnel *JT : ICallBranchFunnels) {
1787 TypeMembers.emplace_back();
1788 std::set<uint64_t> &TMSet = TypeMembers.back();
1789 for (GlobalTypeMember *
T :
JT->targets())
1790 TMSet.insert(GlobalIndices[
T]);
1796 const std::set<uint64_t> &O2) {
1797 return O1.size() < O2.size();
1804 for (
auto &&MemSet : TypeMembers)
1805 GLB.addFragment(MemSet);
1809 Globals.empty() || isa<GlobalVariable>(Globals[0]->getGlobal());
1810 std::vector<GlobalTypeMember *> OrderedGTMs(Globals.size());
1811 auto OGTMI = OrderedGTMs.begin();
1812 for (
auto &&
F : GLB.Fragments) {
1814 if (IsGlobalSet != isa<GlobalVariable>(Globals[
Offset]->getGlobal()))
1816 "variables and functions");
1817 *OGTMI++ = Globals[
Offset];
1823 buildBitSetsFromGlobalVariables(TypeIds, OrderedGTMs);
1825 buildBitSetsFromFunctions(TypeIds, OrderedGTMs);
1829LowerTypeTestsModule::LowerTypeTestsModule(
1832 :
M(
M), ExportSummary(ExportSummary), ImportSummary(ImportSummary),
1834 assert(!(ExportSummary && ImportSummary));
1835 Triple TargetTriple(
M.getTargetTriple());
1836 Arch = TargetTriple.getArch();
1838 CanUseArmJumpTable =
true;
1845 CanUseArmJumpTable =
true;
1847 CanUseThumbBWJumpTable =
true;
1850 OS = TargetTriple.getOS();
1851 ObjectFormat = TargetTriple.getObjectFormat();
1855 GlobalAnnotation =
M.getGlobalVariable(
"llvm.global.annotations");
1856 if (GlobalAnnotation && GlobalAnnotation->hasInitializer()) {
1858 cast<ConstantArray>(GlobalAnnotation->getInitializer());
1860 FunctionAnnotations.insert(
Op);
1872 auto ReadSummaryFile =
1875 yaml::Input
In(ReadSummaryFile->getBuffer());
1881 LowerTypeTestsModule(
1895 yaml::Output Out(
OS);
1903 auto *Usr = dyn_cast<CallInst>(U.getUser());
1905 auto *CB = dyn_cast<CallBase>(Usr);
1906 if (CB && CB->isCallee(&U))
1912void LowerTypeTestsModule::replaceCfiUses(
Function *Old,
Value *New,
1913 bool IsJumpTableCanonical) {
1918 if (isa<BlockAddress, NoCFIValue>(
U.getUser()))
1926 if (isFunctionAnnotation(
U.getUser()))
1931 if (
auto *
C = dyn_cast<Constant>(
U.getUser())) {
1932 if (!isa<GlobalValue>(
C)) {
1945 C->handleOperandChange(Old, New);
1948void LowerTypeTestsModule::replaceDirectCalls(
Value *Old,
Value *New) {
1954 auto *CI = cast<CallInst>(U.getUser());
1957 if (
auto *Assume = dyn_cast<AssumeInst>(CIU.getUser()))
1958 Assume->eraseFromParent();
1964 all_of(CI->
users(), [](
User *U) ->
bool { return isa<PHINode>(U); }));
1971bool LowerTypeTestsModule::lower() {
1975 if (DropTypeTests) {
1983 if (PublicTypeTestFunc)
1985 if (TypeTestFunc || PublicTypeTestFunc) {
2006 if ((!TypeTestFunc || TypeTestFunc->
use_empty()) &&
2007 (!ICallBranchFunnelFunc || ICallBranchFunnelFunc->
use_empty()) &&
2008 !ExportSummary && !ImportSummary)
2011 if (ImportSummary) {
2014 importTypeTest(cast<CallInst>(
U.getUser()));
2016 if (ICallBranchFunnelFunc && !ICallBranchFunnelFunc->
use_empty())
2018 "unexpected call to llvm.icall.branch.funnel during import phase");
2025 if (
F.hasLocalLinkage())
2030 std::string(
F.getName())))
2034 std::vector<GlobalAlias *> AliasesToErase;
2036 ScopedSaveAliaseesAndUsed S(M);
2037 for (
auto *
F : Defs)
2038 importFunction(
F,
true, AliasesToErase);
2039 for (
auto *
F : Decls)
2040 importFunction(
F,
false, AliasesToErase);
2053 GlobalClassesTy GlobalClasses;
2065 std::vector<GlobalTypeMember *> RefGlobals;
2068 unsigned CurUniqueId = 0;
2073 const bool CrossDsoCfi =
M.getModuleFlag(
"Cross-DSO CFI") !=
nullptr;
2075 struct ExportedFunctionInfo {
2080 if (ExportSummary) {
2083 for (
auto &
I : *ExportSummary)
2084 for (
auto &GVS :
I.second.SummaryList)
2086 for (
const auto &
Ref : GVS->refs())
2089 NamedMDNode *CfiFunctionsMD =
M.getNamedMetadata(
"cfi.functions");
2090 if (CfiFunctionsMD) {
2091 for (
auto *FuncMD : CfiFunctionsMD->
operands()) {
2092 assert(FuncMD->getNumOperands() >= 2);
2094 cast<MDString>(FuncMD->getOperand(0))->getString();
2096 cast<ConstantAsMetadata>(FuncMD->getOperand(1))
2098 ->getUniqueInteger()
2104 if (!ExportSummary->isGUIDLive(GUID))
2106 if (!AddressTaken.
count(GUID)) {
2111 if (
auto VI = ExportSummary->getValueInfo(GUID))
2112 for (
const auto &GVS :
VI.getSummaryList())
2119 auto P = ExportedFunctions.
insert({FunctionName, {
Linkage, FuncMD}});
2121 P.first->second = {
Linkage, FuncMD};
2124 for (
const auto &
P : ExportedFunctions) {
2127 MDNode *FuncMD =
P.second.FuncMD;
2129 if (
F &&
F->hasLocalLinkage()) {
2136 F->setName(
F->getName() +
".1");
2143 GlobalVariable::ExternalLinkage,
2144 M.getDataLayout().getProgramAddressSpace(), FunctionName, &M);
2151 if (
F->hasAvailableExternallyLinkage()) {
2154 F->setComdat(
nullptr);
2167 if (
F->isDeclaration()) {
2171 F->eraseMetadata(LLVMContext::MD_type);
2173 F->addMetadata(LLVMContext::MD_type,
2188 bool IsJumpTableCanonical =
false;
2189 bool IsExported =
false;
2190 if (
Function *
F = dyn_cast<Function>(&GO)) {
2192 if (ExportedFunctions.count(
F->getName())) {
2193 IsJumpTableCanonical |=
2200 }
else if (!
F->hasAddressTaken()) {
2201 if (!CrossDsoCfi || !IsJumpTableCanonical ||
F->hasLocalLinkage())
2206 auto *GTM = GlobalTypeMember::create(Alloc, &GO, IsJumpTableCanonical,
2208 GlobalTypeMembers[&GO] = GTM;
2210 verifyTypeMDNode(&GO,
Type);
2211 auto &
Info = TypeIdInfo[
Type->getOperand(1)];
2212 Info.UniqueId = ++CurUniqueId;
2213 Info.RefGlobals.push_back(GTM);
2217 auto AddTypeIdUse = [&](
Metadata *TypeId) -> TypeIdUserInfo & {
2222 auto Ins = TypeIdUsers.insert({TypeId, {}});
2225 GlobalClassesTy::iterator GCI = GlobalClasses.insert(TypeId);
2226 GlobalClassesTy::member_iterator CurSet = GlobalClasses.findLeader(GCI);
2229 for (GlobalTypeMember *GTM : TypeIdInfo[TypeId].RefGlobals)
2230 CurSet = GlobalClasses.unionSets(
2231 CurSet, GlobalClasses.findLeader(GlobalClasses.insert(GTM)));
2234 return Ins.first->second;
2238 for (
const Use &U : TypeTestFunc->
uses()) {
2239 auto CI = cast<CallInst>(
U.getUser());
2247 for (
const Use &CIU : CI->
uses()) {
2248 if (isa<AssumeInst>(CIU.getUser()))
2250 OnlyAssumeUses =
false;
2256 auto TypeIdMDVal = dyn_cast<MetadataAsValue>(CI->
getArgOperand(1));
2259 auto TypeId = TypeIdMDVal->getMetadata();
2260 AddTypeIdUse(TypeId).CallSites.push_back(CI);
2264 if (ICallBranchFunnelFunc) {
2265 for (
const Use &U : ICallBranchFunnelFunc->
uses()) {
2268 "llvm.icall.branch.funnel not supported on this target");
2270 auto CI = cast<CallInst>(
U.getUser());
2272 std::vector<GlobalTypeMember *> Targets;
2276 GlobalClassesTy::member_iterator CurSet;
2277 for (
unsigned I = 1;
I != CI->
arg_size();
I += 2) {
2283 "Expected branch funnel operand to be global value");
2285 GlobalTypeMember *GTM = GlobalTypeMembers[
Base];
2286 Targets.push_back(GTM);
2287 GlobalClassesTy::member_iterator NewSet =
2288 GlobalClasses.findLeader(GlobalClasses.insert(GTM));
2292 CurSet = GlobalClasses.unionSets(CurSet, NewSet);
2295 GlobalClasses.unionSets(
2296 CurSet, GlobalClasses.findLeader(
2297 GlobalClasses.insert(ICallBranchFunnel::create(
2298 Alloc, CI, Targets, ++CurUniqueId))));
2302 if (ExportSummary) {
2304 for (
auto &
P : TypeIdInfo) {
2305 if (
auto *TypeId = dyn_cast<MDString>(
P.first))
2310 for (
auto &
P : *ExportSummary) {
2311 for (
auto &S :
P.second.SummaryList) {
2312 if (!ExportSummary->isGlobalValueLive(S.get()))
2314 if (
auto *FS = dyn_cast<FunctionSummary>(S->getBaseObject()))
2317 AddTypeIdUse(MD).IsExported =
true;
2322 if (GlobalClasses.empty())
2327 std::vector<std::pair<GlobalClassesTy::iterator, unsigned>> Sets;
2328 for (GlobalClassesTy::iterator
I = GlobalClasses.begin(),
2329 E = GlobalClasses.end();
2333 ++NumTypeIdDisjointSets;
2335 unsigned MaxUniqueId = 0;
2336 for (GlobalClassesTy::member_iterator
MI = GlobalClasses.member_begin(
I);
2337 MI != GlobalClasses.member_end(); ++
MI) {
2338 if (
auto *MD = dyn_cast_if_present<Metadata *>(*
MI))
2339 MaxUniqueId = std::max(MaxUniqueId, TypeIdInfo[MD].UniqueId);
2340 else if (
auto *BF = dyn_cast_if_present<ICallBranchFunnel *>(*
MI))
2341 MaxUniqueId = std::max(MaxUniqueId, BF->UniqueId);
2343 Sets.emplace_back(
I, MaxUniqueId);
2348 for (
const auto &S : Sets) {
2350 std::vector<Metadata *> TypeIds;
2351 std::vector<GlobalTypeMember *> Globals;
2352 std::vector<ICallBranchFunnel *> ICallBranchFunnels;
2353 for (GlobalClassesTy::member_iterator
MI =
2354 GlobalClasses.member_begin(S.first);
2355 MI != GlobalClasses.member_end(); ++
MI) {
2356 if (isa<Metadata *>(*
MI))
2357 TypeIds.push_back(cast<Metadata *>(*
MI));
2358 else if (isa<GlobalTypeMember *>(*
MI))
2359 Globals.push_back(cast<GlobalTypeMember *>(*
MI));
2361 ICallBranchFunnels.push_back(cast<ICallBranchFunnel *>(*
MI));
2367 return TypeIdInfo[
M1].UniqueId < TypeIdInfo[M2].UniqueId;
2372 [&](ICallBranchFunnel *F1, ICallBranchFunnel *F2) {
2373 return F1->UniqueId < F2->UniqueId;
2377 buildBitSetsFromDisjointSet(TypeIds, Globals, ICallBranchFunnels);
2380 allocateByteArrays();
2384 if (ExportSummary) {
2385 if (
NamedMDNode *AliasesMD =
M.getNamedMetadata(
"aliases")) {
2386 for (
auto *AliasMD : AliasesMD->operands()) {
2387 assert(AliasMD->getNumOperands() >= 4);
2389 cast<MDString>(AliasMD->getOperand(0))->getString();
2390 StringRef Aliasee = cast<MDString>(AliasMD->getOperand(1))->getString();
2392 if (!ExportedFunctions.count(Aliasee) ||
2394 !
M.getNamedAlias(Aliasee))
2399 cast<ConstantAsMetadata>(AliasMD->getOperand(2))
2401 ->getUniqueInteger()
2404 static_cast<bool>(cast<ConstantAsMetadata>(AliasMD->getOperand(3))
2406 ->getUniqueInteger()
2414 if (
auto *
F =
M.getFunction(AliasName)) {
2416 F->replaceAllUsesWith(Alias);
2417 F->eraseFromParent();
2426 if (ExportSummary) {
2427 if (
NamedMDNode *SymversMD =
M.getNamedMetadata(
"symvers")) {
2428 for (
auto *Symver : SymversMD->operands()) {
2429 assert(Symver->getNumOperands() >= 2);
2431 cast<MDString>(Symver->getOperand(0))->getString();
2432 StringRef Alias = cast<MDString>(Symver->getOperand(1))->getString();
2434 if (!ExportedFunctions.count(SymbolName))
2437 M.appendModuleInlineAsm(
2438 (
llvm::Twine(
".symver ") + SymbolName +
", " + Alias).str());
2450 Changed = LowerTypeTestsModule::runForTesting(M, AM);
2453 LowerTypeTestsModule(M, AM, ExportSummary, ImportSummary, DropTypeTests)
amdgpu AMDGPU Register Bank Select
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file defines the BumpPtrAllocator interface.
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Analysis containing CSE Info
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseMap class.
Generic implementation of equivalence classes through the use Tarjan's efficient union-find algorithm...
This defines the Use class.
static const unsigned kARMJumpTableEntrySize
static const unsigned kLOONGARCH64JumpTableEntrySize
static bool isKnownTypeIdMember(Metadata *TypeId, const DataLayout &DL, Value *V, uint64_t COffset)
static const unsigned kX86IBTJumpTableEntrySize
static cl::opt< std::string > ClReadSummary("lowertypetests-read-summary", cl::desc("Read summary from given YAML file before running pass"), cl::Hidden)
static const unsigned kRISCVJumpTableEntrySize
static Value * createMaskedBitTest(IRBuilder<> &B, Value *Bits, Value *BitOffset)
Build a test that bit BitOffset mod sizeof(Bits)*8 is set in Bits.
static bool isThumbFunction(Function *F, Triple::ArchType ModuleArch)
static const unsigned kX86JumpTableEntrySize
static cl::opt< bool > AvoidReuse("lowertypetests-avoid-reuse", cl::desc("Try to avoid reuse of byte array addresses using aliases"), cl::Hidden, cl::init(true))
static void dropTypeTests(Module &M, Function &TypeTestFunc)
static cl::opt< PassSummaryAction > ClSummaryAction("lowertypetests-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
static const unsigned kARMBTIJumpTableEntrySize
static cl::opt< bool > ClDropTypeTests("lowertypetests-drop-type-tests", cl::desc("Simply drop type test assume sequences"), cl::Hidden, cl::init(false))
static cl::opt< std::string > ClWriteSummary("lowertypetests-write-summary", cl::desc("Write summary to given YAML file after running pass"), cl::Hidden)
static bool isDirectCall(Use &U)
static const unsigned kARMv6MJumpTableEntrySize
ModuleSummaryIndex.h This file contains the declarations the classes that hold the module index and s...
Module.h This file contains the declarations for the Module class.
FunctionAnalysisManager FAM
This header defines various interfaces for pass management in LLVM.
This file defines the PointerUnion class, which is a discriminated union of pointer types.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
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)
This header defines support for implementing classes that have some trailing object (or arrays of obj...
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="", bool Before=false)
Split the basic block into two basic blocks at the specified instruction.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Conditional or Unconditional Branch instruction.
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
Allocate memory in an ever growing pool, as if by bump-pointer.
LLVM_ATTRIBUTE_RETURNS_NONNULL void * Allocate(size_t Size, Align Alignment)
Allocate space at the specified alignment.
Value * getArgOperand(unsigned i) const
unsigned arg_size() const
This class represents a function call, abstracting a target machine's calling convention.
static ConstantAggregateZero * get(Type *Ty)
ConstantArray - Constant Array Declarations.
static Constant * get(LLVMContext &Context, ArrayRef< ElementTy > Elts)
get() constructor - Return a constant with array type with an element count and element type matching...
static Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList)
Create an "inbounds" getelementptr.
static Constant * getPointerCast(Constant *C, Type *Ty)
Create a BitCast, AddrSpaceCast, or a PtrToInt cast constant expression.
static Constant * getSub(Constant *C1, Constant *C2, bool HasNUW=false, bool HasNSW=false)
static Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
static ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getFalse(LLVMContext &Context)
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
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.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
Implements a dense probed hash-table based set.
EquivalenceClasses - This represents a collection of equivalence classes and supports three efficient...
Helper for check-and-exit error handling.
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
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...
MaybeAlign getAlign() const
Returns the alignment of the given variable or function.
void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
bool hasSection() const
Check if this global has a custom object file section.
MDNode * getMetadata(unsigned KindID) const
Get the current metadata attachments for the given kind, if any.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
VisibilityTypes getVisibility() const
static bool isLocalLinkage(LinkageTypes Linkage)
LinkageTypes getLinkage() const
static StringRef dropLLVMManglingEscape(StringRef Name)
If the given string begins with the GlobalValue name mangling escape character '\1',...
void setLinkage(LinkageTypes LT)
bool isDeclarationForLinker() const
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
Module * getParent()
Get the module that this global value is contained inside of...
PointerType * getType() const
Global values are always pointers.
VisibilityTypes
An enumeration for the kinds of visibility of global values.
@ HiddenVisibility
The GV is hidden.
void setVisibility(VisibilityTypes V)
LinkageTypes
An enumeration for the kinds of linkage for global values.
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
@ WeakAnyLinkage
Keep one copy of named function when linking (weak)
@ ExternalWeakLinkage
ExternalWeak linkage description.
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
void setConstant(bool Val)
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
static InlineAsm * get(FunctionType *Ty, StringRef AsmString, StringRef Constraints, bool hasSideEffects, bool isAlignStack=false, AsmDialect asmDialect=AD_ATT, bool canThrow=false)
InlineAsm::get - Return the specified uniqued inline asm string.
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
Class to represent integer types.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
This class implements a map that also provides access to all stored values in a deterministic order.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
Class to hold module path string table and global value map, and encapsulate methods for operating on...
std::set< std::string > & cfiFunctionDecls()
TypeIdSummary & getOrInsertTypeIdSummary(StringRef TypeId)
Return an existing or new TypeIdSummary entry for TypeId.
const TypeIdSummary * getTypeIdSummary(StringRef TypeId) const
This returns either a pointer to the type id summary (if present in the summary map) or null (if not ...
bool partiallySplitLTOUnits() const
std::set< std::string > & cfiFunctionDefs()
A Module instance is used to store all the information related to an LLVM module.
Metadata * getModuleFlag(StringRef Key) const
Return the corresponding value if Key appears in module flags, otherwise return null.
iterator_range< op_iterator > operands()
unsigned getAddressSpace() const
Return the address space of the Pointer type.
A discriminated union of two or more pointer types, with the discriminator in the low bit of the poin...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Class to represent struct types.
Type * getElementType(unsigned N) const
Analysis pass providing the TargetTransformInfo.
See the file comment for details on the usage of the TrailingObjects type.
Triple - Helper class for working with autoconf configuration names.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt1Ty(LLVMContext &C)
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt8Ty(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
static IntegerType * getInt64Ty(LLVMContext &C)
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
void setName(const Twine &Name)
Change the name of the value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
void replaceUsesWithIf(Value *New, llvm::function_ref< bool(Use &U)> ShouldReplace)
Go through the uses list for this definition and make each use point to "V" if the callback ShouldRep...
iterator_range< use_iterator > uses()
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
Linkage
Describes symbol linkage. This can be used to resolve definition clashes.
bool isJumpTableCanonical(Function *F)
NodeAddr< PhiNode * > Phi
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
This is an optimization pass for GlobalISel generic memory operations.
void ReplaceInstWithInst(BasicBlock *BB, BasicBlock::iterator &BI, Instruction *I)
Replace the instruction specified by BI with the instruction specified by I.
void stable_sort(R &&Range)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
unsigned M1(unsigned Val)
bool convertUsersOfConstantsToInstructions(ArrayRef< Constant * > Consts, Function *RestrictToFunc=nullptr, bool RemoveDeadConstants=true, bool IncludeSelf=false)
Replace constant expressions users of the given constants with instructions.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
@ Ref
The access may reference the value stored in memory.
void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
constexpr unsigned BitWidth
void appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Append F to the list of global ctors of module M with the given Priority.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
void appendToUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.used list.
CfiFunctionLinkage
The type of CFI jumptable needed for a function.
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
GlobalVariable * collectUsedGlobalVariables(const Module &M, SmallVectorImpl< GlobalValue * > &Vec, bool CompilerUsed)
Given "llvm.used" or "llvm.compiler.used" as a global name, collect the initializer elements of that ...
This struct is a compact representation of a valid (non-zero power of two) alignment.
Kind
Specifies which kind of type check we should emit for this byte array.
@ Unknown
Unknown (analysis not performed, don't lower)
@ Single
Single element (last example in "Short Inline Bit Vectors")
@ Inline
Inlined bit vector ("Short Inline Bit Vectors")
@ Unsat
Unsatisfiable type (i.e. no global has this type metadata)
@ AllOnes
All-ones bit vector ("Eliminating Bit Vector Checks for All-Ones Bit Vectors")
@ ByteArray
Test a byte array (first example)
unsigned SizeM1BitWidth
Range of size-1 expressed as a bit width.
enum llvm::TypeTestResolution::Kind TheKind
Function object to check whether the second component of a container supported by std::get (like std:...
SmallVector< uint64_t, 16 > Offsets
void addOffset(uint64_t Offset)
bool containsGlobalOffset(uint64_t Offset) const
void print(raw_ostream &OS) const
std::set< uint64_t > Bits
This class is used to build a byte array containing overlapping bit sets.
uint64_t BitAllocs[BitsPerByte]
The number of bytes allocated so far for each of the bits.
std::vector< uint8_t > Bytes
The byte array built so far.
void allocate(const std::set< uint64_t > &Bits, uint64_t BitSize, uint64_t &AllocByteOffset, uint8_t &AllocMask)
Allocate BitSize bits in the byte array where Bits contains the bits to set.
This class implements a layout algorithm for globals referenced by bit sets that tries to keep member...
std::vector< std::vector< uint64_t > > Fragments
The computed layout.
void addFragment(const std::set< uint64_t > &F)
Add F to the layout while trying to keep its indices contiguous.
std::vector< uint64_t > FragmentMap
Mapping from object index to fragment index.