Skip to content

Commit

Permalink
Add early return and recursive tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
ltratt committed Nov 29, 2024
1 parent e258828 commit b2b96ee
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 11 deletions.
63 changes: 63 additions & 0 deletions tests/c/early_return.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Run-time:
// env-var: YKD_LOG_IR=-:jit-post-opt
// env-var: YKD_SERIALISE_COMPILATION=1
// env-var: YK_LOG=4
// stderr:
// 3
// 2
// yk-jit-event: start-tracing
// 1
// yk-jit-event: stop-tracing-early-return
// return
// yk-jit-event: start-tracing
// 3
// yk-jit-event: stop-tracing
// --- Begin jit-pre-opt ---
// ...
// --- End jit-pre-opt ---
// exit

// Check that basic trace compilation works.

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

void loop(YkMT *, YkLocation *);

void loop(YkMT *mt, YkLocation *loc) {
int res = 9998;
int i = 3;
NOOPT_VAL(res);
NOOPT_VAL(i);
while (i > 0) {
yk_mt_control_point(mt, loc);
fprintf(stderr, "%d\n", i);
i--;
}
yk_mt_early_return(mt);
fprintf(stderr, "return\n");
NOOPT_VAL(res);
}

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

int res = 9998;
int i = 4;
NOOPT_VAL(loc);
NOOPT_VAL(res);
NOOPT_VAL(i);
loop(mt, &loc);
loop(mt, &loc);
fprintf(stderr, "exit\n");
NOOPT_VAL(res);
yk_location_drop(loc);
yk_mt_shutdown(mt);
return (EXIT_SUCCESS);
}
1 change: 0 additions & 1 deletion tests/c/fcmp_double.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Run-time:
// env-var: YKD_LOG_IR=aot,jit-pre-opt,jit-asm
// env-var: YKD_SERIALISE_COMPILATION=1
// env-var: YK_LOG=4
// stderr:
Expand Down
1 change: 0 additions & 1 deletion tests/c/fcmp_float.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Run-time:
// env-var: YKD_LOG_IR=aot,jit-pre-opt,jit-asm
// env-var: YKD_SERIALISE_COMPILATION=1
// env-var: YK_LOG=4
// stderr:
Expand Down
61 changes: 61 additions & 0 deletions tests/c/recursive.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Run-time:
// env-var: YKD_LOG_IR=-:jit-post-opt
// env-var: YKD_SERIALISE_COMPILATION=1
// env-var: YK_LOG=4
// stderr:
// 3
// 2
// yk-jit-event: start-tracing
// 1
// yk-jit-event: stop-tracing-early-return
// return
// yk-jit-event: start-tracing
// 3
// yk-jit-event: stop-tracing
// --- Begin jit-pre-opt ---
// ...
// --- End jit-pre-opt ---
// exit

// Check that basic trace compilation works.

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

int loop(YkMT *, YkLocation *, int);

int loop(YkMT *mt, YkLocation *loc, int i) {
int res = 9998;
NOOPT_VAL(res);
NOOPT_VAL(i);
while (i > 0) {
yk_mt_control_point(mt, loc);
loop(mt, loc, i - 1);
fprintf(stderr, "%d\n", i);
i--;
}
yk_mt_early_return(mt);
fprintf(stderr, "return\n");
NOOPT_VAL(res);
return i;
}

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

int res = 9998;
NOOPT_VAL(loc);
NOOPT_VAL(res);
loop(mt, &loc, 3);
fprintf(stderr, "exit\n");
NOOPT_VAL(res);
yk_location_drop(loc);
yk_mt_shutdown(mt);
return (EXIT_SUCCESS);
}
7 changes: 7 additions & 0 deletions ykcapi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ pub extern "C" fn yk_mt_control_point(_mt: *mut MT, _loc: *mut Location) {
// Intentionally empty.
}

#[no_mangle]
pub extern "C" fn __yk_mt_early_return(mt: *mut MT, frameaddr: *mut c_void) {
let mt = unsafe { &*mt };
let arc = unsafe { Arc::from_raw(mt) };
arc.early_return(frameaddr);
}

// The new control point called after the interpreter has been patched by ykllvm.
#[cfg(target_arch = "x86_64")]
#[naked]
Expand Down
16 changes: 16 additions & 0 deletions ykcapi/yk.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ void yk_mt_shutdown(YkMT *);
// execute JITted code.
void yk_mt_control_point(YkMT *, YkLocation *);

// At each point a function containing a control point can exit "early" this
// function must be called. "Early" includes, but is not
// limited to, the following:
//
// 1. Immediately after a non-infinite loop containing a call to
// `yk_mt_control_point`.
// 2. Immediately before `return` statements in code reachable from a
// `yk_mt_control_point`.
//
// Failure to call this function will lead to undefined behaviour.
# define yk_mt_early_return(mt) __yk_mt_early_return(mt, __builtin_frame_address(0))

// This is an internal function to yk: calling it directly leads to undefined
// behaviour.
void __yk_mt_early_return(YkMT *, void *);

// Set the threshold at which `YkLocation`'s are considered hot.
void yk_mt_hot_threshold_set(YkMT *, YkHotThreshold);

Expand Down
2 changes: 1 addition & 1 deletion ykrt/src/compile/jitc_yk/codegen/x64/deopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ fn running_trace(gidxs: &[usize]) -> Arc<X64CompiledTrace> {
/// * glen - Length for list in `gptr`.
#[no_mangle]
pub(crate) extern "C" fn __yk_deopt(
frameaddr: *const c_void,
frameaddr: *mut c_void,
gidx: u64,
gp_regs: &[u64; 16],
fp_regs: &[u64; 16],
Expand Down
50 changes: 42 additions & 8 deletions ykrt/src/mt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ impl MT {
promotions,
frameaddr: tracing_frameaddr,
} => {
assert_eq!(frameaddr as *const c_void, tracing_frameaddr);
assert_eq!(frameaddr, tracing_frameaddr);
(hl, thread_tracer, promotions)
}
_ => unreachable!(),
Expand Down Expand Up @@ -492,7 +492,7 @@ impl MT {
promotions,
frameaddr: tracing_frameaddr,
} => {
assert_eq!(frameaddr as *const c_void, tracing_frameaddr);
assert_eq!(frameaddr, tracing_frameaddr);
(hl, thread_tracer, promotions)
}
_ => unreachable!(),
Expand Down Expand Up @@ -746,7 +746,7 @@ impl MT {
self: &Arc<Self>,
parent: Arc<dyn CompiledTrace>,
gidx: GuardIdx,
frameaddr: *const c_void,
frameaddr: *mut c_void,
) {
match self.transition_guard_failure(parent, gidx) {
TransitionGuardFailure::NoAction => (),
Expand All @@ -770,6 +770,40 @@ impl MT {
}
}
}

pub fn early_return(self: &Arc<Self>, frameaddr: *mut c_void) {
MTThread::with(|mtt| {
let mut abort = false;
if let MTThreadState::Tracing {
frameaddr: tracing_frameaddr,
..
} = &*mtt.tstate.borrow()
{
if frameaddr == *tracing_frameaddr {
abort = true;
}
}

if abort {
match mtt.tstate.replace(MTThreadState::Interpreting) {
MTThreadState::Tracing {
thread_tracer, hl, ..
} => {
// We don't care if the thread tracer went wrong: we're not going to use
// its result anyway.
thread_tracer.stop().unwrap();
let mut lk = hl.lock();
lk.tracecompilation_error(self);
drop(lk);
self.stats.timing_state(TimingState::None);
self.log
.log(Verbosity::JITEvent, "stop-tracing-early-return");
}
_ => unreachable!(),
}
}
});
}
}

#[cfg(target_arch = "x86_64")]
Expand Down Expand Up @@ -826,7 +860,7 @@ enum MTThreadState {
promotions: Vec<u8>,
/// The `frameaddr` when tracing started. This allows us to tell if we're finishing tracing
/// at the same point that we started.
frameaddr: *const c_void,
frameaddr: *mut c_void,
},
/// This thread is executing a trace. Note that the `dyn CompiledTrace` serves two different purposes:
///
Expand Down Expand Up @@ -1041,7 +1075,7 @@ mod tests {
hl,
thread_tracer: Box::new(DummyTraceRecorder),
promotions: Vec::new(),
frameaddr: 0 as *const c_void,
frameaddr: 0 as *mut c_void,
};
});
}
Expand All @@ -1066,7 +1100,7 @@ mod tests {
hl,
thread_tracer: Box::new(DummyTraceRecorder),
promotions: Vec::new(),
frameaddr: 0 as *const c_void,
frameaddr: 0 as *mut c_void,
};
});
}
Expand Down Expand Up @@ -1188,7 +1222,7 @@ mod tests {
hl,
thread_tracer: Box::new(DummyTraceRecorder),
promotions: Vec::new(),
frameaddr: 0 as *const c_void,
frameaddr: 0 as *mut c_void,
};
});
break;
Expand Down Expand Up @@ -1381,7 +1415,7 @@ mod tests {
hl,
thread_tracer: Box::new(DummyTraceRecorder),
promotions: Vec::new(),
frameaddr: 0 as *const c_void,
frameaddr: 0 as *mut c_void,
};
});
assert!(matches!(
Expand Down

0 comments on commit b2b96ee

Please sign in to comment.