[llvm] [llubi] Support the oracle form of llvm.speculative.load. (PR #227095)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 28 12:51:28 PDT 2026
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/227095
Add support for llvm.speculative.load with oracle functions.
This is split into 2 steps:
1. enterCall checks if CB is a speculative load in oracle form. If so, adjust Callee to the oracle functions and drop the non-oracle arguments.
2. returnFromCallee also hecks if the current PC is a speculative load with oracle. If so, it calls callSpeculativeLoadIntrinsic before returning.
>From 1c1cf43aac21151c033367ee91545c10b655a1e2 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 27 Sep 2026 12:25:48 +0100
Subject: [PATCH] [llubi] Support the oracle form of llvm.speculative.load.
Add support for llvm.speculative.load with oracle functions.
This is split into 2 steps:
1. enterCall checks if CB is a speculative load in oracle form. If so,
adjust Callee to the oracle functions and drop the non-oracle
arguments.
2. returnFromCallee also hecks if the current PC is a speculative load
with oracle. If so, it calls callSpeculativeLoadIntrinsic before
returning.
---
.../test/tools/llubi/intr_speculative_load.ll | 22 -----
.../llubi/intr_speculative_load_oracle.ll | 70 ++++++++++++++++
.../llubi/intr_speculative_load_oracle_ub.ll | 82 +++++++++++++++++++
.../tools/llubi/intr_speculative_load_ub.ll | 33 +-------
llvm/tools/llubi/lib/Interpreter.cpp | 41 ++++++++--
5 files changed, 187 insertions(+), 61 deletions(-)
create mode 100644 llvm/test/tools/llubi/intr_speculative_load_oracle.ll
create mode 100644 llvm/test/tools/llubi/intr_speculative_load_oracle_ub.ll
diff --git a/llvm/test/tools/llubi/intr_speculative_load.ll b/llvm/test/tools/llubi/intr_speculative_load.ll
index 8e927f5b49038..4b32766e10c3e 100644
--- a/llvm/test/tools/llubi/intr_speculative_load.ll
+++ b/llvm/test/tools/llubi/intr_speculative_load.ll
@@ -1,19 +1,9 @@
; 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]
-; 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: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, i64 8) => { i32 0, i32 1, poison, poison }
@@ -42,15 +32,3 @@ define void @past_end() {
%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_oracle.ll b/llvm/test/tools/llubi/intr_speculative_load_oracle.ll
new file mode 100644
index 0000000000000..dc413612491bf
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_speculative_load_oracle.ll
@@ -0,0 +1,70 @@
+; RUN: llubi --verbose --entry-function=oracle_load < %s 2>&1 | FileCheck %s --check-prefix=ORACLE
+; RUN: llubi --verbose --entry-function=nested_oracle_load < %s 2>&1 | FileCheck %s --check-prefix=NESTED
+
+ 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
+}
+
+; Returns the second element at %p plus 3, loaded via an oracle-form
+; llvm.speculative.load.
+define i64 @oracle_nested(ptr %p) memory(argmem: read) nounwind nosync willreturn {
+ %v = call <2 x i32> (ptr, i1, ...) @llvm.speculative.load.v2i32.p0(ptr %p, i1 false, ptr @oracle_const, i64 8)
+ %e = extractelement <2 x i32> %v, i64 1
+ %z = zext i32 %e to i64
+ %n = add i64 %z, 3
+ ret i64 %n
+}
+
+define i64 @oracle_const(i64 %n) memory(none) nounwind nosync willreturn {
+ ret i64 %n
+}
+
+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: Entering function: oracle
+; ORACLE-NEXT: ptr %p = ptr 0x20 [@a + 16]
+; ORACLE-NEXT: ptr %end = ptr 0x28 [@a + 24]
+; ORACLE-NEXT: %p.int = ptrtoaddr ptr %p to i64 => i64 32
+; ORACLE-NEXT: %end.int = ptrtoaddr ptr %end to i64 => i64 40
+; ORACLE-NEXT: %diff = sub i64 %end.int, %p.int => i64 8
+; ORACLE-NEXT: %n = call i64 @llvm.umin.i64(i64 %diff, i64 16) => i64 8
+; ORACLE-NEXT: ret i64 %n
+; ORACLE-NEXT: Exiting function: oracle
+; ORACLE-NEXT: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, ptr @oracle, ptr %p, ptr %end) => { i32 4, i32 5, poison, poison }
+; ORACLE-NEXT: ret void
+; ORACLE-NEXT: Exiting function: oracle_load
+ %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
+}
+
+define void @nested_oracle_load() {
+; NESTED: Entering function: nested_oracle_load
+; NESTED-NEXT: Entering function: oracle_nested
+; NESTED-NEXT: ptr %p = ptr 0x10 [@a]
+; NESTED-NEXT: Entering function: oracle_const
+; NESTED-NEXT: i64 %n = i64 8
+; NESTED-NEXT: ret i64 %n
+; NESTED-NEXT: Exiting function: oracle_const
+; NESTED-NEXT: %v = call <2 x i32> (ptr, i1, ...) @llvm.speculative.load.v2i32.p0(ptr %p, i1 false, ptr @oracle_const, i64 8) => { i32 0, i32 1 }
+; NESTED-NEXT: %e = extractelement <2 x i32> %v, i64 1 => i32 1
+; NESTED-NEXT: %z = zext i32 %e to i64 => i64 1
+; NESTED-NEXT: %n = add i64 %z, 3 => i64 4
+; NESTED-NEXT: ret i64 %n
+; NESTED-NEXT: Exiting function: oracle_nested
+; NESTED-NEXT: %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 true, ptr @oracle_nested, ptr @a) => { poison, poison, poison, i32 3 }
+; NESTED-NEXT: ret void
+; NESTED-NEXT: Exiting function: nested_oracle_load
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 true, ptr @oracle_nested, ptr @a)
+ ret void
+}
diff --git a/llvm/test/tools/llubi/intr_speculative_load_oracle_ub.ll b/llvm/test/tools/llubi/intr_speculative_load_oracle_ub.ll
new file mode 100644
index 0000000000000..18eecbd5432ce
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_speculative_load_oracle_ub.ll
@@ -0,0 +1,82 @@
+; 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_poison_noundef_ret < %s 2>&1 | FileCheck %s --check-prefix=NOUNDEF-RET
+; RUN: not llubi --verbose --entry-function=oracle_poison_noundef_arg < %s 2>&1 | FileCheck %s --check-prefix=NOUNDEF-ARG
+; RUN: not llubi --verbose --entry-function=oracle_declaration < %s 2>&1 | FileCheck %s --check-prefix=ORACLE-DECL
+
+ at a = global [6 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5]
+
+; 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
+}
+
+define noundef i64 @oracle_noundef_ret(i64 %n) memory(none) nounwind nosync willreturn {
+ ret i64 poison
+}
+
+define i64 @oracle_noundef_arg(i64 noundef %n) memory(none) nounwind nosync willreturn {
+ ret i64 %n
+}
+
+declare i64 @oracle_decl(i64) memory(none) nounwind nosync willreturn
+
+define void @oracle_out_of_bounds() {
+; ORACLE-OOB: Entering function: oracle_out_of_bounds
+; ORACLE-OOB-NEXT: %p = getelementptr i32, ptr @a, i64 4 => ptr 0x20 [@a + 16]
+; ORACLE-OOB-NEXT: %end = getelementptr i32, ptr @a, i64 6 => ptr 0x28 [@a + 24]
+; ORACLE-OOB-NEXT: Entering function: oracle_off_by_one
+; ORACLE-OOB-NEXT: ptr %p = ptr 0x20 [@a + 16]
+; ORACLE-OOB-NEXT: ptr %end = ptr 0x28 [@a + 24]
+; ORACLE-OOB-NEXT: %p.int = ptrtoaddr ptr %p to i64 => i64 32
+; ORACLE-OOB-NEXT: %end.int = ptrtoaddr ptr %end to i64 => i64 40
+; ORACLE-OOB-NEXT: %diff = sub i64 %end.int, %p.int => i64 8
+; ORACLE-OOB-NEXT: %n = add i64 %diff, 4 => i64 12
+; ORACLE-OOB-NEXT: ret i64 %n
+; ORACLE-OOB-NEXT: Exiting function: oracle_off_by_one
+; ORACLE-OOB-NEXT: Stacktrace:
+; ORACLE-OOB-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr %p, i1 false, ptr @oracle_off_by_one, ptr %p, ptr %end) at @oracle_out_of_bounds <stdin>:{{[0-9]+}}
+; ORACLE-OOB-NEXT: Immediate UB detected: Memory access is out of bounds. Accessed size: 12, Address: 0x20, Object base: 0x10, Object size: 24.
+; ORACLE-OOB-NEXT: error: Execution of function 'oracle_out_of_bounds' 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_off_by_one, ptr %p, ptr %end)
+ ret void
+}
+
+define void @oracle_poison_noundef_ret() {
+; NOUNDEF-RET: Entering function: oracle_poison_noundef_ret
+; NOUNDEF-RET-NEXT: Entering function: oracle_noundef_ret
+; NOUNDEF-RET-NEXT: i64 %n = i64 4
+; NOUNDEF-RET-NEXT: ret i64 poison
+; NOUNDEF-RET-NEXT: Exiting function: oracle_noundef_ret
+; NOUNDEF-RET-NEXT: Stacktrace:
+; NOUNDEF-RET-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_noundef_ret, i64 4) at @oracle_poison_noundef_ret <stdin>:{{[0-9]+}}
+; NOUNDEF-RET-NEXT: Immediate UB detected: The value poison violates noundef attribute.
+; NOUNDEF-RET-NEXT: error: Execution of function 'oracle_poison_noundef_ret' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_noundef_ret, i64 4)
+ ret void
+}
+
+define void @oracle_poison_noundef_arg() {
+; NOUNDEF-ARG: Entering function: oracle_poison_noundef_arg
+; NOUNDEF-ARG-NEXT: Stacktrace:
+; NOUNDEF-ARG-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_noundef_arg, i64 poison) at @oracle_poison_noundef_arg <stdin>:{{[0-9]+}}
+; NOUNDEF-ARG-NEXT: Immediate UB detected: The value poison violates noundef attribute.
+; NOUNDEF-ARG-NEXT: error: Execution of function 'oracle_poison_noundef_arg' failed.
+ %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_noundef_arg, i64 poison)
+ ret void
+}
+
+define void @oracle_declaration() {
+; ORACLE-DECL: Entering function: oracle_declaration
+; ORACLE-DECL-NEXT: Stacktrace:
+; ORACLE-DECL-NEXT: #0 %r = call <4 x i32> (ptr, i1, ...) @llvm.speculative.load.v4i32.p0(ptr @a, i1 false, ptr @oracle_decl, i64 4) at @oracle_declaration <stdin>:{{[0-9]+}}
+; ORACLE-DECL-NEXT: Error: Unsupported llvm.speculative.load oracle declaration: oracle_decl.
+; 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
+}
diff --git a/llvm/test/tools/llubi/intr_speculative_load_ub.ll b/llvm/test/tools/llubi/intr_speculative_load_ub.ll
index e08e1e410183d..11ba81f804e1d 100644
--- a/llvm/test/tools/llubi/intr_speculative_load_ub.ll
+++ b/llvm/test/tools/llubi/intr_speculative_load_ub.ll
@@ -3,27 +3,14 @@
; 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
@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: 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: Immediate UB detected: Memory access is out of bounds. Accessed size: 12, Address: 0x8, Object base: 0x8, 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
@@ -33,7 +20,7 @@ define void @from_end_out_of_bounds() {
; FROM-END-OOB: Entering function: from_end_out_of_bounds
; 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: Immediate UB detected: Memory access is out of bounds. Accessed size: 12, Address: 0x4, Object base: 0x8, 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
@@ -68,19 +55,3 @@ define void @poison_pointer() {
%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
-}
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 3e4b250f4c85c..5d5c2d2778e3d 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -919,6 +919,14 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
return AnyValue();
}
+ /// Returns the oracle function if \p CB is an llvm.speculative.load in
+ /// oracle form, nullptr otherwise.
+ static Function *getSpeculativeLoadOracle(const CallBase &CB) {
+ return CB.getIntrinsicID() == Intrinsic::speculative_load
+ ? dyn_cast<Function>(CB.getArgOperand(2))
+ : nullptr;
+ }
+
AnyValue callSpeculativeLoadIntrinsic(CallBase &CB, const AnyValue &Ptr,
const AnyValue &NumBytes) {
Type *RetTy = CB.getType();
@@ -1043,8 +1051,15 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
void returnFromCallee() {
auto &CB = cast<CallBase>(*CurrentFrame->PC);
- CurrentFrame->CalleeArgs.clear();
AnyValue &RetVal = CurrentFrame->CalleeRetVal;
+ if (Function *Oracle = getSpeculativeLoadOracle(CB)) {
+ // RetVal is the oracle's result; use it to complete the load.
+ handleAttributes(Oracle->getReturnType(), RetVal, AttributeSet(),
+ Oracle->getAttributes().getRetAttrs());
+ RetVal =
+ callSpeculativeLoadIntrinsic(CB, CurrentFrame->CalleeArgs[0], RetVal);
+ }
+ CurrentFrame->CalleeArgs.clear();
if (Type *RetTy = CB.getType(); !RetTy->isVoidTy()) {
// Handle attributes on the return value (Attributes from resolved callee
// should be applied if available).
@@ -1784,12 +1799,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
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.
@@ -2212,6 +2221,23 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
CurrentFrame->ResolvedCallee = Callee;
+ ArrayRef<AnyValue> Args = CalleeArgs;
+ // Call the oracle of an llvm.speculative.load with the trailing arguments.
+ // The load is completed in returnFromCallee.
+ if (Function *Oracle = getSpeculativeLoadOracle(CB)) {
+ if (Oracle->isDeclaration()) {
+ reportError()
+ << "Unsupported llvm.speculative.load oracle declaration: "
+ << Oracle->getName() << ".";
+ return;
+ }
+ Args = Args.drop_front(3);
+ for (auto [Arg, ArgVal] :
+ zip_equal(Oracle->args(), MutableArrayRef(CalleeArgs).drop_front(3)))
+ handleAttributes(Arg.getType(), ArgVal, AttributeSet(),
+ Arg.getAttributes());
+ Callee = Oracle;
+ }
if (Callee->isIntrinsic()) {
CurrentFrame->CalleeRetVal = callIntrinsic(CB, CalleeArgs);
returnFromCallee();
@@ -2228,7 +2254,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
assert(!Callee->empty() && "Expected a defined function.");
// Suspend the current frame and push the callee frame onto the stack.
- ArrayRef<AnyValue> Args = CurrentFrame->CalleeArgs;
AnyValue &RetVal = CurrentFrame->CalleeRetVal;
CurrentFrame->State = FrameState::Pending;
CallStack.emplace_back(*Callee, &CB, CurrentFrame, Args, RetVal,
More information about the llvm-commits
mailing list