zbrid created this revision.
zbrid added reviewers: chandlerc, kristof.beyls, aaron.ballman, 
devinj.jeanpierre.
Herald added subscribers: llvm-commits, cfe-commits, jdoerfert, jfb, aheejin, 
hiraditya, javed.absar, dschuff.
Herald added projects: clang, LLVM.

This is similar to the work Kristof did for ARM here: 
https://reviews.llvm.org/D49072

For now, I have only implemented the version that lowers the intrinsic using an 
LFENCE. I'm workign on a version that can be lowered as an LFENCE or lowered 
using the control flow speculation available, so users have the option just as 
they do in the ARM patch.

This is intended to add to the discussion rather than be a definitive patch 
relating to the way we will handle spot mitigations as far as the final 
API/implementation in LLVM goes. Any comments about the API, the way 
implemented this, or anything else are welcome.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D59827

Files:
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Frontend/InitPreprocessor.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGen/builtin-speculation-safe-value.c
  clang/test/Preprocessor/init.c
  llvm/include/llvm/CodeGen/ISDOpcodes.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/include/llvm/IR/IntrinsicsX86.td
  llvm/include/llvm/Target/TargetSelectionDAG.td
  llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
  llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
  llvm/lib/Target/X86/X86ISelLowering.cpp
  llvm/lib/Target/X86/X86ISelLowering.h
  llvm/lib/Target/X86/X86InstrInfo.td
  llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
  llvm/test/CodeGen/X86/speculative-load-hardening-intrinsic.ll

Index: llvm/test/CodeGen/X86/speculative-load-hardening-intrinsic.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/X86/speculative-load-hardening-intrinsic.ll
@@ -0,0 +1,71 @@
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=X64
+
+; ModuleID = 'hello.cpp'
+source_filename = "hello.cpp"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @_Z5foo32i(i32 %a) #0 {
+entry:
+  %a.addr = alloca i32, align 4
+  %b = alloca i32, align 4
+  %b_safe = alloca i32, align 4
+  %c = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  %0 = load i32, i32* %a.addr, align 4
+  %mul = mul nsw i32 %0, 100
+  store i32 %mul, i32* %b, align 4
+  %1 = load i32, i32* %b, align 4
+  %2 = call i32 @llvm.speculationsafevalue.i32(i32 %1)
+; X64: movl -12(%rbp), %eax
+; X64: lfence
+; X64: movl %eax, -8(%rbp)
+  store i32 %2, i32* %b_safe, align 4
+  %3 = load i32, i32* %b_safe, align 4
+  %add = add nsw i32 %3, 100
+  store i32 %add, i32* %c, align 4
+  %4 = load i32, i32* %c, align 4
+  ret i32 %4
+}
+
+; Function Attrs: nounwind
+declare i32 @llvm.speculationsafevalue.i32(i32) #1
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @_Z5foo64i(i32 %a) #0 {
+entry:
+  %a.addr = alloca i32, align 4
+  %b = alloca i64, align 8
+  %b_safe = alloca i64, align 8
+  %c = alloca i64, align 8
+  store i32 %a, i32* %a.addr, align 4
+  %0 = load i32, i32* %a.addr, align 4
+  %mul = mul nsw i32 %0, 100
+  %conv = sext i32 %mul to i64
+  store i64 %conv, i64* %b, align 8
+  %1 = load i64, i64* %b, align 8
+  %2 = call i64 @llvm.speculationsafevalue.i64(i64 %1)
+; X64: movq -32(%rbp), %rax
+; X64: lfence
+; X64: movq %rax, -24(%rbp)
+  store i64 %2, i64* %b_safe, align 8
+  %3 = load i64, i64* %b_safe, align 8
+  %add = add nsw i64 %3, 100
+  store i64 %add, i64* %c, align 8
+  %4 = load i64, i64* %c, align 8
+  %conv1 = trunc i64 %4 to i32
+  ret i32 %conv1
+}
+
+; Function Attrs: nounwind
+declare i64 @llvm.speculationsafevalue.i64(i64) #1
+
+attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 9.0.0 (https://github.com/llvm/llvm-project.git 6fd90b5505fe7cddd0fd798fe9608ea0e0325302)"}
Index: llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
===================================================================
--- llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
+++ llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
@@ -212,6 +212,7 @@
   void hardenIndirectCallOrJumpInstr(
       MachineInstr &MI,
       SmallDenseMap<unsigned, unsigned, 32> &AddrRegToHardenedReg);
+  bool lowerIntrinsic(MachineFunction &MF);
 };
 
 } // end anonymous namespace
@@ -402,16 +403,19 @@
   LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()
                     << " **********\n");
 
-  // Only run if this pass is forced enabled or we detect the relevant function
-  // attribute requesting SLH.
-  if (!EnableSpeculativeLoadHardening &&
-      !MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening))
-    return false;
-
   Subtarget = &MF.getSubtarget<X86Subtarget>();
   MRI = &MF.getRegInfo();
   TII = Subtarget->getInstrInfo();
   TRI = Subtarget->getRegisterInfo();
+  bool Modified = lowerIntrinsic(MF);
+
+  // Only run this pass completely if it is forced enabled or if we detect the relevant function
+  // attribute requesting SLH. Otherwise we should only check for intrinsics that we must lower by adding an lfence.
+  if (!EnableSpeculativeLoadHardening &&
+      !MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening)) {
+
+    return false || Modified;
+  }
 
   // FIXME: Support for 32-bit.
   PS.emplace(MF, &X86::GR64_NOSPRegClass);
@@ -597,6 +601,37 @@
   }
 }
 
+bool X86SpeculativeLoadHardeningPass::lowerIntrinsic(
+    MachineFunction &MF) {
+  bool Modified = false;
+  for (MachineBasicBlock &MBB : MF) {
+    MachineBasicBlock::iterator MBBI = MBB.begin();
+    MachineBasicBlock::iterator MBBE = MBB.end();
+    while (MBBI != MBBE) {
+      MachineBasicBlock::iterator NMBBI = std::next(MBBI);
+      MachineInstr &MI = *MBBI;
+      unsigned Opcode = MI.getOpcode();
+      if (Opcode == X86::SpeculationSafeValue32) {
+        BuildMI(MBB, NMBBI, DebugLoc(), TII->get(X86::LFENCE));
+        ++NumInstsInserted;
+        ++NumLFENCEsInserted;
+        MRI->replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());
+        MI.eraseFromParent();
+        Modified = true;
+      } else if (Opcode == X86::SpeculationSafeValue64) {
+        BuildMI(MBB, NMBBI, DebugLoc(), TII->get(X86::LFENCE));
+        ++NumInstsInserted;
+        ++NumLFENCEsInserted;
+        MRI->replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());
+        MI.eraseFromParent();
+        Modified = true;
+      }
+      MBBI = NMBBI;
+    }
+  }
+  return Modified;
+}
+
 SmallVector<X86SpeculativeLoadHardeningPass::BlockCondInfo, 16>
 X86SpeculativeLoadHardeningPass::collectBlockCondInfo(MachineFunction &MF) {
   SmallVector<BlockCondInfo, 16> Infos;
Index: llvm/lib/Target/X86/X86InstrInfo.td
===================================================================
--- llvm/lib/Target/X86/X86InstrInfo.td
+++ llvm/lib/Target/X86/X86InstrInfo.td
@@ -298,6 +298,9 @@
                                             SDTCisVT<2, i32>, SDTCisVT<3, i32>]>,
                        [SDNPHasChain, SDNPSideEffect]>;
 
+def X86SpeculationSafeValue : SDNode<"X86ISD::SpeculationSafeValue", SDTIntUnaryOp>;
+
+
 //===----------------------------------------------------------------------===//
 // X86 Operand Definitions.
 //
@@ -1164,6 +1167,15 @@
 //  Miscellaneous Instructions.
 //
 
+let hasSideEffects = 1, isCodeGenOnly = 1 in {
+  def SpeculationSafeValue64
+    : PseudoI<(outs GR64:$dst), (ins GR64:$src),
+        [(set GR64:$dst, (X86SpeculationSafeValue GR64:$src))]>;
+  def SpeculationSafeValue32
+    : PseudoI<(outs GR32:$dst), (ins GR32:$src),
+        [(set GR32:$dst, (X86SpeculationSafeValue GR32:$src))]>;
+}
+
 let isBarrier = 1, hasSideEffects = 1, usesCustomInserter = 1,
     SchedRW = [WriteSystem] in
   def Int_eh_sjlj_setup_dispatch
Index: llvm/lib/Target/X86/X86ISelLowering.h
===================================================================
--- llvm/lib/Target/X86/X86ISelLowering.h
+++ llvm/lib/Target/X86/X86ISelLowering.h
@@ -29,6 +29,8 @@
       // Start the numbering where the builtin ops leave off.
       FIRST_NUMBER = ISD::BUILTIN_OP_END,
 
+      SpeculationSafeValue,
+
       /// Bit scan forward.
       BSF,
       /// Bit scan reverse.
@@ -1188,6 +1190,8 @@
       LegalFPImmediates.push_back(Imm);
     }
 
+    SDValue LowerSPECULATION_SAFE_VALUE(SDValue Op, SelectionDAG &DAG) const;
+
     SDValue LowerCallResult(SDValue Chain, SDValue InFlag,
                             CallingConv::ID CallConv, bool isVarArg,
                             const SmallVectorImpl<ISD::InputArg> &Ins,
Index: llvm/lib/Target/X86/X86ISelLowering.cpp
===================================================================
--- llvm/lib/Target/X86/X86ISelLowering.cpp
+++ llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -193,6 +193,9 @@
   setCondCodeAction(ISD::SETUNE, MVT::f64, Expand);
   setCondCodeAction(ISD::SETUNE, MVT::f80, Expand);
 
+  setOperationAction(ISD::SPECULATION_SAFE_VALUE, MVT::i32, Custom);
+  setOperationAction(ISD::SPECULATION_SAFE_VALUE, MVT::i64, Custom);
+
   // Integer absolute.
   if (Subtarget.hasCMov()) {
     setOperationAction(ISD::ABS            , MVT::i16  , Custom);
@@ -4751,6 +4754,14 @@
   }
 }
 
+SDValue X86TargetLowering::LowerSPECULATION_SAFE_VALUE(SDValue Op, SelectionDAG &DAG) const {
+
+  assert((Op.getValueType() == MVT::i64 || Op.getValueType() == MVT::i32) && "Unexpected lowering");
+
+  SDLoc DL(Op);
+  return DAG.getNode(X86ISD::SpeculationSafeValue, DL, Op.getValueType(), Op.getOperand(0));
+}
+
 
 bool X86TargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
                                            const CallInst &I,
@@ -26714,6 +26725,8 @@
   case ISD::GC_TRANSITION_START:
                                 return LowerGC_TRANSITION_START(Op, DAG);
   case ISD::GC_TRANSITION_END:  return LowerGC_TRANSITION_END(Op, DAG);
+  case ISD::SPECULATION_SAFE_VALUE:
+                                return LowerSPECULATION_SAFE_VALUE(Op, DAG);
   }
 }
 
@@ -27913,6 +27926,8 @@
   case X86ISD::NT_BRIND:           return "X86ISD::NT_BRIND";
   case X86ISD::UMWAIT:             return "X86ISD::UMWAIT";
   case X86ISD::TPAUSE:             return "X86ISD::TPAUSE";
+  case X86ISD::SpeculationSafeValue:
+                                   return "X86ISD::SpeculationSafeValue";
   }
   return nullptr;
 }
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -79,6 +79,7 @@
 #ifndef NDEBUG
   case ISD::DELETED_NODE:               return "<<Deleted Node!>>";
 #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: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6075,6 +6075,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::fshl:
   case Intrinsic::fshr: {
     bool IsFSHL = Intrinsic == Intrinsic::fshl;
Index: llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -343,6 +343,7 @@
   SDValue PromoteIntRes_UNDEF(SDNode *N);
   SDValue PromoteIntRes_VAARG(SDNode *N);
   SDValue PromoteIntRes_XMULO(SDNode *N, unsigned ResNo);
+  SDValue PromoteIntRes_SpeculationSafeValue(SDNode *N);
   SDValue PromoteIntRes_ADDSUBSAT(SDNode *N);
   SDValue PromoteIntRes_MULFIX(SDNode *N);
   SDValue PromoteIntRes_FLT_ROUNDS(SDNode *N);
@@ -438,6 +439,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_ADDSUBSAT         (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandIntRes_MULFIX            (SDNode *N, SDValue &Lo, SDValue &Hi);
 
Index: llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -185,6 +185,9 @@
   case ISD::VECREDUCE_UMIN:
     Res = PromoteIntRes_VECREDUCE(N);
     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.
@@ -787,6 +790,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));
@@ -1680,6 +1690,9 @@
   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;
+
   case ISD::SADDSAT:
   case ISD::UADDSAT:
   case ISD::SSUBSAT:
@@ -2399,6 +2412,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: llvm/include/llvm/Target/TargetSelectionDAG.td
===================================================================
--- llvm/include/llvm/Target/TargetSelectionDAG.td
+++ llvm/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<list<SDTypeConstraint> constraints> :
         SDTypeProfile<0, 2, constraints>;
 class SDCallSeqEnd<list<SDTypeConstraint> constraints> :
@@ -581,6 +585,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: llvm/include/llvm/IR/IntrinsicsX86.td
===================================================================
--- llvm/include/llvm/IR/IntrinsicsX86.td
+++ llvm/include/llvm/IR/IntrinsicsX86.td
@@ -4816,3 +4816,7 @@
   def int_x86_invpcid : GCCBuiltin<"__builtin_ia32_invpcid">,
               Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty], []>;
 }
+
+//===----- Intrinsics to mitigate against miss-speculation exploits -------===//
+
+def int_speculationsafevalue : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], []>;
Index: llvm/include/llvm/IR/Intrinsics.td
===================================================================
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -1168,6 +1168,7 @@
 
 def int_ssa_copy : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>],
                              [IntrNoMem, Returned<0>]>;
+
 //===----------------------------------------------------------------------===//
 // Target-specific intrinsics
 //===----------------------------------------------------------------------===//
Index: llvm/include/llvm/CodeGen/ISDOpcodes.h
===================================================================
--- llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -881,6 +881,8 @@
     VECREDUCE_AND, VECREDUCE_OR, VECREDUCE_XOR,
     VECREDUCE_SMAX, VECREDUCE_SMIN, VECREDUCE_UMAX, VECREDUCE_UMIN,
 
+    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: clang/test/Preprocessor/init.c
===================================================================
--- clang/test/Preprocessor/init.c
+++ clang/test/Preprocessor/init.c
@@ -9675,6 +9675,7 @@
 // WEBASSEMBLY-NEXT:#define __GNUC_STDC_INLINE__ 1
 // WEBASSEMBLY-NEXT:#define __GNUC__ {{.*}}
 // WEBASSEMBLY-NEXT:#define __GXX_ABI_VERSION 1002
+// WEBASSEMBLY-NEXT: #define __HAVE_SPECULATION_SAFE_VALUE 1
 // WEBASSEMBLY32-NEXT:#define __ILP32__ 1
 // WEBASSEMBLY64-NOT:#define __ILP32__
 // WEBASSEMBLY-NEXT:#define __INT16_C_SUFFIX__
Index: clang/test/CodeGen/builtin-speculation-safe-value.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/builtin-speculation-safe-value.c
@@ -0,0 +1,19 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-SUPPORTED %s
+
+void test(char c, int i, void *p) {
+  // CHECK-LABEL-SUPPORTED: define void @test
+
+  char c_safe = __builtin_speculation_safe_value(c);
+  // CHECK-SUPPORTED: call i8 @llvm.speculationsafevalue.i8(i8 %{{[0-9a-z]+}})
+
+  int i_safe = __builtin_speculation_safe_value(i);
+  // CHECK-SUPPORTED: call i32 @llvm.speculationsafevalue.i32(i32 %{{[0-9a-z]+}})
+
+  void *p_safe = __builtin_speculation_safe_value(p);
+  // CHECK-SUPPORTED: call i8* @llvm.speculationsafevalue.p0i8(i8* %{{[0-9a-z]+}})
+
+  int arr[4];
+  int *arr_safe = __builtin_speculation_safe_value(arr);
+  // CHECK-SUPPORTED: call i32* @llvm.speculationsafevalue.p0i32(i32* %{{[0-9a-z]+}})
+}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -1492,6 +1492,8 @@
     if (SemaBuiltinOSLogFormat(TheCall))
       return ExprError();
     break;
+  case Builtin::BI__builtin_speculation_safe_value:
+   return SemaBuiltinSpeculationSafeValueOverloaded(TheCallResult);
   }
 
   // Since the target specific builtins for each arch overlap, only check those
@@ -5307,6 +5309,44 @@
   return TheCallResult;
 }
 
+ExprResult Sema::SemaBuiltinSpeculationSafeValueOverloaded(ExprResult TheCallResult) {
+  CallExpr *TheCall = (CallExpr *) TheCallResult.get();
+  DeclRefExpr *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+  FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+  unsigned BuiltinID = FDecl->getBuiltinID();
+  assert(BuiltinID == Builtin::BI__builtin_speculation_safe_value && "Unexpected speculation_Safe_value builtin!");
+
+  // Too few args
+  if (TheCall->getNumArgs() < 1)
+    return Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
+      << 0 /*function call*/ << 1 /* min args */ << TheCall->getNumArgs();
+
+  // Too many args
+  if (TheCall->getNumArgs() < 1)
+    return Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_many_args_at_most)
+      << 0 /*function call*/ << 1 << TheCall->getNumArgs()
+      << SourceRange(TheCall->getArg(1)->getBeginLoc(),
+      (*(TheCall->arg_end() - 1))->getEndLoc());
+
+  // Derive the return type from the pointer argument
+  ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
+  if (FirstArg.isInvalid())
+    return true;
+  TheCall->setArg(0, FirstArg.get());
+  QualType FirstArgType = FirstArg.get()->getType();
+
+  TheCall->setType(FirstArgType);
+
+  // The first argument must be a pointer or integer type.
+  if (!(FirstArgType->isIntegerType() || FirstArgType->isAnyPointerType()))
+    return Diag(TheCall->getArg(0)->getBeginLoc(),
+      diag::err_specsafevalue_builtin_must_be_pointer_or_integral)
+        << TheCall->getArg(0)->getType()
+        << TheCall->getArg(0)->getSourceRange();
+
+  return TheCallResult;
+}
+
 /// CheckObjCString - Checks that the argument to the builtin
 /// CFString constructor is correct
 /// Note: It might also make sense to do the UTF-16 conversion here (would
Index: clang/lib/Frontend/InitPreprocessor.cpp
===================================================================
--- clang/lib/Frontend/InitPreprocessor.cpp
+++ clang/lib/Frontend/InitPreprocessor.cpp
@@ -1083,6 +1083,8 @@
     Builder.defineMacro("__GLIBCXX_BITSIZE_INT_N_0", "128");
   }
 
+  Builder.defineMacro("__HAVE_SPECULATION_SAFE_VALUE");
+
   // Get other target #defines.
   TI.getTargetDefines(LangOpts, Builder);
 }
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "/usr/local/google/home/zbrid/repos/llvm-project/clang/lib/CodeGen/CodeGenTypeCache.h"
 #include "CGCXXABI.h"
 #include "CGObjCRuntime.h"
 #include "CGOpenCLRuntime.h"
@@ -3939,6 +3940,15 @@
     Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val");
     return RValue::get(Builder.CreateStore(ArgPtr, DestAddr));
   }
+  case Builtin::BI__builtin_speculation_safe_value: {
+    Value *Val = EmitScalarExpr(E->getArg(0));
+
+    llvm::Type *T = ConvertType(E->getType());
+    assert((isa<llvm::IntegerType>(T) || isa<llvm::PointerType>(T)) && "unsupported type");
+
+    return RValue::get(Builder.CreateCall(
+        CGM.getIntrinsic(Intrinsic::speculationsafevalue, T), {Val}));
+  }
   }
 
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -10712,6 +10712,7 @@
                                      AtomicExpr::AtomicOp Op);
   ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult,
                                                     bool IsDelete);
+  ExprResult SemaBuiltinSpeculationSafeValueOverloaded(ExprResult TheCallResult);
   bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
                               llvm::APSInt &Result);
   bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9553,6 +9553,10 @@
    "the type is not trivially copyable|"
    "the type does not have the expected form}1">;
 
+def err_specsafevalue_builtin_must_be_pointer_or_integral : Error<
+  "argument to speculation_safe_value builtin must be a pointer or integer "
+  "(%0 invalid)">;
+
 def warn_dereference_of_noderef_type : Warning<
   "dereferencing %0; was declared with a 'noderef' type">, InGroup<NoDeref>;
 def warn_dereference_of_noderef_type_no_decl : Warning<
Index: clang/include/clang/Basic/Builtins.def
===================================================================
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -1525,6 +1525,9 @@
 BUILTIN(__builtin_ms_va_end, "vc*&", "n")
 BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n")
 
+// T __builtin_speculation_safe_value (T val)
+BUILTIN(__builtin_speculation_safe_value, "vv", "t")
+
 #undef BUILTIN
 #undef LIBBUILTIN
 #undef LANGBUILTIN
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to