[llvm] [llubi] Add support for llvm.speculative.load. (PR #226839)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 27 14:46:31 PDT 2026
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/226839
Implement the direct form of llvm.speculative.load, where the number of
accessible bytes N is passed as an i64. Only the N accessible bytes are
read from memory and they must be in bounds of the underlying object;
all other bytes are poison. With from_end, the accessible bytes are the
last N bytes of the loaded value. It is UB if N is poison or exceeds the
size of the loaded type.
Support for the oracle form will be added as follow-up.
>From fac4e8c4708fd9a8e5076e94c09363ec35fe44b5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 27 Sep 2026 15:13:56 +0000
Subject: [PATCH 1/2] [llubi] Precommit speculative load tests
---
.../test/tools/llubi/intr_speculative_load.ll | 53 +++++++++++++
.../tools/llubi/intr_speculative_load_ub.ll | 76 +++++++++++++++++++
2 files changed, 129 insertions(+)
create mode 100644 llvm/test/tools/llubi/intr_speculative_load.ll
create mode 100644 llvm/test/tools/llubi/intr_speculative_load_ub.ll
diff --git a/llvm/test/tools/llubi/intr_speculative_load.ll b/llvm/test/tools/llubi/intr_speculative_load.ll
new file mode 100644
index 0000000000000..221200b7c3e64
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_speculative_load.ll
@@ -0,0 +1,53 @@
+; RUN: not llubi --verbose --entry-function=first_bytes < %s 2>&1 | FileCheck %s --check-prefix=FIRST
+; RUN: not llubi --verbose --entry-function=last_bytes < %s 2>&1 | FileCheck %s --check-prefix=LAST
+; RUN: not llubi --verbose --entry-function=past_end < %s 2>&1 | FileCheck %s --check-prefix=PAST-END
+; RUN: not llubi --verbose --entry-function=oracle_load < %s 2>&1 | FileCheck %s --check-prefix=ORACLE
+
+ at a = global [6 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5]
+
+; Returns the number of bytes from %p to %end, clamped to 16.
+define i64 @oracle(ptr %p, ptr %end) memory(none) nounwind nosync willreturn {
+ %p.int = ptrtoaddr ptr %p to i64
+ %end.int = ptrtoaddr ptr %end to i64
+ %diff = sub i64 %end.int, %p.int
+ %n = call i64 @llvm.umin.i64(i64 %diff, i64 16)
+ ret i64 %n
+}
+
+define void @first_bytes() {
+; FIRST: Entering function: first_bytes
+; FIRST-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 8)
+; FIRST-NEXT: error: Execution of function 'first_bytes' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 8)
+ ret void
+}
+
+define void @last_bytes() {
+; LAST: Entering function: last_bytes
+; LAST-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 true, i64 8)
+; LAST-NEXT: error: Execution of function 'last_bytes' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 true, i64 8)
+ ret void
+}
+
+define void @past_end() {
+; PAST-END: Entering function: past_end
+; PAST-END-NEXT: %p = getelementptr i32, ptr @a, i64 4 => ptr 0x20 [@a + 16]
+; PAST-END-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, i64 8)
+; PAST-END-NEXT: error: Execution of function 'past_end' failed.
+ %p = getelementptr i32, ptr @a, i64 4
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, i64 8)
+ ret void
+}
+
+define void @oracle_load() {
+; ORACLE: Entering function: oracle_load
+; ORACLE-NEXT: %p = getelementptr i32, ptr @a, i64 4 => ptr 0x20 [@a + 16]
+; ORACLE-NEXT: %end = getelementptr i32, ptr @a, i64 6 => ptr 0x28 [@a + 24]
+; ORACLE-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, ptr @oracle, ptr %p, ptr %end)
+; ORACLE-NEXT: error: Execution of function 'oracle_load' failed.
+ %p = getelementptr i32, ptr @a, i64 4
+ %end = getelementptr i32, ptr @a, i64 6
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, ptr @oracle, ptr %p, ptr %end)
+ ret void
+}
diff --git a/llvm/test/tools/llubi/intr_speculative_load_ub.ll b/llvm/test/tools/llubi/intr_speculative_load_ub.ll
new file mode 100644
index 0000000000000..c6c163adb4d3d
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_speculative_load_ub.ll
@@ -0,0 +1,76 @@
+; RUN: not llubi --verbose --entry-function=out_of_bounds < %s 2>&1 | FileCheck %s --check-prefix=OOB
+; RUN: not llubi --verbose --entry-function=from_end_out_of_bounds < %s 2>&1 | FileCheck %s --check-prefix=FROM-END-OOB
+; RUN: not llubi --verbose --entry-function=exceeds_size < %s 2>&1 | FileCheck %s --check-prefix=EXCEEDS-SIZE
+; RUN: not llubi --verbose --entry-function=poison_num_bytes < %s 2>&1 | FileCheck %s --check-prefix=POISON-N
+; RUN: not llubi --verbose --entry-function=poison_pointer < %s 2>&1 | FileCheck %s --check-prefix=POISON-PTR
+; RUN: not llubi --verbose --entry-function=oracle_out_of_bounds < %s 2>&1 | FileCheck %s --check-prefix=ORACLE-OOB
+; RUN: not llubi --verbose --entry-function=oracle_declaration < %s 2>&1 | FileCheck %s --check-prefix=ORACLE-DECL
+
+ at a = global [2 x i32] [i32 0, i32 1]
+
+; Returns one element more than the number of bytes from %p to %end.
+define i64 @oracle_off_by_one(ptr %p, ptr %end) memory(none) nounwind nosync willreturn {
+ %p.int = ptrtoaddr ptr %p to i64
+ %end.int = ptrtoaddr ptr %end to i64
+ %diff = sub i64 %end.int, %p.int
+ %n = add i64 %diff, 4
+ ret i64 %n
+}
+
+declare i64 @oracle_decl(i64) memory(none) nounwind nosync willreturn
+
+define void @out_of_bounds() {
+; OOB: Entering function: out_of_bounds
+; OOB-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 12)
+; OOB-NEXT: error: Execution of function 'out_of_bounds' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 12)
+ ret void
+}
+
+define void @from_end_out_of_bounds() {
+; FROM-END-OOB: Entering function: from_end_out_of_bounds
+; FROM-END-OOB-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr getelementptr (i8, ptr @a, i64 -8), i1 true, i64 12)
+; FROM-END-OOB-NEXT: error: Execution of function 'from_end_out_of_bounds' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr getelementptr (i8, ptr @a, i64 -8), i1 true, i64 12)
+ ret void
+}
+
+define void @exceeds_size() {
+; EXCEEDS-SIZE: Entering function: exceeds_size
+; EXCEEDS-SIZE-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 17)
+; EXCEEDS-SIZE-NEXT: error: Execution of function 'exceeds_size' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 17)
+ ret void
+}
+
+define void @poison_num_bytes() {
+; POISON-N: Entering function: poison_num_bytes
+; POISON-N-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 poison)
+; POISON-N-NEXT: error: Execution of function 'poison_num_bytes' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 poison)
+ ret void
+}
+
+define void @poison_pointer() {
+; POISON-PTR: Entering function: poison_pointer
+; POISON-PTR-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr poison, i1 false, i64 0)
+; POISON-PTR-NEXT: error: Execution of function 'poison_pointer' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr poison, i1 false, i64 0)
+ ret void
+}
+
+define void @oracle_out_of_bounds() {
+; ORACLE-OOB: Entering function: oracle_out_of_bounds
+; ORACLE-OOB-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_off_by_one, ptr @a, ptr getelementptr (i8, ptr @a, i64 8))
+; ORACLE-OOB-NEXT: error: Execution of function 'oracle_out_of_bounds' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_off_by_one, ptr @a, ptr getelementptr (i8, ptr @a, i64 8))
+ ret void
+}
+
+define void @oracle_declaration() {
+; ORACLE-DECL: Entering function: oracle_declaration
+; ORACLE-DECL-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_decl, i64 4)
+; ORACLE-DECL-NEXT: error: Execution of function 'oracle_declaration' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_decl, i64 4)
+ ret void
+}
>From 91857a1e80e6acda39f950dfe921bb27484d3fe5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 27 Sep 2026 12:24:51 +0100
Subject: [PATCH 2/2] [llubi] Add support for llvm.speculative.load.
Implement the direct form of llvm.speculative.load, where the number of
accessible bytes N is passed as an i64. Only the N accessible bytes are
read from memory and they must be in bounds of the underlying object;
all other bytes are poison. With from_end, the accessible bytes are the
last N bytes of the loaded value. It is UB if N is poison or exceeds the
size of the loaded type.
Support for the oracle form will be added as follow-up.
---
.../test/tools/llubi/intr_speculative_load.ll | 21 ++++----
.../tools/llubi/intr_speculative_load_ub.ll | 20 ++++++--
llvm/tools/llubi/lib/Interpreter.cpp | 48 +++++++++++++++++++
3 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/llvm/test/tools/llubi/intr_speculative_load.ll b/llvm/test/tools/llubi/intr_speculative_load.ll
index 221200b7c3e64..8e927f5b49038 100644
--- a/llvm/test/tools/llubi/intr_speculative_load.ll
+++ b/llvm/test/tools/llubi/intr_speculative_load.ll
@@ -1,6 +1,6 @@
-; RUN: not llubi --verbose --entry-function=first_bytes < %s 2>&1 | FileCheck %s --check-prefix=FIRST
-; RUN: not llubi --verbose --entry-function=last_bytes < %s 2>&1 | FileCheck %s --check-prefix=LAST
-; RUN: not llubi --verbose --entry-function=past_end < %s 2>&1 | FileCheck %s --check-prefix=PAST-END
+; RUN: llubi --verbose --entry-function=first_bytes < %s 2>&1 | FileCheck %s --check-prefix=FIRST
+; RUN: llubi --verbose --entry-function=last_bytes < %s 2>&1 | FileCheck %s --check-prefix=LAST
+; RUN: llubi --verbose --entry-function=past_end < %s 2>&1 | FileCheck %s --check-prefix=PAST-END
; RUN: not llubi --verbose --entry-function=oracle_load < %s 2>&1 | FileCheck %s --check-prefix=ORACLE
@a = global [6 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5]
@@ -16,16 +16,18 @@ define i64 @oracle(ptr %p, ptr %end) memory(none) nounwind nosync willreturn {
define void @first_bytes() {
; FIRST: Entering function: first_bytes
-; FIRST-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 8)
-; FIRST-NEXT: error: Execution of function 'first_bytes' failed.
+; FIRST-NEXT: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 8) => { i32 0, i32 1, poison, poison }
+; FIRST-NEXT: ret void
+; FIRST-NEXT: Exiting function: first_bytes
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 8)
ret void
}
define void @last_bytes() {
; LAST: Entering function: last_bytes
-; LAST-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 true, i64 8)
-; LAST-NEXT: error: Execution of function 'last_bytes' failed.
+; LAST-NEXT: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 true, i64 8) => { poison, poison, i32 2, i32 3 }
+; LAST-NEXT: ret void
+; LAST-NEXT: Exiting function: last_bytes
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 true, i64 8)
ret void
}
@@ -33,8 +35,9 @@ define void @last_bytes() {
define void @past_end() {
; PAST-END: Entering function: past_end
; PAST-END-NEXT: %p = getelementptr i32, ptr @a, i64 4 => ptr 0x20 [@a + 16]
-; PAST-END-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, i64 8)
-; PAST-END-NEXT: error: Execution of function 'past_end' failed.
+; PAST-END-NEXT: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, i64 8) => { i32 4, i32 5, poison, poison }
+; PAST-END-NEXT: ret void
+; PAST-END-NEXT: Exiting function: past_end
%p = getelementptr i32, ptr @a, i64 4
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, i64 8)
ret void
diff --git a/llvm/test/tools/llubi/intr_speculative_load_ub.ll b/llvm/test/tools/llubi/intr_speculative_load_ub.ll
index c6c163adb4d3d..e08e1e410183d 100644
--- a/llvm/test/tools/llubi/intr_speculative_load_ub.ll
+++ b/llvm/test/tools/llubi/intr_speculative_load_ub.ll
@@ -21,7 +21,9 @@ declare i64 @oracle_decl(i64) memory(none) nounwind nosync willreturn
define void @out_of_bounds() {
; OOB: Entering function: out_of_bounds
-; OOB-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 12)
+; OOB-NEXT: Stacktrace:
+; OOB-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 12) at @out_of_bounds <stdin>:{{[0-9]+}}
+; OOB-NEXT: Immediate UB detected: Memory access is out of bounds. Accessed size: 12, Address: 0xc, Object base: 0xc, Object size: 8.
; OOB-NEXT: error: Execution of function 'out_of_bounds' failed.
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 12)
ret void
@@ -29,7 +31,9 @@ define void @out_of_bounds() {
define void @from_end_out_of_bounds() {
; FROM-END-OOB: Entering function: from_end_out_of_bounds
-; FROM-END-OOB-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr getelementptr (i8, ptr @a, i64 -8), i1 true, i64 12)
+; FROM-END-OOB-NEXT: Stacktrace:
+; FROM-END-OOB-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr getelementptr (i8, ptr @a, i64 -8), i1 true, i64 12) at @from_end_out_of_bounds <stdin>:{{[0-9]+}}
+; FROM-END-OOB-NEXT: Immediate UB detected: Memory access is out of bounds. Accessed size: 12, Address: 0x8, Object base: 0xc, Object size: 8.
; FROM-END-OOB-NEXT: error: Execution of function 'from_end_out_of_bounds' failed.
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr getelementptr (i8, ptr @a, i64 -8), i1 true, i64 12)
ret void
@@ -37,7 +41,9 @@ define void @from_end_out_of_bounds() {
define void @exceeds_size() {
; EXCEEDS-SIZE: Entering function: exceeds_size
-; EXCEEDS-SIZE-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 17)
+; EXCEEDS-SIZE-NEXT: Stacktrace:
+; EXCEEDS-SIZE-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 17) at @exceeds_size <stdin>:{{[0-9]+}}
+; EXCEEDS-SIZE-NEXT: Immediate UB detected: llvm.speculative.load number of accessible bytes 17 exceeds the loaded size 16.
; EXCEEDS-SIZE-NEXT: error: Execution of function 'exceeds_size' failed.
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 17)
ret void
@@ -45,7 +51,9 @@ define void @exceeds_size() {
define void @poison_num_bytes() {
; POISON-N: Entering function: poison_num_bytes
-; POISON-N-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 poison)
+; POISON-N-NEXT: Stacktrace:
+; POISON-N-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 poison) at @poison_num_bytes <stdin>:{{[0-9]+}}
+; POISON-N-NEXT: Immediate UB detected: llvm.speculative.load with poison number of accessible bytes.
; POISON-N-NEXT: error: Execution of function 'poison_num_bytes' failed.
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 poison)
ret void
@@ -53,7 +61,9 @@ define void @poison_num_bytes() {
define void @poison_pointer() {
; POISON-PTR: Entering function: poison_pointer
-; POISON-PTR-NEXT: Unrecognized instruction: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr poison, i1 false, i64 0)
+; POISON-PTR-NEXT: Stacktrace:
+; POISON-PTR-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr poison, i1 false, i64 0) at @poison_pointer <stdin>:{{[0-9]+}}
+; POISON-PTR-NEXT: Immediate UB detected: llvm.speculative.load with poison pointer.
; POISON-PTR-NEXT: error: Execution of function 'poison_pointer' failed.
%r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr poison, i1 false, i64 0)
ret void
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 0c7e74f52f689..3e4b250f4c85c 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -919,6 +919,46 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
return AnyValue();
}
+ AnyValue callSpeculativeLoadIntrinsic(CallBase &CB, const AnyValue &Ptr,
+ const AnyValue &NumBytes) {
+ Type *RetTy = CB.getType();
+ if (Ptr.isPoison()) {
+ reportImmediateUB() << "llvm.speculative.load with poison pointer.";
+ return AnyValue();
+ }
+ if (NumBytes.isPoison()) {
+ reportImmediateUB()
+ << "llvm.speculative.load with poison number of accessible bytes.";
+ return AnyValue();
+ }
+
+ const uint64_t Size = Ctx.getEffectiveTypeStoreSize(RetTy);
+ const APInt &NumBytesInt = NumBytes.asInteger();
+ if (NumBytesInt.ugt(Size)) {
+ reportImmediateUB() << "llvm.speculative.load number of accessible bytes "
+ << NumBytesInt.getZExtValue()
+ << " exceeds the loaded size " << Size << ".";
+ return AnyValue();
+ }
+
+ // Only the accessible bytes are read from memory and must be in bounds of
+ // the underlying object. All other bytes are poison.
+ const uint64_t N = NumBytesInt.getZExtValue();
+ SmallVector<Byte> Bytes(Size, Byte::poison());
+ if (N != 0) {
+ const bool FromEnd = cast<ConstantInt>(CB.getArgOperand(1))->isOne();
+ const uint64_t Start = FromEnd ? Size - N : 0;
+ const Pointer &PtrVal = Ptr.asPointer();
+ auto [MO, Offset] =
+ verifyMemAccess(PtrVal.getWithNewAddr(PtrVal.address() + Start), N,
+ Align(1), /*IsStore=*/false);
+ if (!MO)
+ return AnyValue();
+ copy(MO->getBytes().slice(Offset, N), Bytes.begin() + Start);
+ }
+ return Ctx.fromBytes(Bytes, RetTy);
+ }
+
public:
InstExecutor(Context &C, EventHandler &H, Function &F,
ArrayRef<AnyValue> Args, AnyValue &RetVal)
@@ -1743,6 +1783,14 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
case Intrinsic::memset:
case Intrinsic::memset_inline:
return callMemSetIntrinsic(CB, Args);
+ case Intrinsic::speculative_load:
+ // TODO: Support the oracle form.
+ if (isa<Function>(CB.getArgOperand(2))) {
+ Handler.onUnrecognizedInstruction(CB);
+ setFailed();
+ return AnyValue();
+ }
+ return callSpeculativeLoadIntrinsic(CB, Args[0], Args[2]);
case Intrinsic::experimental_noalias_scope_decl:
// FIXME: Not implemented yet. Currently it acts as a noop.
return AnyValue();
More information about the llvm-commits
mailing list