60#define PASS_KEY "x86-slh"
61#define DEBUG_TYPE PASS_KEY
63STATISTIC(NumCondBranchesTraced,
"Number of conditional branches traced");
64STATISTIC(NumBranchesUntraced,
"Number of branches unable to trace");
66 "Number of address mode used registers hardened");
68 "Number of post-load register values hardened");
70 "Number of calls or jumps requiring extra hardening");
71STATISTIC(NumInstsInserted,
"Number of instructions inserted");
72STATISTIC(NumLFENCEsInserted,
"Number of lfence instructions inserted");
75 "x86-speculative-load-hardening",
82 "Use LFENCE along each conditional edge to harden against speculative "
83 "loads rather than conditional movs and poisoned pointers."),
88 cl::desc(
"Harden the value loaded *after* it is loaded by "
89 "flushing the loaded bits to 1. This is hard to do "
90 "in general but can be done easily for GPRs."),
95 cl::desc(
"Use a full speculation fence to harden both call and ret edges "
96 "rather than a lighter weight mitigation."),
101 cl::desc(
"Harden interprocedurally by passing our state in and out of "
102 "functions in the high bits of the stack pointer."),
107 cl::desc(
"Sanitize loads from memory. When disable, no "
108 "significant security is provided."),
113 cl::desc(
"Harden indirect calls and jumps against using speculatively "
114 "stored attacker controlled addresses. This is designed to "
115 "mitigate Spectre v1.2 style attacks."),
120constexpr StringRef X86SLHPassName =
"X86 speculative load hardening";
126 StringRef getPassName()
const override {
return X86SLHPassName; }
127 bool runOnMachineFunction(MachineFunction &MF)
override;
128 void getAnalysisUsage(AnalysisUsage &AU)
const override;
134class X86SpeculativeLoadHardeningImpl {
136 X86SpeculativeLoadHardeningImpl() =
default;
138 bool run(MachineFunction &MF);
143 struct BlockCondInfo {
144 MachineBasicBlock *MBB;
148 SmallVector<MachineInstr *, 2> CondBrs;
150 MachineInstr *UncondBr;
158 const TargetRegisterClass *RC;
159 MachineSSAUpdater SSA;
161 PredState(MachineFunction &MF,
const TargetRegisterClass *RC)
165 const X86Subtarget *Subtarget =
nullptr;
166 MachineRegisterInfo *MRI =
nullptr;
167 const X86InstrInfo *TII =
nullptr;
168 const TargetRegisterInfo *TRI =
nullptr;
170 std::optional<PredState> PS;
172 void hardenEdgesWithLFENCE(MachineFunction &MF);
179 void unfoldCallAndJumpLoads(MachineFunction &MF);
182 tracePredStateThroughIndirectBranches(MachineFunction &MF);
184 void tracePredStateThroughBlocksAndHarden(MachineFunction &MF);
189 void restoreEFLAGS(MachineBasicBlock &
MBB,
193 void mergePredStateIntoSP(MachineBasicBlock &
MBB,
196 Register extractPredStateFromSP(MachineBasicBlock &
MBB,
201 hardenLoadAddr(MachineInstr &
MI, MachineOperand &BaseMO,
202 MachineOperand &IndexMO,
203 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg);
205 sinkPostLoadHardenedInst(MachineInstr &
MI,
206 SmallPtrSetImpl<MachineInstr *> &HardenedInstrs);
212 void hardenReturnInstr(MachineInstr &
MI);
213 void tracePredStateThroughCall(MachineInstr &
MI);
214 void hardenIndirectCallOrJumpInstr(
216 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg);
221bool X86SpeculativeLoadHardeningLegacy::runOnMachineFunction(
223 X86SpeculativeLoadHardeningImpl Impl;
230char X86SpeculativeLoadHardeningLegacy::ID = 0;
232void X86SpeculativeLoadHardeningLegacy::getAnalysisUsage(
233 AnalysisUsage &AU)
const {
241 assert(!Succ.
isEHPad() &&
"Shouldn't get edges to EH pads!");
255 "Didn't start with the right target!");
264 assert(
MBB.isSuccessor(&OldLayoutSucc) &&
265 "Without an unconditional branch, the old layout successor should "
266 "be an actual successor!");
270 UncondBr = &*BrBuilder;
281 "Cannot have a branchless successor and an unconditional branch!");
283 "A non-branch successor must have been a layout successor before "
284 "and now is a layout successor of the new block.");
290 if (SuccCount == 1) {
291 MBB.replaceSuccessor(&Succ, &NewMBB);
293 MBB.splitSuccessor(&Succ, &NewMBB);
307 assert(OpMBB.
isMBB() &&
"Block operand to a PHI is not a block!");
312 if (SuccCount == 1) {
318 MI.addOperand(MF, OpV);
325 for (
auto &LI : Succ.
liveins())
345 for (
auto &
MI :
MBB) {
367 while (!DupIndices.
empty()) {
390 if (
MI.getOpcode() == X86::LFENCE)
398 if (
MI.getOpcode() == X86::MFENCE)
410bool X86SpeculativeLoadHardeningImpl::run(MachineFunction &MF) {
426 PS.emplace(MF, &X86::GR64_NOSPRegClass);
434 hardenEdgesWithLFENCE(MF);
442 auto EntryInsertPt =
Entry.SkipPHIsLabelsAndDebug(
Entry.begin());
452 if (!HasVulnerableLoad && Infos.
empty())
457 const int PoisonVal = -1;
458 PS->PoisonReg = MRI->createVirtualRegister(PS->RC);
459 BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::MOV64ri32), PS->PoisonReg)
472 BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::LFENCE));
474 ++NumLFENCEsInserted;
487 PS->InitialReg = extractPredStateFromSP(Entry, EntryInsertPt, Loc);
491 PS->InitialReg = MRI->createVirtualRegister(PS->RC);
492 Register PredStateSubReg = MRI->createVirtualRegister(&X86::GR32RegClass);
493 auto ZeroI =
BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::MOV32r0),
496 MachineOperand *ZeroEFLAGSDefOp =
497 ZeroI->findRegisterDefOperand(X86::EFLAGS,
nullptr);
499 "Must have an implicit def of EFLAGS!");
501 BuildMI(Entry, EntryInsertPt, Loc,
TII->get(X86::SUBREG_TO_REG),
514 PS->SSA.Initialize(PS->InitialReg);
515 PS->SSA.AddAvailableValue(&Entry, PS->InitialReg);
518 auto CMovs = tracePredStateThroughCFG(MF, Infos);
528 for (MachineBasicBlock &
MBB : MF) {
534 PS->SSA.AddAvailableValue(
543 unfoldCallAndJumpLoads(MF);
546 auto IndirectBrCMovs = tracePredStateThroughIndirectBranches(MF);
547 CMovs.append(IndirectBrCMovs.begin(), IndirectBrCMovs.end());
553 tracePredStateThroughBlocksAndHarden(MF);
557 for (MachineInstr *CMovI : CMovs)
558 for (MachineOperand &
Op : CMovI->operands()) {
559 if (!
Op.isReg() ||
Op.getReg() != PS->InitialReg)
562 PS->SSA.RewriteUse(
Op);
574void X86SpeculativeLoadHardeningImpl::hardenEdgesWithLFENCE(
575 MachineFunction &MF) {
578 SmallSetVector<MachineBasicBlock *, 8> Blocks;
579 for (MachineBasicBlock &
MBB : MF) {
587 if (TermIt ==
MBB.
end() || !TermIt->isBranch())
594 if (!SuccMBB->isEHPad())
598 for (MachineBasicBlock *
MBB : Blocks) {
602 ++NumLFENCEsInserted;
607X86SpeculativeLoadHardeningImpl::collectBlockCondInfo(MachineFunction &MF) {
612 for (MachineBasicBlock &
MBB : MF) {
637 BlockCondInfo
Info = {&
MBB, {},
nullptr};
643 if (!
MI.isTerminator())
647 if (!
MI.isBranch()) {
648 Info.CondBrs.clear();
654 if (
MI.getOpcode() == X86::JMP_1) {
655 Info.CondBrs.clear();
670 Info.CondBrs.clear();
676 Info.CondBrs.push_back(&
MI);
678 if (
Info.CondBrs.empty()) {
679 ++NumBranchesUntraced;
680 LLVM_DEBUG(
dbgs() <<
"WARNING: unable to secure successors of block:\n";
699X86SpeculativeLoadHardeningImpl::tracePredStateThroughCFG(
707 for (
const BlockCondInfo &Info : Infos) {
708 MachineBasicBlock &
MBB = *
Info.MBB;
709 const SmallVectorImpl<MachineInstr *> &CondBrs =
Info.CondBrs;
710 MachineInstr *UncondBr =
Info.UncondBr;
714 ++NumCondBranchesTraced;
718 MachineBasicBlock *UncondSucc =
719 UncondBr ? (UncondBr->
getOpcode() == X86::JMP_1
725 SmallDenseMap<MachineBasicBlock *, int> SuccCounts;
727 ++SuccCounts[UncondSucc];
728 for (
auto *CondBr : CondBrs)
729 ++SuccCounts[CondBr->getOperand(0).getMBB()];
733 auto BuildCheckingBlockForSuccAndConds =
734 [&](MachineBasicBlock &
MBB, MachineBasicBlock &Succ,
int SuccCount,
735 MachineInstr *Br, MachineInstr *&UncondBr,
740 (SuccCount == 1 && Succ.pred_size() == 1)
742 : splitEdge(MBB, Succ, SuccCount, Br, UncondBr, *TII);
744 bool LiveEFLAGS = Succ.isLiveIn(X86::EFLAGS);
746 CheckingMBB.addLiveIn(X86::EFLAGS);
749 auto InsertPt = CheckingMBB.begin();
750 assert((InsertPt == CheckingMBB.end() || !InsertPt->isPHI()) &&
751 "Should never have a PHI in the initial checking block as it "
752 "always has a single predecessor!");
756 Register CurStateReg = PS->InitialReg;
758 for (X86::CondCode Cond : Conds) {
759 int PredStateSizeInBytes = TRI->getRegSizeInBits(*PS->RC) / 8;
760 auto CMovOp = X86::getCMovOpcode(PredStateSizeInBytes);
762 Register UpdatedStateReg = MRI->createVirtualRegister(PS->RC);
765 auto CMovI = BuildMI(CheckingMBB, InsertPt, DebugLoc(),
766 TII->get(CMovOp), UpdatedStateReg)
768 .addReg(PS->PoisonReg)
772 if (!LiveEFLAGS && Cond == Conds.back())
773 CMovI->findRegisterUseOperand(X86::EFLAGS, nullptr)
777 LLVM_DEBUG(dbgs() <<
" Inserting cmov: "; CMovI->dump();
782 if (CurStateReg == PS->InitialReg)
783 CMovs.push_back(&*CMovI);
786 CurStateReg = UpdatedStateReg;
791 PS->SSA.AddAvailableValue(&CheckingMBB, CurStateReg);
794 std::vector<X86::CondCode> UncondCodeSeq;
795 for (
auto *CondBr : CondBrs) {
796 MachineBasicBlock &Succ = *CondBr->getOperand(0).getMBB();
797 int &SuccCount = SuccCounts[&Succ];
801 UncondCodeSeq.push_back(
Cond);
803 BuildCheckingBlockForSuccAndConds(
MBB, Succ, SuccCount, CondBr, UncondBr,
826 assert(SuccCounts[UncondSucc] == 1 &&
827 "We should never have more than one edge to the unconditional "
828 "successor at this point because every other edge must have been "
833 UncondCodeSeq.erase(
llvm::unique(UncondCodeSeq), UncondCodeSeq.end());
836 BuildCheckingBlockForSuccAndConds(
MBB, *UncondSucc, 1,
837 UncondBr, UncondBr, UncondCodeSeq);
848static const TargetRegisterClass *
851 unsigned UnfoldedOpc =
TII.getOpcodeAfterMemoryUnfold(
852 Opcode,
true,
false, &Index);
854 return TII.getRegClass(
MCID, Index);
857void X86SpeculativeLoadHardeningImpl::unfoldCallAndJumpLoads(
858 MachineFunction &MF) {
859 for (MachineBasicBlock &
MBB : MF)
864 if (!
MI.isCall() && !
MI.isBranch())
870 switch (
MI.getOpcode()) {
873 dbgs() <<
"ERROR: Found an unexpected loading branch or call "
879 case X86::FARCALL16m:
880 case X86::FARCALL32m:
881 case X86::FARCALL64m:
890 case X86::CALL16m_NT:
892 case X86::CALL32m_NT:
894 case X86::CALL64m_NT:
901 case X86::TAILJMPm64:
902 case X86::TAILJMPm64_REX:
904 case X86::TCRETURNmi64:
905 case X86::TCRETURN_WINmi64:
906 case X86::TCRETURNmi: {
913 <<
"ERROR: Unable to unfold load from instruction:\n";
917 Register Reg = MRI->createVirtualRegister(UnfoldedRC);
918 SmallVector<MachineInstr *, 2> NewMIs;
922 TII->unfoldMemoryOperand(MF,
MI,
Reg,
true,
926 "Computed unfolded register class but failed to unfold");
928 for (
auto *NewMI : NewMIs)
932 if (
MI.isCandidateForAdditionalCallInfo())
933 MF.eraseAdditionalCallInfo(&
MI);
935 MI.eraseFromParent();
937 dbgs() <<
"Unfolded load successfully into:\n";
938 for (
auto *NewMI : NewMIs) {
968X86SpeculativeLoadHardeningImpl::tracePredStateThroughIndirectBranches(
969 MachineFunction &MF) {
974 MachineSSAUpdater TargetAddrSSA(MF);
975 TargetAddrSSA.Initialize(MRI->createVirtualRegister(&X86::GR64RegClass));
978 SmallPtrSet<MachineBasicBlock *, 4> IndirectTerminatedMBBs;
983 SmallPtrSet<MachineBasicBlock *, 4> IndirectTargetMBBs;
987 for (MachineBasicBlock &
MBB : MF) {
994 MachineInstr &TI = *MII;
1006 case X86::FARJMP16m:
1007 case X86::FARJMP32m:
1008 case X86::FARJMP64m:
1014 case X86::JMP16m_NT:
1016 case X86::JMP32m_NT:
1018 case X86::JMP64m_NT:
1024 "Support for 16-bit indirect branches is not implemented.");
1027 "Support for 32-bit indirect branches is not implemented.");
1036 return !OtherTI.isDebugInstr() && &OtherTI != &TI;
1039 dbgs() <<
"ERROR: Found other terminators in a block with an indirect "
1040 "branch! This is not yet supported! Terminator sequence:\n";
1050 TargetAddrSSA.AddAvailableValue(&
MBB, TargetReg);
1061 if (IndirectTargetMBBs.
empty())
1067 for (MachineBasicBlock &
MBB : MF) {
1069 if (!IndirectTargetMBBs.
count(&
MBB))
1076 "Unexpected EH pad as target of an indirect branch!");
1084 "Cannot check within a block that already has live-in EFLAGS!");
1091 if (IndirectTerminatedMBBs.
count(Pred))
1099 if (!
llvm::all_of(Pred->successors(), [&](MachineBasicBlock *Succ) {
1100 return Succ->isEHPad() || Succ == &MBB;
1103 dbgs() <<
"ERROR: Found conditional entry to target of indirect "
1109 "an indirect branch!");
1115 auto InsertPt = Pred->getFirstTerminator();
1116 Register TargetReg = MRI->createVirtualRegister(&X86::GR64RegClass);
1121 TII->get(X86::MOV64ri32), TargetReg)
1141 TargetAddrSSA.AddAvailableValue(Pred, TargetReg);
1149 Register TargetReg = TargetAddrSSA.GetValueInMiddleOfBlock(&
MBB);
1160 .
addReg(TargetReg, RegState::Kill)
1167 Register AddrReg = MRI->createVirtualRegister(&X86::GR64RegClass);
1179 .
addReg(TargetReg, RegState::Kill)
1180 .
addReg(AddrReg, RegState::Kill);
1187 int PredStateSizeInBytes =
TRI->getRegSizeInBits(*PS->RC) / 8;
1189 Register UpdatedStateReg = MRI->createVirtualRegister(PS->RC);
1203 PS->SSA.AddAvailableValue(&
MBB, UpdatedStateReg);
1214 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr)) {
1215 return !DefOp->isDead();
1226 MI.findRegisterDefOperand(X86::EFLAGS,
nullptr)) {
1228 if (DefOp->isDead())
1236 if (
MI.killsRegister(X86::EFLAGS, &
TRI))
1242 return MBB.isLiveIn(X86::EFLAGS);
1272void X86SpeculativeLoadHardeningImpl::tracePredStateThroughBlocksAndHarden(
1273 MachineFunction &MF) {
1274 SmallPtrSet<MachineInstr *, 16> HardenPostLoad;
1275 SmallPtrSet<MachineInstr *, 16> HardenLoadAddr;
1277 SmallSet<Register, 16> HardenedAddrRegs;
1279 SmallDenseMap<Register, Register, 32> AddrRegToHardenedReg;
1284 SparseBitVector<> LoadDepRegs;
1286 for (MachineBasicBlock &
MBB : MF) {
1303 for (MachineInstr &
MI :
MBB) {
1309 return Op.isReg() && LoadDepRegs.test(Op.getReg().id());
1311 for (MachineOperand &Def :
MI.defs())
1313 LoadDepRegs.
set(
Def.getReg().id());
1318 if (
MI.getOpcode() == X86::LFENCE)
1326 if (
MI.getOpcode() == X86::MFENCE)
1331 if (MemRefBeginIdx < 0) {
1333 <<
"WARNING: unable to harden loading instruction: ";
1338 MachineOperand &BaseMO =
1340 MachineOperand &IndexMO =
1346 if (!BaseMO.
isFI() && BaseMO.
getReg() != X86::RIP &&
1350 IndexReg = IndexMO.
getReg();
1352 if (!BaseReg && !IndexReg)
1360 if ((BaseReg && LoadDepRegs.
test(
BaseReg.id())) ||
1361 (IndexReg && LoadDepRegs.
test(IndexReg.
id())))
1371 MI.getOperand(0).isReg() &&
1372 canHardenRegister(
MI.getOperand(0).getReg()) &&
1373 !HardenedAddrRegs.
count(BaseReg) &&
1374 !HardenedAddrRegs.
count(IndexReg)) {
1376 HardenedAddrRegs.
insert(
MI.getOperand(0).getReg());
1384 HardenedAddrRegs.
insert(BaseReg);
1386 HardenedAddrRegs.
insert(IndexReg);
1388 for (MachineOperand &Def :
MI.defs())
1390 LoadDepRegs.
set(
Def.getReg().id());
1398 for (MachineInstr &
MI :
MBB) {
1402 "Requested to harden both the address and def of a load!");
1405 if (HardenLoadAddr.
erase(&
MI)) {
1407 assert(MemRefBeginIdx >= 0 &&
"Cannot have an invalid index here!");
1409 MachineOperand &BaseMO =
1411 MachineOperand &IndexMO =
1413 hardenLoadAddr(
MI, BaseMO, IndexMO, AddrRegToHardenedReg);
1419 if (HardenPostLoad.
erase(&
MI)) {
1420 assert(!
MI.isCall() &&
"Must not try to post-load harden a call!");
1428 MachineInstr *SunkMI = sinkPostLoadHardenedInst(
MI, HardenPostLoad);
1433 if (SunkMI != &
MI) {
1440 HardenPostLoad.
insert(SunkMI);
1448 AddrRegToHardenedReg[HardenedReg] = HardenedReg;
1459 hardenIndirectCallOrJumpInstr(
MI, AddrRegToHardenedReg);
1466 if (!
MI.isCall() && !
MI.isReturn())
1471 if (
MI.isReturn() && !
MI.isCall()) {
1472 hardenReturnInstr(
MI);
1479 assert(
MI.isCall() &&
"Should only reach here for calls!");
1480 tracePredStateThroughCall(
MI);
1483 HardenPostLoad.
clear();
1484 HardenLoadAddr.
clear();
1485 HardenedAddrRegs.
clear();
1486 AddrRegToHardenedReg.
clear();
1491 LoadDepRegs.
clear();
1501Register X86SpeculativeLoadHardeningImpl::saveEFLAGS(
1506 Register Reg = MRI->createVirtualRegister(&X86::GR32RegClass);
1519void X86SpeculativeLoadHardeningImpl::restoreEFLAGS(
1530void X86SpeculativeLoadHardeningImpl::mergePredStateIntoSP(
1533 Register TmpReg = MRI->createVirtualRegister(PS->RC);
1537 auto ShiftI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::SHL64ri), TmpReg)
1538 .
addReg(PredStateReg, RegState::Kill)
1542 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::OR64rr), X86::RSP)
1544 .
addReg(TmpReg, RegState::Kill);
1550Register X86SpeculativeLoadHardeningImpl::extractPredStateFromSP(
1553 Register PredStateReg = MRI->createVirtualRegister(PS->RC);
1554 Register TmpReg = MRI->createVirtualRegister(PS->RC);
1559 BuildMI(
MBB, InsertPt, Loc,
TII->get(TargetOpcode::COPY), TmpReg)
1562 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::SAR64ri), PredStateReg)
1563 .
addReg(TmpReg, RegState::Kill)
1564 .
addImm(
TRI->getRegSizeInBits(*PS->RC) - 1);
1568 return PredStateReg;
1571void X86SpeculativeLoadHardeningImpl::hardenLoadAddr(
1572 MachineInstr &
MI, MachineOperand &BaseMO, MachineOperand &IndexMO,
1573 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg) {
1574 MachineBasicBlock &
MBB = *
MI.getParent();
1583 if (BaseMO.
isFI()) {
1587 dbgs() <<
" Skipping hardening base of explicit stack frame load: ";
1589 }
else if (BaseMO.
getReg() == X86::RSP) {
1594 "Explicit RSP access with dynamic index!");
1596 dbgs() <<
" Cannot harden base of explicit RSP offset in a load!");
1597 }
else if (BaseMO.
getReg() == X86::RIP ||
1598 BaseMO.
getReg() == X86::NoRegister) {
1608 dbgs() <<
" Cannot harden base of "
1609 << (BaseMO.
getReg() == X86::RIP ?
"RIP-relative" :
"no-base")
1610 <<
" address in a load!");
1613 "Only allowed to have a frame index or register base.");
1617 if (IndexMO.
getReg() != X86::NoRegister &&
1618 (HardenOpRegs.
empty() ||
1619 HardenOpRegs.
front()->getReg() != IndexMO.
getReg()))
1623 "Should have exactly one or two registers to harden!");
1625 HardenOpRegs[0]->getReg() != HardenOpRegs[1]->getReg()) &&
1626 "Should not have two of the same registers!");
1631 auto It = AddrRegToHardenedReg.
find(
Op->getReg());
1632 if (It == AddrRegToHardenedReg.
end())
1637 Op->setReg(It->second);
1641 if (HardenOpRegs.
empty())
1645 Register StateReg = PS->SSA.GetValueAtEndOfBlock(&
MBB);
1647 auto InsertPt =
MI.getIterator();
1653 if (EFLAGSLive && !Subtarget->hasBMI2()) {
1655 FlagsReg = saveEFLAGS(
MBB, InsertPt, Loc);
1658 for (MachineOperand *
Op : HardenOpRegs) {
1660 auto *OpRC = MRI->getRegClass(OpReg);
1661 Register TmpReg = MRI->createVirtualRegister(OpRC);
1665 if (!Subtarget->hasVLX() && (OpRC->hasSuperClassEq(&X86::VR128RegClass) ||
1666 OpRC->hasSuperClassEq(&X86::VR256RegClass))) {
1667 assert(Subtarget->
hasAVX2() &&
"AVX2-specific register classes!");
1668 bool Is128Bit = OpRC->hasSuperClassEq(&X86::VR128RegClass);
1673 Register VStateReg = MRI->createVirtualRegister(&X86::VR128RegClass);
1675 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::VMOV64toPQIrr), VStateReg)
1682 Register VBStateReg = MRI->createVirtualRegister(OpRC);
1683 auto BroadcastI =
BuildMI(
MBB, InsertPt, Loc,
1684 TII->get(Is128Bit ? X86::VPBROADCASTQrr
1685 : X86::VPBROADCASTQYrr),
1690 LLVM_DEBUG(
dbgs() <<
" Inserting broadcast: "; BroadcastI->dump();
1696 TII->get(Is128Bit ? X86::VPORrr : X86::VPORYrr), TmpReg)
1702 }
else if (OpRC->hasSuperClassEq(&X86::VR128XRegClass) ||
1703 OpRC->hasSuperClassEq(&X86::VR256XRegClass) ||
1704 OpRC->hasSuperClassEq(&X86::VR512RegClass)) {
1705 assert(Subtarget->
hasAVX512() &&
"AVX512-specific register classes!");
1706 bool Is128Bit = OpRC->hasSuperClassEq(&X86::VR128XRegClass);
1707 bool Is256Bit = OpRC->hasSuperClassEq(&X86::VR256XRegClass);
1708 if (Is128Bit || Is256Bit)
1709 assert(Subtarget->hasVLX() &&
"AVX512VL-specific register classes!");
1712 Register VStateReg = MRI->createVirtualRegister(OpRC);
1713 unsigned BroadcastOp =
Is128Bit ? X86::VPBROADCASTQrZ128rr
1714 : Is256Bit ? X86::VPBROADCASTQrZ256rr
1715 : X86::VPBROADCASTQrZrr;
1717 BuildMI(
MBB, InsertPt, Loc,
TII->get(BroadcastOp), VStateReg)
1721 LLVM_DEBUG(
dbgs() <<
" Inserting broadcast: "; BroadcastI->dump();
1725 unsigned OrOp =
Is128Bit ? X86::VPORQZ128rr
1726 : Is256Bit ? X86::VPORQZ256rr : X86::VPORQZrr;
1727 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(OrOp), TmpReg)
1735 assert(OpRC->hasSuperClassEq(&X86::GR64RegClass) &&
1736 "Not a supported register class for address hardening!");
1740 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::OR64rr), TmpReg)
1750 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::SHRX64rr), TmpReg)
1762 "Should not have checked this register yet!");
1763 AddrRegToHardenedReg[
Op->getReg()] = TmpReg;
1765 ++NumAddrRegsHardened;
1770 restoreEFLAGS(
MBB, InsertPt, Loc, FlagsReg);
1773MachineInstr *X86SpeculativeLoadHardeningImpl::sinkPostLoadHardenedInst(
1774 MachineInstr &InitialMI, SmallPtrSetImpl<MachineInstr *> &HardenedInstrs) {
1776 "Cannot get here with a non-invariant load!");
1778 "Cannot get here with a data invariant load "
1779 "that interferes with EFLAGS!");
1782 auto SinkCheckToSingleUse =
1783 [&](MachineInstr &
MI) -> std::optional<MachineInstr *> {
1789 MachineInstr *SingleUseMI =
nullptr;
1790 for (MachineInstr &
UseMI : MRI->use_instructions(DefReg)) {
1799 "Data variant instruction being hardened!");
1806 assert(MemRefBeginIdx >= 0 &&
1807 "Should always have mem references here!");
1809 MachineOperand &BaseMO =
1811 MachineOperand &IndexMO =
1813 if ((BaseMO.
isReg() && BaseMO.
getReg() == DefReg) ||
1834 if (
UseMI.getDesc().getNumDefs() > 1)
1841 if (!canHardenRegister(UseDefReg))
1844 SingleUseMI = &
UseMI;
1849 return {SingleUseMI};
1852 MachineInstr *
MI = &InitialMI;
1853 while (std::optional<MachineInstr *> SingleUse = SinkCheckToSingleUse(*
MI)) {
1863bool X86SpeculativeLoadHardeningImpl::canHardenRegister(
Register Reg) {
1868 auto *RC = MRI->getRegClass(
Reg);
1869 int RegBytes =
TRI->getRegSizeInBits(*RC) / 8;
1874 unsigned RegIdx =
Log2_32(RegBytes);
1875 assert(RegIdx < 4 &&
"Unsupported register size");
1884 const TargetRegisterClass *NOREXRegClasses[] = {
1885 &X86::GR8_NOREXRegClass, &X86::GR16_NOREXRegClass,
1886 &X86::GR32_NOREXRegClass, &X86::GR64_NOREXRegClass};
1887 if (RC == NOREXRegClasses[RegIdx])
1890 const TargetRegisterClass *GPRRegClasses[] = {
1891 &X86::GR8RegClass, &X86::GR16RegClass, &X86::GR32RegClass,
1892 &X86::GR64RegClass};
1893 return RC->hasSuperClassEq(GPRRegClasses[RegIdx]);
1910Register X86SpeculativeLoadHardeningImpl::hardenValueInRegister(
1913 assert(canHardenRegister(
Reg) &&
"Cannot harden this register!");
1915 auto *RC = MRI->getRegClass(
Reg);
1916 int Bytes =
TRI->getRegSizeInBits(*RC) / 8;
1917 Register StateReg = PS->SSA.GetValueAtEndOfBlock(&
MBB);
1918 assert((Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8) &&
1919 "Unknown register size");
1923 unsigned SubRegImms[] = {X86::sub_8bit, X86::sub_16bit, X86::sub_32bit};
1924 unsigned SubRegImm = SubRegImms[
Log2_32(Bytes)];
1925 Register NarrowStateReg = MRI->createVirtualRegister(RC);
1926 BuildMI(
MBB, InsertPt, Loc,
TII->get(TargetOpcode::COPY), NarrowStateReg)
1927 .
addReg(StateReg, {}, SubRegImm);
1928 StateReg = NarrowStateReg;
1933 FlagsReg = saveEFLAGS(
MBB, InsertPt, Loc);
1935 Register NewReg = MRI->createVirtualRegister(RC);
1936 unsigned OrOpCodes[] = {X86::OR8rr, X86::OR16rr, X86::OR32rr, X86::OR64rr};
1937 unsigned OrOpCode = OrOpCodes[
Log2_32(Bytes)];
1938 auto OrI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(OrOpCode), NewReg)
1946 restoreEFLAGS(
MBB, InsertPt, Loc, FlagsReg);
1960Register X86SpeculativeLoadHardeningImpl::hardenPostLoad(MachineInstr &
MI) {
1961 MachineBasicBlock &
MBB = *
MI.getParent();
1964 auto &DefOp =
MI.getOperand(0);
1965 Register OldDefReg = DefOp.getReg();
1966 auto *DefRC = MRI->getRegClass(OldDefReg);
1971 Register UnhardenedReg = MRI->createVirtualRegister(DefRC);
1972 DefOp.setReg(UnhardenedReg);
1977 Register HardenedReg = hardenValueInRegister(
1978 UnhardenedReg,
MBB, std::next(
MI.getIterator()), Loc);
1982 MRI->replaceRegWith( OldDefReg, HardenedReg);
1984 ++NumPostLoadRegsHardened;
2011void X86SpeculativeLoadHardeningImpl::hardenReturnInstr(MachineInstr &
MI) {
2012 MachineBasicBlock &
MBB = *
MI.getParent();
2014 auto InsertPt =
MI.getIterator();
2024 mergePredStateIntoSP(
MBB, InsertPt, Loc, PS->SSA.GetValueAtEndOfBlock(&
MBB));
2057void X86SpeculativeLoadHardeningImpl::tracePredStateThroughCall(
2059 MachineBasicBlock &
MBB = *
MI.getParent();
2061 auto InsertPt =
MI.getIterator();
2074 BuildMI(
MBB, std::next(InsertPt), Loc,
TII->get(X86::LFENCE));
2076 ++NumLFENCEsInserted;
2082 Register StateReg = PS->SSA.GetValueAtEndOfBlock(&
MBB);
2083 mergePredStateIntoSP(
MBB, InsertPt, Loc, StateReg);
2098 MI.setPostInstrSymbol(MF, RetSymbol);
2100 const TargetRegisterClass *AddrRC = &X86::GR64RegClass;
2126 ExpectedRetAddrReg = MRI->createVirtualRegister(AddrRC);
2129 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::MOV64ri32), ExpectedRetAddrReg)
2132 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::LEA64r), ExpectedRetAddrReg)
2148 if (!ExpectedRetAddrReg) {
2149 ExpectedRetAddrReg = MRI->createVirtualRegister(AddrRC);
2150 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::MOV64rm), ExpectedRetAddrReg)
2160 Register NewStateReg = extractPredStateFromSP(
MBB, InsertPt, Loc);
2170 .
addReg(ExpectedRetAddrReg, RegState::Kill)
2173 Register ActualRetAddrReg = MRI->createVirtualRegister(AddrRC);
2174 BuildMI(
MBB, InsertPt, Loc,
TII->get(X86::LEA64r), ActualRetAddrReg)
2181 .
addReg(ExpectedRetAddrReg, RegState::Kill)
2182 .
addReg(ActualRetAddrReg, RegState::Kill);
2187 int PredStateSizeInBytes =
TRI->getRegSizeInBits(*PS->RC) / 8;
2190 Register UpdatedStateReg = MRI->createVirtualRegister(PS->RC);
2191 auto CMovI =
BuildMI(
MBB, InsertPt, Loc,
TII->get(CMovOp), UpdatedStateReg)
2192 .
addReg(NewStateReg, RegState::Kill)
2199 PS->SSA.AddAvailableValue(&
MBB, UpdatedStateReg);
2217void X86SpeculativeLoadHardeningImpl::hardenIndirectCallOrJumpInstr(
2219 SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg) {
2220 switch (
MI.getOpcode()) {
2221 case X86::FARCALL16m:
2222 case X86::FARCALL32m:
2223 case X86::FARCALL64m:
2224 case X86::FARJMP16m:
2225 case X86::FARJMP32m:
2226 case X86::FARJMP64m:
2237 assert(!
MI.mayLoad() &&
"Found a lingering loading instruction!");
2241 if (!
MI.getOperand(0).isReg())
2246 auto &TargetOp =
MI.getOperand(0);
2247 Register OldTargetReg = TargetOp.getReg();
2252 Register &HardenedTargetReg = AddrRegToHardenedReg[OldTargetReg];
2261 if (!HardenedTargetReg)
2262 HardenedTargetReg = hardenValueInRegister(
2263 OldTargetReg, *
MI.getParent(),
MI.getIterator(),
MI.getDebugLoc());
2266 TargetOp.setReg(HardenedTargetReg);
2268 ++NumCallsOrJumpsHardened;
2274 X86SpeculativeLoadHardeningImpl Impl;
2275 const bool Changed = Impl.run(MF);
2284 "X86 speculative load hardener",
false,
false)
2289 return new X86SpeculativeLoadHardeningLegacy();
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< bool > HardenLoads("aarch64-slh-loads", cl::Hidden, cl::desc("Sanitize loads from memory."), cl::init(true))
This file defines the DenseMap class.
const HexagonInstrInfo * TII
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register const TargetRegisterInfo * TRI
Promote Memory to Register
MachineInstr unsigned OpIdx
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the SparseBitVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static MachineBasicBlock & splitEdge(MachineBasicBlock &MBB, MachineBasicBlock &Succ, int SuccCount, MachineInstr *Br, MachineInstr *&UncondBr, const X86InstrInfo &TII)
static cl::opt< bool > HardenLoads(PASS_KEY "-loads", cl::desc("Sanitize loads from memory. When disable, no " "significant security is provided."), cl::init(true), cl::Hidden)
static void canonicalizePHIOperands(MachineFunction &MF)
Removing duplicate PHI operands to leave the PHI in a canonical and predictable form.
static cl::opt< bool > HardenInterprocedurally(PASS_KEY "-ip", cl::desc("Harden interprocedurally by passing our state in and out of " "functions in the high bits of the stack pointer."), cl::init(true), cl::Hidden)
static cl::opt< bool > FenceCallAndRet(PASS_KEY "-fence-call-and-ret", cl::desc("Use a full speculation fence to harden both call and ret edges " "rather than a lighter weight mitigation."), cl::init(false), cl::Hidden)
static cl::opt< bool > EnablePostLoadHardening(PASS_KEY "-post-load", cl::desc("Harden the value loaded *after* it is loaded by " "flushing the loaded bits to 1. This is hard to do " "in general but can be done easily for GPRs."), cl::init(true), cl::Hidden)
static cl::opt< bool > HardenEdgesWithLFENCE(PASS_KEY "-lfence", cl::desc("Use LFENCE along each conditional edge to harden against speculative " "loads rather than conditional movs and poisoned pointers."), cl::init(false), cl::Hidden)
static bool isEFLAGSLive(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const TargetRegisterInfo &TRI)
static cl::opt< bool > EnableSpeculativeLoadHardening("x86-speculative-load-hardening", cl::desc("Force enable speculative load hardening"), cl::init(false), cl::Hidden)
static const TargetRegisterClass * getRegClassForUnfoldedLoad(const X86InstrInfo &TII, unsigned Opcode)
Compute the register class for the unfolded load.
static bool hasVulnerableLoad(MachineFunction &MF)
Helper to scan a function for loads vulnerable to misspeculation that we want to harden.
static bool isEFLAGSDefLive(const MachineInstr &MI)
static cl::opt< bool > HardenIndirectCallsAndJumps(PASS_KEY "-indirect", cl::desc("Harden indirect calls and jumps against using speculatively " "stored attacker controlled addresses. This is designed to " "mitigate Spectre v1.2 style attacks."), cl::init(true), cl::Hidden)
Represents analyses that only rely on functions' control flow.
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
FunctionPass class - This class is used to implement most global optimizations.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Describe properties that are true of each instruction in the target description file.
void normalizeSuccProbs()
Normalize probabilities of all successors so that the sum of them becomes one.
bool isEHPad() const
Returns true if the block is a landing pad.
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
iterator_range< livein_iterator > liveins() const
reverse_instr_iterator instr_rbegin()
LLVM_ABI iterator SkipPHIsAndLabels(iterator I)
Return the first instruction in MBB after I that is not a PHI or a label.
LLVM_ABI iterator SkipPHIsLabelsAndDebug(iterator I, Register Reg=Register(), bool SkipPseudoOp=true)
Return the first instruction in MBB after I that is not a PHI, label or debug.
bool isEHFuncletEntry() const
Returns true if this is the entry block of an EH funclet.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned succ_size() const
LLVM_ABI void dump() const
bool isEHScopeEntry() const
Returns true if this is the entry block of an EH scope, i.e., the block that used to have a catchpad ...
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
reverse_instr_iterator instr_rend()
LLVM_ABI bool isLayoutSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB will be emitted immediately after this block, such that if this bloc...
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< iterator > terminators()
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
void setMachineBlockAddressTaken()
Set this block to indicate that its address is used as something other than the target of a terminato...
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
bool isCleanupFuncletEntry() const
Returns true if this is the entry block of a cleanup funclet.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
void dump() const
dump - Print the current MachineFunction to cerr, useful for debugger use.
bool exposesReturnsTwice() const
exposesReturnsTwice - Returns true if the function calls setjmp or any other similar functions with a...
MCContext & getContext() const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
bool verify(Pass *p=nullptr, const char *Banner=nullptr, raw_ostream *OS=nullptr, bool AbortOnError=true) const
Run the current MachineFunction through the machine code verifier, useful for debugger use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isTerminator(QueryType Type=AnyInBundle) const
Returns true if this instruction part of the terminator for a basic block.
bool isBranch(QueryType Type=AnyInBundle) const
Returns true if this is a conditional, unconditional, or indirect branch.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI bool addRegisterDead(Register Reg, const TargetRegisterInfo *RegInfo, bool AddIfNotFound=false)
We have determined MI defined a register without a use.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
void setIsDead(bool Val=true)
void setIsKill(bool Val=true)
void setMBB(MachineBasicBlock *MBB)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr unsigned id() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void insert_range(Range &&R)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool test(unsigned Idx) const
Represent a constant reference to a string, i.e.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool has128ByteRedZone(const MachineFunction &MF) const
Return true if the function has a redzone (accessible bytes past the frame of the top of stack functi...
static bool isDataInvariantLoad(MachineInstr &MI)
Returns true if the instruction has no behavior (specified or otherwise) that is based on the value l...
static bool isDataInvariant(MachineInstr &MI)
Returns true if the instruction has no behavior (specified or otherwise) that is based on the value o...
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const X86InstrInfo * getInstrInfo() const override
bool isPositionIndependent() const
const X86RegisterInfo * getRegisterInfo() const override
const X86FrameLowering * getFrameLowering() const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
CondCode getCondFromBranch(const MachineInstr &MI)
int getFirstAddrOperandIdx(const MachineInstr &MI)
Return the index of the instruction's first address operand, if it has a memory reference,...
CondCode GetOppositeBranchCondition(CondCode CC)
GetOppositeBranchCondition - Return the inverse of the specified cond, e.g.
unsigned getCMovOpcode(unsigned RegBytes, bool HasMemoryOperand=false, bool HasNDD=false)
Return a cmov opcode for the given register size in bytes, and operand type.
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
NodeAddr< DefNode * > Def
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
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...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
auto unique(Range &&R, Predicate P)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionPass * createX86SpeculativeLoadHardeningLegacyPass()
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...