Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 0 additions & 50 deletions tests/c/funcptrarg_hasir.c

This file was deleted.

72 changes: 72 additions & 0 deletions tests/c/inline_indirect_call.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// ignore-if: test "$YK_JITC" = "j2"
// Compiler:
// env-var: YKB_EXTRA_CC_FLAGS=-O2
// Run-time:
// env-var: YKD_LOG_IR=aot,jit-post-opt
// env-var: YKD_SERIALISE_COMPILATION=1
// env-var: YKD_LOG=4
// stderr:
// yk-tracing: start-tracing
// foo 7
// yk-tracing: stop-tracing
// --- Begin aot ---
// ...
// #[yk_outline]
// func bar(%{{_}}: i{{ty}}) -> i{{ty}};
// ...
// #[yk_indirect_inline]
// func foo(...
// ...
// %{{_}}: i32 = icall %{{_}}(...
// ...
// --- End aot ---
// ...
// --- Begin jit-post-opt ---
// ...
// %{{1}}: i32 = call @bar(...
// ...
// --- End jit-post-opt ---
// foo 6
// yk-execution: enter-jit-code
// foo 5
// foo 4
// yk-execution: deoptimise ...
// exit

// Check that an indirect call whose callee is marked `yk_indirect_inline` is
// inlined into the trace (as long as the calee pointer is promoted).

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <yk.h>
#include <yk_testing.h>

__attribute__((noinline, yk_outline)) int bar(int i) { return i + 3; }

__attribute__((yk_indirect_inline, noinline)) int foo(int i) { return bar(i); }

int main(int argc, char **argv) {
YkMT *mt = yk_mt_new(NULL);
yk_mt_hot_threshold_set(mt, 0);
YkLocation loc = yk_location_new();

int i = 4;
int (*fn)(int) = foo;

NOOPT_VAL(loc);
NOOPT_VAL(i);
NOOPT_VAL(fn);
while (i > 0) {
yk_mt_control_point(mt, &loc);
int (*fp)(int) = yk_promote((void *) fn);
int x = fp(i);
fprintf(stderr, "foo %d\n", x);
i--;
}
fprintf(stderr, "exit\n");
yk_location_drop(loc);
yk_mt_shutdown(mt);
return (EXIT_SUCCESS);
}
16 changes: 10 additions & 6 deletions tests/c/indirect_call.c → tests/c/outline_indirect_call.c
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
// ignore-if: test "$YK_JITC" = "j2"
// Run-time:
// env-var: YKD_LOG_IR=jit-pre-opt
// env-var: YKD_LOG_IR=jit-post-opt
// env-var: YKD_SERIALISE_COMPILATION=1
// env-var: YKD_LOG=4
// stderr:
// yk-tracing: start-tracing
// foo 7
// yk-tracing: stop-tracing
// --- Begin jit-pre-opt ---
// --- Begin jit-post-opt ---
// ...
// %{{1}}: i32 = icall %{{2}}(%{{3}})
// %{{1}}: i32 = icall 0x...
// ...
// --- End jit-pre-opt ---
// --- End jit-post-opt ---
// foo 6
// yk-execution: enter-jit-code
// foo 5
// foo 4
// yk-execution: deoptimise ...
// exit

// Check that indirect calls work.
// Check that an indirect call whose callee isn't marked `yk_indirect_inline`
// is outlined in the trace (even if the callee pointer is promoted).
//
// To have it inlined, the calle would need to be marked `yk_indirect_inline`.

#include <assert.h>
#include <stdio.h>
Expand All @@ -43,7 +46,8 @@ int main(int argc, char **argv) {
NOOPT_VAL(fn);
while (i > 0) {
yk_mt_control_point(mt, &loc);
int x = fn(i);
int (*fp)(int) = yk_promote((void *) fn);
int x = fp(i);
fprintf(stderr, "foo %d\n", x);
i--;
}
Expand Down
8 changes: 8 additions & 0 deletions ykrt/src/compile/jitc_yk/aot_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,7 @@ pub(crate) struct Func {

const FUNCFLAG_OUTLINE: u8 = 1;
const FUNCFLAG_IDEMPOTENT: u8 = 1 << 1;
const FUNCFLAG_INDIRECT_INLINE: u8 = 1 << 2;

impl Func {
pub(crate) fn is_declaration(&self) -> bool {
Expand All @@ -1504,6 +1505,10 @@ impl Func {
self.flags & FUNCFLAG_IDEMPOTENT != 0
}

pub(crate) fn is_indirect_inline(&self) -> bool {
self.flags & FUNCFLAG_INDIRECT_INLINE != 0
}

/// Return the [BBlock] at the specified index.
///
/// # Panics
Expand Down Expand Up @@ -1570,6 +1575,9 @@ impl fmt::Display for DisplayableFunc<'_> {
if self.func_.is_outline() {
attrs.push("yk_outline");
}
if self.func_.is_indirect_inline() {
attrs.push("yk_indirect_inline");
}
let attrs = if !attrs.is_empty() {
&format!("#[{}]\n", attrs.join(", "))
} else {
Expand Down
7 changes: 6 additions & 1 deletion ykrt/src/compile/jitc_yk/trace_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,12 @@ impl TraceBuilder {
let nextinst = blk.insts.last().unwrap();
self.handle_indirectcall(
inst, bid, iidx, ftyidx, callop, args, nextinst, safepoint,
)
)?;
// FIXME: This `return` assumes that the indirect callee is traceable. If it
// isn't, we shouldn't update the previous block (like in the `Inst::Call` case
// above), but we (currently) have no way of knowing if the (dynamic) callee is
// traceable. At least an assertion will fail if/when we encounter this.
return Ok(Some(None));
}
aot_ir::Inst::Store { tgt, val, volatile } => {
self.handle_store(bid, iidx, tgt, val, *volatile)
Expand Down