Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -14825,6 +14825,53 @@ This intrinsic actually does nothing, but optimizers must assume that it has externally observable side effects. + +'``llvm.speculation_safe_value``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use llvm.speculation_safe_value on any +integer type, and any pointer type. However, not all targets support this +intrinsic at the moment. + +:: + + declare T @llvm.speculation_safe_value.T(T %val) + +Overview: +""""""""" + +The '``llvm.speculation_safe_value``' intrinsic. + +Arguments: +"""""""""" + +The first argument is a pointer or integer value. + + +Semantics: +"""""""""" + +On a processor that predicts the direction and target of branches, code executes +speculatively, i.e. before it is known if the code actually should be executed +according to program logic. + +When the processor executes code speculatively that it should not execute +according to program logic, the code is said to be executing on a +miss-speculated path. Miss-speculated paths are caused by incorrect prediction +of the direction or targets of branches. + +This intrinsic guarantees that for miss-speculated paths where at least the +direction of one of the previously executed conditional branches was +mispredicted, the intrinsic returns 0. + +On fully correctly predicted execution paths, it returns %val. + +For paths not covered by the above statements, it returns either 0 or %val. + + Stack Map Intrinsics -------------------- Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -824,6 +824,8 @@ /// FMIN/FMAX nodes can have flags, for NaN/NoNaN variants. VECREDUCE_FMAX, VECREDUCE_FMIN, + SPECULATION_SAFE_VALUE, + /// BUILTIN_OP_END - This must be the last enum value in this list. /// The target-specific pre-isel opcode values start here. BUILTIN_OP_END Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -983,6 +983,11 @@ def int_ssa_copy : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], [IntrNoMem, Returned<0>]>; + +//===----- Intrinsics to mitigate against miss-speculation exploits -------===// + +def int_speculationsafevalue : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], []>; + //===----------------------------------------------------------------------===// // Target-specific intrinsics //===----------------------------------------------------------------------===// Index: include/llvm/Target/TargetSelectionDAG.td =================================================================== --- include/llvm/Target/TargetSelectionDAG.td +++ include/llvm/Target/TargetSelectionDAG.td @@ -280,6 +280,10 @@ SDTCisVT<2, OtherVT>, SDTCisVT<3, OtherVT>, SDTCisPtrTy<4>, SDTCisPtrTy<5> ]>; +def SDTSpeculationSafe: SDTypeProfile<1, 1, [ + SDTCisInt<1>, SDTCisSameAs<1, 0> +]>; + class SDCallSeqStart constraints> : SDTypeProfile<0, 2, constraints>; class SDCallSeqEnd constraints> : @@ -564,6 +568,8 @@ def assertsext : SDNode<"ISD::AssertSext", SDT_assertext>; def assertzext : SDNode<"ISD::AssertZext", SDT_assertext>; +def speculationsafevalue : SDNode<"ISD::SPECULATION_SAFE_VALUE", + SDTSpeculationSafe, []>; //===----------------------------------------------------------------------===// // Selection DAG Condition Codes Index: lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -162,6 +162,9 @@ case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: Res = PromoteIntRes_AtomicCmpSwap(cast(N), ResNo); break; + case ISD::SPECULATION_SAFE_VALUE: + Res = PromoteIntRes_SpeculationSafeValue(N); + break; } // If the result is null then the sub-method took care of registering it. @@ -642,6 +645,13 @@ LHS.getValueType(), LHS, RHS); } +SDValue DAGTypeLegalizer::PromoteIntRes_SpeculationSafeValue(SDNode *N) { + // Propagate size promotion through the intrinsic. + SDValue Op = GetPromotedInteger(N->getOperand(0)); + return DAG.getNode(N->getOpcode(), SDLoc(N), + Op.getValueType(), Op); +} + SDValue DAGTypeLegalizer::PromoteIntRes_SExtIntBinOp(SDNode *N) { // Sign extend the input. SDValue LHS = SExtPromotedInteger(N->getOperand(0)); @@ -1475,6 +1485,9 @@ case ISD::USUBO: ExpandIntRes_UADDSUBO(N, Lo, Hi); break; case ISD::UMULO: case ISD::SMULO: ExpandIntRes_XMULO(N, Lo, Hi); break; + + case ISD::SPECULATION_SAFE_VALUE: + ExpandIntRes_SPECULATION_SAFE_VALUE(N, Lo, Hi); break; } // If Lo/Hi is null, the sub-method took care of registering results etc. @@ -2160,6 +2173,15 @@ Hi = DAG.getConstant(0, dl, NVT); } +void DAGTypeLegalizer::ExpandIntRes_SPECULATION_SAFE_VALUE(SDNode *N, + SDValue &Lo, + SDValue &Hi) { + SDLoc dl(N); + GetExpandedInteger(N->getOperand(0), Lo, Hi); + Lo = DAG.getNode(N->getOpcode(), dl, Lo.getValueType(), Lo); + Hi = DAG.getNode(N->getOpcode(), dl, Hi.getValueType(), Hi); +} + void DAGTypeLegalizer::ExpandIntRes_CTTZ(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); Index: lib/CodeGen/SelectionDAG/LegalizeTypes.h =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -330,6 +330,7 @@ SDValue PromoteIntRes_UNDEF(SDNode *N); SDValue PromoteIntRes_VAARG(SDNode *N); SDValue PromoteIntRes_XMULO(SDNode *N, unsigned ResNo); + SDValue PromoteIntRes_SpeculationSafeValue(SDNode *N); // Integer Operand Promotion. bool PromoteIntegerOperand(SDNode *N, unsigned OperandNo); @@ -414,6 +415,7 @@ void ExpandIntRes_SADDSUBO (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_UADDSUBO (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_XMULO (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandIntRes_SPECULATION_SAFE_VALUE(SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_ATOMIC_LOAD (SDNode *N, SDValue &Lo, SDValue &Hi); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5659,6 +5659,12 @@ setValue(&I, DAG.getNode(ISD::CTPOP, sdl, Ty, Arg)); return nullptr; } + case Intrinsic::speculationsafevalue: { + SDValue Arg = getValue(I.getArgOperand(0)); + EVT Ty = Arg.getValueType(); + setValue(&I, DAG.getNode(ISD::SPECULATION_SAFE_VALUE, sdl, Ty, Arg)); + return nullptr; + } case Intrinsic::stacksave: { SDValue Op = getRoot(); Res = DAG.getNode( Index: lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -79,6 +79,7 @@ #ifndef NDEBUG case ISD::DELETED_NODE: return "<>"; #endif + case ISD::SPECULATION_SAFE_VALUE: return "SpeculationSafeValue"; case ISD::PREFETCH: return "Prefetch"; case ISD::ATOMIC_FENCE: return "AtomicFence"; case ISD::ATOMIC_CMP_SWAP: return "AtomicCmpSwap"; Index: lib/Target/AArch64/AArch64ISelLowering.h =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.h +++ lib/Target/AArch64/AArch64ISelLowering.h @@ -191,6 +191,9 @@ FRECPE, FRECPS, FRSQRTE, FRSQRTS, + // control flow miss-speculation protection + SpeculationSafeValue, + // NEON Load/Store with post-increment base updates LD2post = ISD::FIRST_TARGET_MEMORY_OPCODE, LD3post, @@ -623,6 +626,7 @@ SDValue LowerWindowsDYNAMIC_STACKALLOC(SDValue Op, SDValue Chain, SDValue &Size, SelectionDAG &DAG) const; + SDValue LowerSPECULATION_SAFE_VALUE(SDValue Op, SelectionDAG &DAG) const; SDValue BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG, std::vector *Created) const override; Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -543,6 +543,9 @@ // Trap. setOperationAction(ISD::TRAP, MVT::Other, Legal); + setOperationAction(ISD::SPECULATION_SAFE_VALUE, MVT::i32, Custom); + setOperationAction(ISD::SPECULATION_SAFE_VALUE, MVT::i64, Custom); + // We combine OR nodes for bitfield operations. setTargetDAGCombine(ISD::OR); @@ -1206,6 +1209,8 @@ case AArch64ISD::FRECPS: return "AArch64ISD::FRECPS"; case AArch64ISD::FRSQRTE: return "AArch64ISD::FRSQRTE"; case AArch64ISD::FRSQRTS: return "AArch64ISD::FRSQRTS"; + case AArch64ISD::SpeculationSafeValue: + return "AArch64ISD::SpeculationSafeValue"; } return nullptr; } @@ -2175,6 +2180,17 @@ DAG.getConstant(PrfOp, DL, MVT::i32), Op.getOperand(1)); } +SDValue +AArch64TargetLowering::LowerSPECULATION_SAFE_VALUE(SDValue Op, + SelectionDAG &DAG) const { + assert((Op.getValueType() == MVT::i32 || Op.getValueType() == MVT::i64) && + "Unexpected lowering"); + + SDLoc DL(Op); + return DAG.getNode(AArch64ISD::SpeculationSafeValue, DL, Op.getValueType(), + Op.getOperand(0)); +} + SDValue AArch64TargetLowering::LowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const { assert(Op.getValueType() == MVT::f128 && "Unexpected lowering"); @@ -2798,6 +2814,8 @@ return LowerATOMIC_LOAD_AND(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); + case ISD::SPECULATION_SAFE_VALUE: + return LowerSPECULATION_SAFE_VALUE(Op, DAG); } } Index: lib/Target/AArch64/AArch64InstrInfo.h =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.h +++ lib/Target/AArch64/AArch64InstrInfo.h @@ -264,6 +264,10 @@ /// executed in one cycle less. bool isFalkorShiftExtFast(const MachineInstr &MI) const; + bool isSchedulingBoundary(const MachineInstr &MI, + const MachineBasicBlock *MBB, + const MachineFunction &MF) const override; + private: /// Sets the offsets on outlined instructions in \p MBB which use SP /// so that they will be valid post-outlining. Index: lib/Target/AArch64/AArch64InstrInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.cpp +++ lib/Target/AArch64/AArch64InstrInfo.cpp @@ -5449,3 +5449,22 @@ return CallPt; } + +bool AArch64InstrInfo::isSchedulingBoundary(const MachineInstr &MI, + const MachineBasicBlock *MBB, + const MachineFunction &MF) const { + if (AArch64GenInstrInfo::isSchedulingBoundary(MI, MBB, MF)) + return true; + + switch (MI.getOpcode()) { + case AArch64::HINT: + // CSDB hints are scheduling barriers. + if (MI.getOperand(0).getImm() == 0x14) + return true; + break; + default: + ; + } + + return false; +} Index: lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.td +++ lib/Target/AArch64/AArch64InstrInfo.td @@ -318,6 +318,8 @@ def AArch64uminv : SDNode<"AArch64ISD::UMINV", SDT_AArch64UnaryVec>; def AArch64smaxv : SDNode<"AArch64ISD::SMAXV", SDT_AArch64UnaryVec>; def AArch64umaxv : SDNode<"AArch64ISD::UMAXV", SDT_AArch64UnaryVec>; +def AArch64SpeculationSafeValue : SDNode<"AArch64ISD::SpeculationSafeValue", + SDTIntUnaryOp>; //===----------------------------------------------------------------------===// @@ -1391,6 +1393,17 @@ def : Pat<(AArch64tlsdesc_callseq texternalsym:$sym), (TLSDESC_CALLSEQ texternalsym:$sym)>; +let hasSideEffects = 1, isCodeGenOnly = 1 in { + def SpeculationSafeValueX + : Pseudo<(outs GPR64:$dst), (ins GPR64:$src), + [(set GPR64:$dst, (AArch64SpeculationSafeValue GPR64:$src))]>, + Sched<[]>; + def SpeculationSafeValueW + : Pseudo<(outs GPR32:$dst), (ins GPR32:$src), + [(set GPR32:$dst, (AArch64SpeculationSafeValue GPR32:$src))]>, + Sched<[]>; +} + //===----------------------------------------------------------------------===// // Conditional branch (immediate) instruction. //===----------------------------------------------------------------------===// Index: lib/Target/AArch64/AArch64SpeculationHardening.cpp =================================================================== --- lib/Target/AArch64/AArch64SpeculationHardening.cpp +++ lib/Target/AArch64/AArch64SpeculationHardening.cpp @@ -56,6 +56,8 @@ class AArch64SpeculationHardening : public MachineFunctionPass { public: const AArch64InstrInfo *TII; + MachineRegisterInfo *MRI; + const TargetRegisterInfo *TRI; static char ID; @@ -72,8 +74,14 @@ private: unsigned MisspeculatingTaintVR; unsigned MisspeculatingTaintVR32Bit; + BitVector RegsNeedingBarrierBeforeUse; bool instrumentCFST(MachineBasicBlock &MBB); + bool lowerSpeculationSafeValuePseudo(MachineBasicBlock &MBB); + bool expandSpeculationSafeValue(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI); + bool insertSpeculationBarrier(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc DL); bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, AArch64CC::CondCode &Cond) const; bool endsWithCondControlFlow(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, @@ -303,15 +311,118 @@ .addImm(0); // no shift } +/// \brief If MBBI references a pseudo instruction that should be expanded here, +/// do the expansion and return true. Otherwise return false. +bool AArch64SpeculationHardening::expandSpeculationSafeValue( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + bool Is64Bit = true; + switch (Opcode) { + default: + break; + case AArch64::SpeculationSafeValueW: + Is64Bit = false; + LLVM_FALLTHROUGH; + case AArch64::SpeculationSafeValueX: + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SrcReg = MI.getOperand(1).getReg(); + for (MachineOperand Op : MI.defs()) { + assert(Op.isReg()); + // Mark this register and all its super-registers as needing to be + // value speculation protected before its next use, by using a CSDB + // barrier instruction. + TRI->markSuperRegs(RegsNeedingBarrierBeforeUse, Op.getReg()); + } + + assert(EnableSpeculationTracking); + // mask off with CFST state + BuildMI(MBB, MBBI, MI.getDebugLoc(), + Is64Bit ? TII->get(AArch64::ANDXrs) : TII->get(AArch64::ANDWrs)) + .addDef(DstReg) + .addUse(SrcReg, RegState::Kill) + .addUse(Is64Bit ? MisspeculatingTaintVR : MisspeculatingTaintVR32Bit) + .addImm(0); + MI.eraseFromParent(); + return true; + } + return false; +} + +bool AArch64SpeculationHardening::insertSpeculationBarrier( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL) { + assert(EnableSpeculationTracking && "Speculation tracking must be enabled " + "when inserting speculation barriers"); + // insert data value speculation barrier (CSDB) + BuildMI(MBB, MBBI, DL, TII->get(AArch64::HINT)).addImm(0x14); + RegsNeedingBarrierBeforeUse.reset(); + return true; +} + +bool AArch64SpeculationHardening::lowerSpeculationSafeValuePseudo( + MachineBasicBlock &MBB) { + bool Modified = false; + + RegsNeedingBarrierBeforeUse.reset(); + + // The following loop iterates over all instructions in the basic block, and + // performs 2 operations: + // 1. Insert a CSDB at this location if needed. + // 2. Insert a masking instruction (AND) with the CFST to lower the + // ValueSpeculationSafe pseudo instruction. + // + // The insertion of the CSDB is done as late as possible (i.e. just before + // the use of a masked register), in the hope that that will reduce the total + // number of CSDBs in a block when there are multiple masked registers in the + // block. + MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); + DebugLoc DL; + while (MBBI != E) { + MachineInstr &MI = *MBBI; + DL = MI.getDebugLoc(); + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + + // First check if a barrier needs to be inserted due to earlier registers + // that were masked and that are used by the next instruction. + // Also emit the barrier on any potential control flow changes. + bool NeedToEmitBarrier = false; + if (RegsNeedingBarrierBeforeUse.any() && (MI.isCall() || MI.isTerminator())) + NeedToEmitBarrier = true; + if (!NeedToEmitBarrier) + for (MachineOperand Op : MI.uses()) { + if (Op.isReg() && RegsNeedingBarrierBeforeUse[Op.getReg()]) { + NeedToEmitBarrier = true; + break; + } + } + + if (NeedToEmitBarrier) + Modified |= insertSpeculationBarrier(MBB, MBBI, DL); + + Modified |= expandSpeculationSafeValue(MBB, MBBI); + + MBBI = NMBBI; + } + + if (RegsNeedingBarrierBeforeUse.any()) + Modified |= insertSpeculationBarrier(MBB, MBBI, DL); + + return Modified; +} + bool AArch64SpeculationHardening::runOnMachineFunction(MachineFunction &MF) { TII = static_cast(MF.getSubtarget().getInstrInfo()); + MRI = &MF.getRegInfo(); + TRI = MF.getSubtarget().getRegisterInfo(); + + RegsNeedingBarrierBeforeUse.resize(TRI->getNumRegs()); bool Modified = false; MisspeculatingTaintVR = AArch64::X16; MisspeculatingTaintVR32Bit = AArch64::W16; - // Instrument control flow speculation tracking, if requested. + // Step 2: instrument control flow speculation tracking, if requested. LLVM_DEBUG( dbgs() << "***** AArch64SpeculationHardening - track control flow *****\n"); @@ -331,6 +442,14 @@ Modified |= instrumentCFST(MBB); } + LLVM_DEBUG( + dbgs() + << "***** AArch64SpeculationHardening - Lowering SpeculationSafeValue " + "Pseudos *****\n"); + // Step 3: Lower SpeculationSafeValue pseudo instructions. + for (auto &MBB : MF) + Modified |= lowerSpeculationSafeValuePseudo(MBB); + return Modified; } Index: test/CodeGen/AArch64/speculation-hardening.ll =================================================================== --- test/CodeGen/AArch64/speculation-hardening.ll +++ test/CodeGen/AArch64/speculation-hardening.ll @@ -1,5 +1,9 @@ ; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -aarch64-track-speculation | FileCheck %s --check-prefix=CFST +declare i8 @llvm.speculationsafevalue.i8(i8) +declare i96 @llvm.speculationsafevalue.i96(i96) +declare i8* @llvm.speculationsafevalue.p0(i8*) + declare void @function_without_arguments() define i32 @f(i8* nocapture readonly %p, i32 %i, i32 %N) local_unnamed_addr { @@ -23,8 +27,11 @@ %idxprom = sext i32 %i to i64 %arrayidx = getelementptr inbounds i8, i8* %p, i64 %idxprom %0 = load i8, i8* %arrayidx, align 1 + %1 = tail call i8 @llvm.speculationsafevalue.i8(i8 %0) ; CFST: ldrb [[LOADED:w[0-9]+]], - %conv = zext i8 %0 to i32 +; CFST: and [[DST:w[0-9]+]], [[LOADED]], w16 +; CFST-NEXT: csdb + %conv = zext i8 %1 to i32 br label %return ; CFST: csel x16, x16, xzr, ge @@ -36,6 +43,86 @@ ret i32 %retval.0 } +define i64 @nonpow2_narrowing(i128* %p) { +; CFST-LABEL: nonpow2_narrowing: + %a = load i128, i128* %p +; CFST: ldp [[SRC1:x[0-9]+]], [[SRC2:x[0-9]+]], [x0] + %b = trunc i128 %a to i96 + %c = tail call i96 @llvm.speculationsafevalue.i96(i96 %b) +; CFST: and [[SRC1]], [[SRC1]], x16 +; CFST-NOT: csdb +; CFST: and [[SRC2]], [[SRC2]], x16 +; CFST-NEXT: csdb +; CFST: add x0, + %lo = trunc i96 %c to i64 + %hi96 = lshr i96 %c, 64 + %hi = trunc i96 %hi96 to i64 + %d = add i64 %lo, %hi + ret i64 %d +} + +define i8* @ptr(i8* %p) { +; CFST-LABEL: ptr: + %a = tail call i8* @llvm.speculationsafevalue.p0(i8* %p) +; CFST: and x0, x0, x16 +; CFST: csdb +; CFST: ret + ret i8* %a +} + +define i8* @csdb_before_call(i8* %p) { +; CFST-LABEL: csdb_before_call: + %a = tail call i8* @llvm.speculationsafevalue.p0(i8* %p) + call void @function_without_arguments() + ret i8* %a +; CFST: and [[DST:x[0-9]+]], x0, x16 +; CFST: csdb +; CFST: bl function_without_arguments +; CFST: ret +} + +define i8* @csdb_on_unused_in_bb_with_terminator(i8* %p, i32 %v1, i32 %v2) { +; CFST-LABEL: csdb_on_unused_in_bb_with_terminator: +entry: + %a = tail call i8* @llvm.speculationsafevalue.p0(i8* %p) + %cmp = icmp slt i32 %v1, %v2 + br i1 %cmp, label %if.then, label %return +; CFST: and [[DST:x[0-9]+]], x0, x16 +; CFST: csdb +; CFST: b.ge +; CFST-NOT: csdb +if.then: + %tmp1 = sdiv i32 %v1, %v2 + %b = getelementptr i8, i8* %a, i32 %tmp1 + br label %return + +return: + %c = phi i8* [ %a, %entry ] , [ %b, %if.then ] + ret i8* %c +; CFST: ret +} + +define i8* @csdb_on_unused_in_bb_without_terminator(i8* %p, i32 %v1, i32 %v2) { +; CFST-LABEL: csdb_on_unused_in_bb_without_terminator: +entry: + %cmp = icmp slt i32 %v1, %v2 + br i1 %cmp, label %if.then, label %return +; CFST: b.ge +if.then: + %tmp1 = sdiv i32 %v1, %v2 + %b1 = getelementptr i8, i8* %p, i32 %tmp1 + %b = tail call i8* @llvm.speculationsafevalue.p0(i8* %b1) + br label %return +; CFST: and [[DST:x[0-9]+]], [[SRC:x[0-9]+]], x16 +; CFST: csdb +; CFST-NOT: csdb +; CFST: ret + +return: + %c = phi i8* [ %p, %entry ] , [ %b, %if.then ] + ret i8* %c +} + ; Make sure that for a tail call, taint doesn't get put into SP twice. define i32 @tail_caller(i32 %a) local_unnamed_addr { ; CFST-LABEL: tail_caller: @@ -48,3 +135,4 @@ } declare i32 @tail_callee(i32) local_unnamed_addr +declare i32 @g(i32) local_unnamed_addr