├── .buildbot.sh ├── .buildbot_dockerfile_debian ├── .cargo └── config.toml ├── .dockerignore ├── .editorconfig ├── .github └── workflows │ └── sdci.yml ├── .gitignore ├── .gitmodules ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── bin ├── dump_ir ├── gdb_c_test └── yk-config ├── deny.toml ├── docs ├── .gitignore ├── book.toml └── src │ ├── SUMMARY.md │ ├── contributing │ └── prs.md │ ├── dev │ ├── build_config.md │ ├── debugging.md │ ├── gotchas.md │ ├── index.md │ ├── profiling.md │ ├── runtime_config.md │ └── understanding_traces.md │ ├── gotchas.md │ ├── internals │ ├── debug_testing.md │ ├── index.md │ └── working_on_yk.md │ ├── intro.md │ └── user │ ├── index.md │ ├── install.md │ └── interps.md ├── hwtracer ├── .clangd ├── .gitignore ├── Cargo.toml ├── README.md ├── build.rs ├── feature_checks │ └── linux_perf.c └── src │ ├── block.rs │ ├── errors.rs │ ├── lib.rs │ ├── llvm_blockmap.rs │ ├── perf │ ├── collect.c │ ├── collect.rs │ └── mod.rs │ └── pt │ ├── c_errors.rs │ ├── mod.rs │ └── ykpt │ ├── mod.rs │ ├── packets.rs │ └── parser.rs ├── tests ├── Cargo.toml ├── benches │ ├── collect_and_decode.c │ ├── collect_and_decode.rs │ ├── promote.c │ └── promote.rs ├── build.rs ├── c │ ├── .clang-format │ ├── .clangd │ ├── abs.c │ ├── aot_debuginfo.c │ ├── arg_mapping_callee.c │ ├── arithmetic.c │ ├── ashr_exact.c │ ├── bf.O0.c │ ├── bf.O1.c │ ├── bf.O2.c │ ├── bf.O3.c │ ├── blockmap.c │ ├── call_args.c │ ├── call_ext_in_obj.c │ ├── call_ext_simple.c │ ├── calls_double.c │ ├── choice.c │ ├── conditionals.c │ ├── connector_trace.c │ ├── const_global.c │ ├── constexpr.c │ ├── control_point_in_nested_loop.c │ ├── control_point_not_in_loop.c │ ├── double.c │ ├── doubleinline.c │ ├── dyn_ptradd_mixed.c │ ├── dyn_ptradd_multidim.c │ ├── dyn_ptradd_simple.c │ ├── early_return1.c │ ├── early_return2.c │ ├── exit_and_reenter_interploop.c │ ├── fcmp_double.c │ ├── fcmp_float.c │ ├── fcmp_float_unordered.c │ ├── fib.c │ ├── float.c │ ├── float_binop.c │ ├── float_consts.c │ ├── float_div.c │ ├── float_mul.c │ ├── float_store.c │ ├── floats.c │ ├── floats_return.c │ ├── fp_in_out.c │ ├── fp_to_si.c │ ├── funcptrarg_hasir.c │ ├── funcptrarg_noir.c │ ├── funcptrarg_pretrace.c │ ├── goto_loop.c │ ├── guard_consting.c │ ├── hl_debug.c │ ├── icmp_ptr.c │ ├── idempotent.c │ ├── idempotent_outline.c │ ├── idempotent_outline_simple.c │ ├── indirect_branch.c │ ├── indirect_call.c │ ├── indirect_external_function_call.c │ ├── inline_asm.c │ ├── inline_const.c │ ├── inst_type_depends_global.c │ ├── internal_linkage_same_obj.c │ ├── intrinsic_noinline.c │ ├── intrinsics.c │ ├── longjmp_from_foreign_into_trace1.c │ ├── longjmp_from_foreign_into_trace2.c │ ├── longjmp_within_trace_confines.c │ ├── loopy_funcs_not_inlined_by_default.c │ ├── many_threads_many_locs.c │ ├── many_threads_one_loc.c │ ├── missing_control_point.c │ ├── mutable_global.c │ ├── neg_ptradd.c │ ├── neg_ptradd_dyn.c │ ├── neg_ptradd_dyn_ptr.c │ ├── nested_execution.c │ ├── nested_sidetrace.c │ ├── nested_writetoptr.c │ ├── no_trace_annotation.c │ ├── no_trace_annotation2.c │ ├── noopts.c │ ├── not_loopy_funcs_inlined_by_default.c │ ├── outline.c │ ├── outline_promoted_ptr.c │ ├── outline_recursion.c │ ├── outline_recursion_indirect.c │ ├── peel1.c │ ├── phi1.c │ ├── phi2.c │ ├── phi3.c │ ├── promote.c │ ├── promote_expr.c │ ├── promote_guard.c │ ├── promote_many.c │ ├── pt_zero_len_call.c │ ├── pthread_create.c │ ├── ptr_global.c │ ├── ptradd.c │ ├── ptrtoint.c │ ├── qsort.c │ ├── reentrant.c │ ├── rel_path.c │ ├── resume_and_branch.c │ ├── safepoint_const.c │ ├── sdiv.c │ ├── select.c │ ├── shadow_longjmp.c │ ├── shadow_reentrant.c │ ├── side-trace.c │ ├── sidetrace_phinode.old.c │ ├── sidetrace_while.old.c │ ├── signal_handler_interrupts_trace.c │ ├── signextend_negative.c │ ├── signextend_positive.c │ ├── simple.c │ ├── simple_binop.c │ ├── simple_fprintf.c │ ├── simple_inline.c │ ├── simple_interp_loop1.c │ ├── simple_interp_loop2.c │ ├── simple_nested.c │ ├── simple_non_serialised.c │ ├── simple_peeling.c │ ├── simplecall.c │ ├── smmultisrc.c │ ├── smmultisrc2.c │ ├── srem.c │ ├── stats1.c │ ├── stats2.c │ ├── stats3.c │ ├── stats4.c │ ├── strarray.c │ ├── struct_simple.c │ ├── switch_default.c │ ├── switch_many_guards_failing.c │ ├── switch_nested_guard.c │ ├── switch_non_default.c │ ├── switch_phases.c │ ├── swt_module_clone.c │ ├── thread_local_in_trace.c │ ├── trace_too_long.c │ ├── trace_too_long_hwt.c │ ├── trace_while_executing1.c │ ├── trace_while_executing2.c │ ├── tracing_recursion1.c │ ├── truncate.c │ ├── udiv.c │ ├── uitofp.c │ ├── unintptr_t_to_ptr.c │ ├── unmapped_setjmp.c │ ├── unroll_safe_implies_noinline.c │ ├── unroll_safe_inlines.c │ ├── va_start.c │ ├── varargs.c │ ├── varargs_inlined.c │ ├── void_ret.c │ ├── yk_debug_str.c │ ├── yk_debug_str_outline.c │ ├── yk_outline_dynamic_with_promote.c │ ├── yk_unroll_safe_vs_yk_outline.c │ ├── ykd_opt_off.c │ └── zext.c ├── extra_linkage │ ├── call_me.c │ ├── fudge.s │ └── pt_zero_len_call.s ├── ir_lowering │ ├── after_alloca.ll │ ├── after_call.ll │ ├── call_operands.ll │ ├── const_floats.ll │ ├── empty.ll │ ├── func_ty.ll │ ├── gep.ll │ ├── icmp_predicates.ll │ ├── mem_access.ll │ ├── non_byte_sized_int_constant.ll │ ├── null_ptr.ll │ ├── struct.ll │ ├── unsupported_variants.ll │ ├── vararg_call.ll │ └── vararg_func_ty.ll ├── langtest_c.rs ├── langtest_ir_lowering.rs ├── langtest_lua.rs ├── lua │ ├── for_loop.lua │ ├── inline_indirect_call.lua │ ├── nested_loops.lua │ ├── recursive_function.lua │ ├── recursive_function_indirect.lua │ ├── sidetrace.lua │ ├── sidetrace_to_loop.lua │ └── while_loop.lua └── src │ ├── bin │ ├── dump_ir.rs │ └── gdb_c_test.rs │ ├── hwtracer_ykpt.rs │ └── lib.rs ├── xtask ├── Cargo.toml └── src │ └── main.rs ├── ykaddr ├── Cargo.toml ├── build.rs └── src │ ├── addr.rs │ ├── find_main.c │ ├── lib.rs │ └── obj.rs ├── ykbuild ├── Cargo.toml ├── build.rs ├── completion-wrapper └── src │ ├── completion_wrapper.rs │ └── lib.rs ├── ykcapi ├── Cargo.toml ├── build.rs ├── src │ └── lib.rs ├── yk.h └── yk_testing.h ├── ykrt ├── .gitignore ├── Cargo.toml ├── build.rs ├── src │ ├── aotsmp.rs │ ├── compile │ │ ├── guard.rs │ │ ├── jitc_yk │ │ │ ├── aot_ir.rs │ │ │ ├── arbbitint.rs │ │ │ ├── codegen │ │ │ │ ├── abs_stack.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── reg_alloc.rs │ │ │ │ └── x64 │ │ │ │ │ ├── deopt.rs │ │ │ │ │ ├── lsregalloc.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── rev_analyse.rs │ │ │ ├── gdb.rs │ │ │ ├── int_signs.rs │ │ │ ├── jit_ir │ │ │ │ ├── dead_code.rs │ │ │ │ ├── jit_ir.l │ │ │ │ ├── jit_ir.y │ │ │ │ ├── mod.rs │ │ │ │ ├── parser.rs │ │ │ │ └── well_formed.rs │ │ │ ├── mod.rs │ │ │ ├── opt │ │ │ │ ├── analyse.rs │ │ │ │ ├── heapvalues.rs │ │ │ │ ├── instll.rs │ │ │ │ └── mod.rs │ │ │ └── trace_builder.rs │ │ └── mod.rs │ ├── job_queue.rs │ ├── lib.rs │ ├── location.rs │ ├── log │ │ ├── mod.rs │ │ └── stats.rs │ ├── mt.rs │ ├── promote.rs │ ├── stack.rs │ ├── thread_intercept.rs │ └── trace │ │ ├── hwt │ │ ├── mapper.rs │ │ ├── mod.rs │ │ └── testing.rs │ │ ├── mod.rs │ │ └── swt │ │ └── mod.rs └── yk_gdb_plugin │ ├── Makefile │ └── yk_gdb_plugin.c └── yksmp ├── .gitignore ├── Cargo.toml └── src └── lib.rs /.buildbot_dockerfile_debian: -------------------------------------------------------------------------------- 1 | FROM debian:latest 2 | WORKDIR /ci 3 | RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \ 4 | --mount=target=/var/cache/apt,type=cache,sharing=locked \ 5 | rm -f /etc/apt/apt.conf.d/docker-clean && \ 6 | apt-get update && \ 7 | apt-get -y install clang-15 make curl procps file git cmake python3 \ 8 | libtinfo-dev libzip-dev mold ninja-build gdb pipx rsync && \ 9 | update-alternatives --install /usr/bin/cc cc /usr/bin/clang-15 999 && \ 10 | update-alternatives --set cc /usr/bin/clang-15 && \ 11 | update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-15 999 && \ 12 | update-alternatives --set c++ /usr/bin/clang++-15 && \ 13 | update-alternatives --install /usr/bin/ld ld /usr/bin/mold 999 && \ 14 | update-alternatives --set ld /usr/bin/mold && \ 15 | ln -sf /usr/bin/clang-15 /usr/bin/clang && \ 16 | ln -sf /usr/bin/clang++-15 /usr/bin/clang++ 17 | ARG CI_UID 18 | RUN useradd -m -u ${CI_UID} ci && chown ${CI_UID}:${CI_UID} . 19 | ARG CI_RUNNER 20 | ENV CI_RUNNER=${CI_RUNNER} 21 | COPY --chown=${CI_UID}:${CI_UID} . . 22 | CMD ["sh", "-x", ".buildbot.sh"] 23 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | xtask = "run --package xtask --" 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .gitignore -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | 7 | [*.{cpp,cc,c,h}] 8 | indent_size = 2 9 | -------------------------------------------------------------------------------- /.github/workflows/sdci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | merge_group: 4 | 5 | # This is required to silence emails about the workflow having no jobs. 6 | # We simply define a dummy job that does nothing much. 7 | jobs: 8 | dummy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - run: /usr/bin/true 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | .gdb_history 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ykllvm"] 2 | path = ykllvm 3 | url = https://github.com/ykjit/ykllvm 4 | shallow = true 5 | [submodule "tests/yklua"] 6 | path = tests/yklua 7 | url = https://github.com/ykjit/yklua 8 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Except as otherwise noted (below and/or in individual files), this project is 2 | licensed under the Apache License, Version 2.0 3 | or the MIT license 4 | , at your option. 5 | 6 | Copyright is retained by contributors and/or the organisations they 7 | represent(ed) -- this project does not require copyright assignment. Please see 8 | version control history for a full list of contributors. Note that some files 9 | may include explicit copyright and/or licensing notices. 10 | 11 | The following contributors wish to explicitly make it known that the copyright 12 | of their contributions is retained by an organisation: 13 | 14 | Edd Barrett : copyright retained by 15 | King's College London 16 | Jacob Hughes : copyright retained by 17 | King's College London 18 | Laurence Tratt : copyright retained by 19 | King's College London 20 | Lukas Diekmann : copyright retained by 21 | King's College London 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "hwtracer", 4 | "tests", 5 | "ykaddr", 6 | "ykbuild", 7 | "ykcapi", 8 | "ykrt", 9 | "yksmp", 10 | "xtask", 11 | ] 12 | resolver = "2" 13 | 14 | [profile.release-with-debug] 15 | inherits = "release" 16 | debug = true 17 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 2 | this file except in compliance with the License. You may obtain a copy of the 3 | License at 4 | 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software distributed 8 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy of 2 | this software and associated documentation files (the "Software"), to deal in 3 | the Software without restriction, including without limitation the rights to 4 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 5 | of the Software, and to permit persons to whom the Software is furnished to do 6 | so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The yk meta-tracing system. 2 | 3 | yk is a meta-tracing system. See the [yk book](https://ykjit.github.io/yk/) 4 | for more details. 5 | 6 | 7 | ## Contributors 8 | 9 | Yk is developed by a team of people listed in the 10 | [contributors page](https://github.com/softdevteam/yk/graphs/contributors). 11 | -------------------------------------------------------------------------------- /bin/dump_ir: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Wrapper around the `dump_ir` binary to make it easier to use. 4 | 5 | set -e 6 | cargo run --bin dump_ir -- $@ 7 | -------------------------------------------------------------------------------- /bin/gdb_c_test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Wrapper around the `gdb_c_test` binary to make it easier to use. 4 | 5 | set -e 6 | cargo run --bin gdb_c_test -- $@ 7 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | confidence-threshold = 1.0 3 | allow = [ 4 | "Apache-2.0", 5 | "BSD-3-Clause", 6 | "MIT", 7 | "MPL-2.0", 8 | "Unicode-3.0" 9 | ] 10 | 11 | [sources.allow-org] 12 | github = ["softdevteam"] 13 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["The Software Development Team"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Yk" 7 | -------------------------------------------------------------------------------- /docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Introduction](./intro.md) 4 | - [Using Yk](./user/index.md) 5 | - [Installation](./user/install.md) 6 | - [Available Interpreters](./user/interps.md) 7 | - [Development](./dev/index.md) 8 | - [Configuring the build](./dev/build_config.md) 9 | - [Run-time configuration](./dev/runtime_config.md) 10 | - [Debugging](./dev/debugging.md) 11 | - [Profiling](./dev/profiling.md) 12 | - [Understanding Traces](./dev/understanding_traces.md) 13 | - [Gotchas](./dev/gotchas.md) 14 | - [Internals](./internals/index.md) 15 | - [Debugging / testing](./internals/debug_testing.md) 16 | - [Working on yk](./internals/working_on_yk.md) 17 | - [Contributing]() 18 | - [Pull Requests](./contributing/prs.md) 19 | -------------------------------------------------------------------------------- /docs/src/dev/build_config.md: -------------------------------------------------------------------------------- 1 | # Configuring the build 2 | 3 | Start by following the [general installation 4 | instructions](../user/install.html#building). 5 | 6 | The `yk` repo is a Rust workspace (i.e. a collection of crates). You can build 7 | and test in the usual ways using `cargo`. For example, to build and test the 8 | system, run: 9 | 10 | ``` 11 | cargo test 12 | ``` 13 | 14 | 15 | ## `YKB_YKLLVM_BIN_DIR` 16 | 17 | Under normal circumstances, yk builds a copy of its LLVM fork "ykllvm", which 18 | it also uses it to build interpreters (via the compiler's use of `yk-config`). 19 | You can use your own ykllvm build by specifying the directory where the 20 | executables (e.g. `clang`, `llvm-config`, and so on) are stored with 21 | `YKB_YKLLVM_BIN_DIR`. 22 | 23 | yk does not check your installation for compatibility: it is your 24 | responsibility to ensure that your ykllvm build matches that expected by yk. 25 | 26 | It is also undefined behaviour to move between defining this variable and not 27 | within a repository using `yk` (including the `yk` repository itself). If you 28 | want to set/unset `YKB_YKLLVM_BIN_DIR` then `cargo clean` any repositories 29 | using `yk` before rebuilding them. 30 | 31 | ## `YKB_TRACER` 32 | 33 | The `YKB_TRACER` environment variable allows building yk with either `hwt` 34 | (Hardware Tracer) or `swt` (Software Software Tracer). 35 | 36 | `hwt` - Relies on Intel PT, suitable only for x86 CPUs supporting it. 37 | 38 | `swt` - CPU architecture-independent, but with fewer features compared to 39 | `hwt`. 40 | -------------------------------------------------------------------------------- /docs/src/dev/index.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | This section explains how to setup and use yk. 4 | -------------------------------------------------------------------------------- /docs/src/dev/understanding_traces.md: -------------------------------------------------------------------------------- 1 | # Understanding Traces 2 | 3 | yk can print the traces it has created to `stderr` to help with debugging. 4 | However, these traces are often lengthy, and not always easy to understand. 5 | This section briefly explains how to get yk to print its traces, and how 6 | to make them a bit easier to understand. 7 | 8 | 9 | ## Producing a trace 10 | 11 | ### `YKD_LOG_IR` 12 | 13 | `YKD_LOG_IR=[:][,...,]` logs IR from different stages 14 | to `path`. The special value `-` (i.e. a single dash) can be used for `` 15 | to indicate stderr. 16 | 17 | The following `ir_stage`s are supported: 18 | 19 | - `aot`: the entire AOT IR for the interpreter. 20 | - `jit-pre-opt`: the JIT IR trace before optimisation. 21 | - `jit-post-opt`: the JIT IR trace after optimisation. 22 | - `jit-asm`: the assembler code of the compiled JIT IR trace. 23 | - `jit-asm-full`: the assembler code of the compiled JIT IR trace with 24 | instruction offsets and virtual addresses annotated. 25 | -------------------------------------------------------------------------------- /docs/src/gotchas.md: -------------------------------------------------------------------------------- 1 | # Gotchas 2 | -------------------------------------------------------------------------------- /docs/src/internals/debug_testing.md: -------------------------------------------------------------------------------- 1 | # Debugging / Testing 2 | 3 | ## Compile-time features 4 | 5 | ### `yk_testing` 6 | 7 | The `yk_testing` Cargo feature is enabled whenever the `tests` crate is being 8 | compiled, so a regular `cargo build` in the root of the workspace will enable 9 | the feature (to build *without* the feature enabled, do `cargo build -p 10 | ykcapi`). 11 | 12 | 13 | ## Run-time debugging / testing features 14 | 15 | ### `YKD_SERIALISE_COMPILATION` 16 | 17 | When `YKD_SERIALISE_COMPILATION=1`, calls to `yk_control_point(loc)` will block 18 | while `loc` is being compiled. 19 | 20 | This variable is only available when building `ykrt` with the `yk_testing` 21 | Cargo feature enabled. 22 | -------------------------------------------------------------------------------- /docs/src/internals/index.md: -------------------------------------------------------------------------------- 1 | # Internals 2 | -------------------------------------------------------------------------------- /docs/src/internals/working_on_yk.md: -------------------------------------------------------------------------------- 1 | # Working on yk 2 | 3 | yk has several features designed to make it easier to work on yk itself. Most 4 | of these are transparent to the developer (e.g. rebuilding ykllvm when needed): 5 | in this page we document those that are not. 6 | 7 | 8 | ## clangd 9 | 10 | The `yk` build system generates compilation command databases for use with 11 | clangd. If you want diagnostics and/or completion in your editor (via an LSP), 12 | you will have to configure the LSP to use `clangd` (the automated build system 13 | puts a `clangd` binary into `target//ykllvm/bin` that you could 14 | use). 15 | -------------------------------------------------------------------------------- /docs/src/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This book contains documentation for the yk metatracing system. A preformatted 4 | version of this book can be found at 5 | [https://ykjit.github.io/yk/](https://ykjit.github.io/yk/). 6 | 7 | This book is written in [mdbook](https://crates.io/crates/mdbook) format. If 8 | you want to edit this book, `mdbook serve --open` runs a local server, opens a 9 | formatted version of this book in your browser, and automatically refreshes the 10 | browser when you save a markdown file after editing. 11 | 12 | 13 | ## Major components 14 | 15 | yk is a meta-tracing system that turns existing C interpreters into 16 | JIT-compiling VMs. It is comprised of two major components: 17 | 18 | 1. `ykllvm` is a fork of [LLVM](https://llvm.org/]) that must be used to: 19 | compile C interpreters with the necessary extra information for yk; link 20 | in the `yk` Rust library. 21 | 22 | 2. The `yk` Rust library is the core of the run-time JIT system. 23 | 24 | 25 | ## Terminology 26 | 27 | yk utilises two different *Intermediate Representations* (IRs): 28 | 29 | * *AOT IR* is the Ahead-Of-Time IR generated by ykllvm and embedded in the 30 | binary of a C interpreter. AOT IR is similar to LLVM IR, though customised 31 | and simplified for yk. 32 | 33 | * *JIT IR* is the IR generated (from AOT IR) at run-time by yk and which is 34 | dynamically converted into machine code. 35 | 36 | There are three styles of "trace" in yk: 37 | 38 | * When a hot loop in a program is detected, the actions of the interpreter 39 | are recorded to make an *AOT IR trace*. 40 | 41 | * The AOT IR trace is combined with AOT IR and then compiled into JIT IR to 42 | make a *JIT IR trace*. 43 | 44 | * The JIT IR trace is compiled into machine code to make an *executable trace*. 45 | -------------------------------------------------------------------------------- /docs/src/user/index.md: -------------------------------------------------------------------------------- 1 | # yk Internals 2 | -------------------------------------------------------------------------------- /docs/src/user/install.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | This section details how to get yk up and running. 4 | 5 | ## System Requirements 6 | 7 | At the time of writing, yk requires the following: 8 | 9 | - A Linux system with a CPU that supports Intel Processor Trace. 10 | (`grep intel_pt /proc/cpuinfo` to check) 11 | 12 | - Linux perf (for collecting PT traces). 13 | 14 | - A [Yk-enabled programming language interpreter](interps.md). 15 | 16 | - A recent nightly install of [Rust](https://www.rust-lang.org/). 17 | 18 | Note that at present, non-root users can only use Yk if 19 | `/proc/sys/kernel/perf_event_paranoid` is set to `-1`. 20 | 21 | 22 | ## Building 23 | 24 | Clone the [main yk repository](https://github.com/ykjit/yk) and build 25 | it with `cargo`: 26 | 27 | ```sh 28 | $ git clone --recurse-submodules --depth 1 \ 29 | https://github.com/ykjit/yk/ 30 | $ cd yk 31 | $ cargo build --release 32 | ``` 33 | 34 | Note that this will also clone [ykllvm](https://github.com/ykjit/ykllvm) as a 35 | submodule of yk. If you later want access to the full git history, either 36 | remove `--depth 1` or run `git fetch --unshallow`. 37 | -------------------------------------------------------------------------------- /docs/src/user/interps.md: -------------------------------------------------------------------------------- 1 | # Available Interpreters 2 | 3 | The following interpreters use Yk: 4 | 5 | | Interpreter | Status | 6 | | ------------------------------------------ | --------- | 7 | | [yklua](https://github.com/ykjit/yklua) | pre-alpha | 8 | | [ykcbf](https://github.com/ykjit/ykcbf) | pre-alpha | 9 | -------------------------------------------------------------------------------- /hwtracer/.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | CompilationDatabase: ../target/debug/clangd/hwtracer/ 3 | -------------------------------------------------------------------------------- /hwtracer/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | *.ptt 5 | *.map 6 | -------------------------------------------------------------------------------- /hwtracer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hwtracer" 3 | version = "0.1.0" 4 | authors = ["The Yk Developers"] 5 | edition = "2021" 6 | license = "Apache-2.0 OR MIT" 7 | 8 | [dependencies] 9 | byteorder = "1.4.3" 10 | deku = "0.18.1" 11 | intervaltree = "0.2.7" 12 | leb128 = "0.2.5" 13 | libc = "0.2.148" 14 | memmap2 = "0.9.4" 15 | strum = { version = "0.27.1", features = ["derive"] } 16 | strum_macros = "0.27.1" 17 | thiserror = "2.0.12" 18 | ykaddr = { path = "../ykaddr" } 19 | 20 | [dependencies.object] 21 | version = "0.36.7" 22 | default-features = false 23 | features = ["read_core", "elf"] 24 | 25 | [target.'cfg(target_arch = "x86_64")'.dependencies] 26 | iced-x86 = { version = "1.18.0", features = ["decoder"]} 27 | 28 | [build-dependencies] 29 | cc = "1.0.83" 30 | rerun_except = "1" 31 | ykbuild = { path = "../ykbuild" } 32 | -------------------------------------------------------------------------------- /hwtracer/README.md: -------------------------------------------------------------------------------- 1 | # hwtracer 2 | 3 | A small Rust/C library to trace sections of the current process using CPU 4 | tracing technology. 5 | 6 | This library only supports Intel Processor Trace, but in the future we hope to 7 | support alternatives such as Arm's CoreSight. 8 | 9 | **This is experimental code.** 10 | -------------------------------------------------------------------------------- /hwtracer/feature_checks/linux_perf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int check(void) { 4 | // The perf configuration struct version that first supported Intel PT. 5 | return PERF_ATTR_SIZE_VER5; 6 | } 7 | -------------------------------------------------------------------------------- /hwtracer/src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Display, Formatter}; 2 | use thiserror::Error; 3 | 4 | #[derive(Debug, Error)] 5 | pub enum HWTracerError { 6 | /// hwtracer does not support the requested configuration. Adjust the configuration and retry. 7 | #[error("Configuration error: {0}")] 8 | ConfigError(String), 9 | /// hwtracer has failed in such a way that there is no point retrying the operation. 10 | #[error("Unrecoverable error: {0}")] 11 | Unrecoverable(String), 12 | /// hwtracer has encountered a temporary error: it is possible (though not guaranteed!) that 13 | /// retrying the same operation again will succeed. 14 | #[error("Temporary error: {0}")] 15 | Temporary(TemporaryErrorKind), 16 | } 17 | 18 | #[derive(Debug)] 19 | pub enum TemporaryErrorKind { 20 | /// Memory allocation failed. 21 | CantAllocate, 22 | /// The trace buffer has overflowed. Either record a smaller trace or increase the size of the 23 | /// trace buffer. 24 | TraceBufferOverflow, 25 | /// The trace was interrupted. 26 | TraceInterrupted, 27 | /// Perf can't set itself up. 28 | PerfBusy, 29 | } 30 | 31 | impl Display for TemporaryErrorKind { 32 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 33 | match *self { 34 | TemporaryErrorKind::CantAllocate => write!(f, "Unable to allocate memory"), 35 | TemporaryErrorKind::TraceBufferOverflow => write!(f, "Trace buffer overflow"), 36 | TemporaryErrorKind::TraceInterrupted => write!(f, "Trace interrupted"), 37 | TemporaryErrorKind::PerfBusy => write!(f, "Perf busy"), 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /hwtracer/src/pt/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod c_errors; 2 | pub(crate) mod ykpt; 3 | 4 | use core::arch::x86_64::__cpuid_count; 5 | 6 | /// Checks if the CPU supports Intel Processor Trace. 7 | pub(crate) fn pt_supported() -> bool { 8 | // Check that the chip has PT capabilities. 9 | let cpuid1 = unsafe { __cpuid_count(0x7, 0x0) }; 10 | let res1 = (cpuid1.ebx & (1 << 25)) != 0; 11 | 12 | // Check that the chip supports at least one PT IP filtering range. 13 | let cpuid2 = unsafe { __cpuid_count(0x14, 0x0) }; 14 | let res2 = (cpuid2.ebx & (1 << 2)) != 0; 15 | 16 | res1 && res2 17 | } 18 | -------------------------------------------------------------------------------- /tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tests" 3 | version = "0.1.0" 4 | authors = ["The Yk Developers"] 5 | edition = "2021" 6 | license = "Apache-2.0 OR MIT" 7 | 8 | [lib] 9 | # cdylib is reuired for the `hwtracer_ykpt` suite. 10 | crate-type = ["lib", "cdylib"] 11 | 12 | [[test]] 13 | name = "c_tests" 14 | path = "langtest_c.rs" 15 | harness = false 16 | 17 | [[test]] 18 | name = "lua_tests" 19 | path = "langtest_lua.rs" 20 | harness = false 21 | 22 | [[test]] 23 | name = "ir_lowering_tests" 24 | path = "langtest_ir_lowering.rs" 25 | harness = false 26 | 27 | [dependencies] 28 | clap = { features = ["derive"], version = "4.4" } 29 | fs4 = { version="0.13.1", features=["sync"] } 30 | hwtracer = { path = "../hwtracer" } 31 | memmap2 = "0.9.4" 32 | num_cpus = "1.13.1" 33 | regex = "1.9" 34 | tempfile = "3.9.0" 35 | ykbuild = { path = "../ykbuild" } 36 | ykrt = { path = "../ykrt", features = ["yk_testing", "ykd"] } 37 | ykcapi = { path = "../ykcapi", features = ["yk_testing", "ykd"] } 38 | 39 | [dev-dependencies] 40 | criterion = { version = "0.5.1", features = ["html_reports"] } 41 | lang_tester = "0.9" 42 | 43 | [build-dependencies] 44 | rerun_except = "1.0.0" 45 | ykbuild = { path = "../ykbuild" } 46 | 47 | [[bench]] 48 | name = "collect_and_decode" 49 | harness = false 50 | 51 | [[bench]] 52 | name = "promote" 53 | harness = false 54 | -------------------------------------------------------------------------------- /tests/benches/promote.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | uint64_t inner(uint64_t a, uint64_t b, uint64_t x, uint64_t y, uint64_t z) { 9 | #ifdef DO_PROMOTE 10 | yk_promote(a); 11 | yk_promote(b); 12 | yk_promote(x); 13 | yk_promote(z); 14 | #endif 15 | y += x * 3 - z; // +1 16 | y += a - 10 * b; // no-op 17 | return y; 18 | } 19 | 20 | int main(int argc, char **argv) { 21 | if (argc != 2) { 22 | fprintf(stderr, "usage: promote \n"); 23 | exit(EXIT_FAILURE); 24 | } 25 | int reps = atoi(argv[1]); 26 | 27 | YkMT *mt = yk_mt_new(NULL); 28 | yk_mt_hot_threshold_set(mt, 0); 29 | YkLocation loc = yk_location_new(); 30 | 31 | uint64_t a = 100, b = 10, x = 1, y = 0, z = 2; 32 | NOOPT_VAL(a); 33 | NOOPT_VAL(b); 34 | NOOPT_VAL(x); 35 | NOOPT_VAL(z); 36 | 37 | for (int i = 0; i < reps; i++) { 38 | yk_mt_control_point(mt, &loc); 39 | y = inner(a, b, x, y, z); 40 | } 41 | 42 | assert(y == reps); 43 | yk_location_drop(loc); 44 | yk_mt_shutdown(mt); 45 | return (EXIT_SUCCESS); 46 | } 47 | -------------------------------------------------------------------------------- /tests/build.rs: -------------------------------------------------------------------------------- 1 | #![feature(exit_status_error)] 2 | 3 | use rerun_except::rerun_except; 4 | use std::env; 5 | 6 | pub fn main() { 7 | // Don't rebuild the whole crate when only test inputs change. 8 | rerun_except(&[ 9 | "c", 10 | "extra_linkage", 11 | "lua", 12 | "trace_compiler", 13 | "benches/*.c", 14 | "yklua", 15 | ]) 16 | .unwrap(); 17 | 18 | // Expose the cargo profile to run.rs so that it can set the right link flags. 19 | let profile = env::var("PROFILE").unwrap(); 20 | println!("cargo::rustc-cfg=cargo_profile=\"{profile}\""); 21 | println!( 22 | r#"cargo::rustc-check-cfg=cfg(cargo_profile, values("debug", "release", "release-with-debug"))"# 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /tests/c/.clang-format: -------------------------------------------------------------------------------- 1 | # Some lang_tester comment lines have to be long. 2 | ReflowComments: false 3 | -------------------------------------------------------------------------------- /tests/c/.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | CompilationDatabase: ../../target/debug/clangd/c_tests/ 3 | -------------------------------------------------------------------------------- /tests/c/abs.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // stderr: 4 | // 4: 10 10 5 | // 3: -10 10 6 | // 2: 10 10 7 | // 1: -10 10 8 | // exit 9 | 10 | // Check computing absolute values works. 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int main(int argc, char **argv) { 21 | YkMT *mt = yk_mt_new(NULL); 22 | yk_mt_hot_threshold_set(mt, 0); 23 | YkLocation loc = yk_location_new(); 24 | 25 | int i = 4; 26 | long long j = 10; 27 | NOOPT_VAL(loc); 28 | NOOPT_VAL(i); 29 | while (i > 0) { 30 | yk_mt_control_point(mt, &loc); 31 | NOOPT_VAL(j); 32 | fprintf(stderr, "%d: %lld %lld\n", i, j, llabs(j)); 33 | i--; 34 | j = -j; 35 | } 36 | fprintf(stderr, "exit\n"); 37 | yk_location_drop(loc); 38 | yk_mt_shutdown(mt); 39 | return (EXIT_SUCCESS); 40 | } 41 | -------------------------------------------------------------------------------- /tests/c/arg_mapping_callee.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 3:5 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // --- End jit-pre-opt --- 12 | // 2:5 13 | // yk-execution: enter-jit-code 14 | // 1:5 15 | // yk-execution: deoptimise 16 | // ... 17 | 18 | // Check that using an argument (of a non-main() function) in a trace works. 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int f(int x) { 27 | YkMT *mt = yk_mt_new(NULL); 28 | yk_mt_hot_threshold_set(mt, 0); 29 | YkLocation loc = yk_location_new(); 30 | 31 | int i = 3; 32 | NOOPT_VAL(i); 33 | while (i > 0) { 34 | yk_mt_control_point(mt, &loc); 35 | fprintf(stderr, "%d:%d\n", i, x); 36 | i--; 37 | } 38 | 39 | yk_location_drop(loc); 40 | yk_mt_shutdown(mt); 41 | return 0; 42 | } 43 | 44 | int main(int argc, char **argv) { 45 | f(5); 46 | return (EXIT_SUCCESS); 47 | } 48 | -------------------------------------------------------------------------------- /tests/c/arithmetic.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt,jit-post-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // add 5 10 | // sub 3 11 | // mul 12 12 | // yk-tracing: stop-tracing 13 | // --- Begin jit-pre-opt --- 14 | // ... 15 | // %{{1}}: i32 = add %{{2}}, %{{argc}} 16 | // ... 17 | // %{{3}}: i32 = sub %{{4}}, %{{argc}} 18 | // ... 19 | // --- End jit-pre-opt --- 20 | // ... 21 | // add 4 22 | // sub 2 23 | // mul 9 24 | // yk-execution: enter-jit-code 25 | // add 3 26 | // sub 1 27 | // mul 6 28 | // add 2 29 | // sub 0 30 | // mul 3 31 | // yk-execution: deoptimise 32 | // exit 33 | 34 | // Test some binary operations. 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | int main(int argc, char **argv) { 44 | YkMT *mt = yk_mt_new(NULL); 45 | yk_mt_hot_threshold_set(mt, 0); 46 | YkLocation loc = yk_location_new(); 47 | 48 | int i = 4; 49 | NOOPT_VAL(loc); 50 | NOOPT_VAL(i); 51 | while (i > 0) { 52 | yk_mt_control_point(mt, &loc); 53 | int add = i + argc; 54 | int sub = i - argc; 55 | int mul = i * argc * 3; 56 | fprintf(stderr, "add %d\n", add); 57 | fprintf(stderr, "sub %d\n", sub); 58 | fprintf(stderr, "mul %d\n", mul); 59 | i--; 60 | } 61 | fprintf(stderr, "exit\n"); 62 | yk_location_drop(loc); 63 | yk_mt_shutdown(mt); 64 | return (EXIT_SUCCESS); 65 | } 66 | -------------------------------------------------------------------------------- /tests/c/ashr_exact.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O0 -Xclang -disable-O0-optnone -Xlinker --lto-newpm-passes=instcombine 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // ashr 4 10 | // yk-tracing: stop-tracing 11 | // --- Begin jit-pre-opt --- 12 | // ... 13 | // %{{result}}: i64 = ashr %{{1}}, 2i64 14 | // ... 15 | // --- End jit-pre-opt --- 16 | // ashr 3 17 | // yk-execution: enter-jit-code 18 | // ashr 2 19 | // ashr 1 20 | // yk-execution: deoptimise 21 | // exit 22 | 23 | // Test ashr instructions with the exact keyword. 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | struct P { 34 | int *yklocs; 35 | int *code; 36 | }; 37 | 38 | int main(int argc, char **argv) { 39 | YkMT *mt = yk_mt_new(NULL); 40 | yk_mt_hot_threshold_set(mt, 0); 41 | YkLocation loc = yk_location_new(); 42 | 43 | int i = 4; 44 | struct P p; 45 | p.yklocs = malloc(sizeof(int) * 4); 46 | p.code = &p.yklocs[0]; 47 | p.yklocs[4] = 4; 48 | p.yklocs[3] = 3; 49 | p.yklocs[2] = 2; 50 | p.yklocs[1] = 1; 51 | NOOPT_VAL(loc); 52 | NOOPT_VAL(i); 53 | while (i > 0) { 54 | yk_mt_control_point(mt, &loc); 55 | int *elem = &p.yklocs[i]; 56 | int ashr = p.yklocs[elem - p.code]; 57 | fprintf(stderr, "ashr %d\n", ashr); 58 | i--; 59 | } 60 | fprintf(stderr, "exit\n"); 61 | yk_location_drop(loc); 62 | yk_mt_shutdown(mt); 63 | return (EXIT_SUCCESS); 64 | } 65 | -------------------------------------------------------------------------------- /tests/c/blockmap.c: -------------------------------------------------------------------------------- 1 | // ## The function __yktrace_hwt_mapper_blockmap_len is compile-time guarded for hwt only. 2 | // ignore-if: test "$YKB_TRACER" != "hwt" 3 | // Compiler: 4 | // Run-time: 5 | 6 | // Check the blockmap for this test program contains blocks. 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char **argv) { 15 | assert(__yktrace_hwt_mapper_blockmap_len() > 0); 16 | return (EXIT_SUCCESS); 17 | } 18 | 19 | // This isn't used as part of the test, but is required for this file to 20 | // compile with ykllvm. 21 | uint32_t unused() { 22 | YkMT *mt = yk_mt_new(NULL); 23 | YkLocation loc = yk_location_new(); 24 | while (true) { 25 | yk_mt_control_point(mt, &loc); 26 | } 27 | yk_location_drop(loc); 28 | yk_mt_shutdown(mt); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tests/c/call_args.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 3: 5 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{20}}: i32 = add %{{13}}, %{{14}} 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // 2: 5 15 | // yk-execution: enter-jit-code 16 | // 1: 5 17 | // yk-execution: deoptimise 18 | // ... 19 | 20 | // Check that function calls with arguments do the right thing 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | __attribute__((noinline)) int f(int a, int b) { 28 | int c = a + b; 29 | return c; 30 | } 31 | 32 | int main(int argc, char **argv) { 33 | YkMT *mt = yk_mt_new(NULL); 34 | yk_mt_hot_threshold_set(mt, 0); 35 | YkLocation loc = yk_location_new(); 36 | 37 | int i = 3, two = 2, three = 3; 38 | NOOPT_VAL(i); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, &loc); 41 | NOOPT_VAL(two); 42 | NOOPT_VAL(three); 43 | fprintf(stderr, "%d: %d\n", i, f(two, three)); 44 | i--; 45 | } 46 | 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | return (EXIT_SUCCESS); 50 | } 51 | -------------------------------------------------------------------------------- /tests/c/call_ext_in_obj.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 4 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // --- End jit-pre-opt --- 12 | // 3 13 | // yk-execution: enter-jit-code 14 | // 2 15 | // yk-execution: deoptimise 16 | // ... 17 | 18 | // Check that we can call a function without IR from another object (.o) file. 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | extern int call_me_add(int); 26 | 27 | int main(int argc, char **argv) { 28 | YkMT *mt = yk_mt_new(NULL); 29 | yk_mt_hot_threshold_set(mt, 0); 30 | YkLocation loc = yk_location_new(); 31 | 32 | int i = 3; 33 | NOOPT_VAL(i); 34 | while (i > 0) { 35 | yk_mt_control_point(mt, &loc); 36 | fprintf(stderr, "%d\n", call_me_add(i)); 37 | i--; 38 | } 39 | 40 | yk_location_drop(loc); 41 | yk_mt_shutdown(mt); 42 | return (EXIT_SUCCESS); 43 | } 44 | -------------------------------------------------------------------------------- /tests/c/call_ext_simple.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // stderr: 7 | // ... 8 | // func_decl putc (i32, ptr) -> i32 9 | // ... 10 | // %{{6}}: i32 = call @putc... 11 | // ... 12 | // stdout: 13 | // 12 14 | 15 | // Check that calling an external function works. 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | int main(int argc, char **argv) { 25 | YkMT *mt = yk_mt_new(NULL); 26 | yk_mt_hot_threshold_set(mt, 0); 27 | YkLocation loc = yk_location_new(); 28 | 29 | int ch = '1'; 30 | NOOPT_VAL(ch); 31 | while (ch != '3') { 32 | yk_mt_control_point(mt, &loc); 33 | // Note that sometimes the compiler will make this a call to putc(3). 34 | putchar(ch); 35 | ch++; 36 | } 37 | fflush(stdout); 38 | 39 | yk_location_drop(loc); 40 | yk_mt_shutdown(mt); 41 | return (EXIT_SUCCESS); 42 | } 43 | -------------------------------------------------------------------------------- /tests/c/calls_double.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // ... 6 | // yk-execution: enter-jit-code 7 | // res=3 8 | // ... 9 | 10 | // Check that calling the same function in sequence (but with different 11 | // arguments) works. 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | __attribute__((noinline)) int f(int a) { return a; } 19 | 20 | int main(int argc, char **argv) { 21 | YkMT *mt = yk_mt_new(NULL); 22 | yk_mt_hot_threshold_set(mt, 0); 23 | YkLocation loc = yk_location_new(); 24 | 25 | int i = 4; 26 | NOOPT_VAL(i); 27 | while (i > 0) { 28 | yk_mt_control_point(mt, &loc); 29 | int a = f(1); 30 | int b = f(2); 31 | int res = a + b; 32 | fprintf(stderr, "res=%d\n", res); 33 | i--; 34 | } 35 | 36 | yk_location_drop(loc); 37 | yk_mt_shutdown(mt); 38 | return (EXIT_SUCCESS); 39 | } 40 | -------------------------------------------------------------------------------- /tests/c/choice.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // Run-time: 3 | // env-var: YKD_LOG=4 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // stderr: 7 | // ... 8 | // yk-tracing: start-tracing 9 | // 3: 47 10 | // yk-tracing: stop-tracing 11 | // --- Begin jit-pre-opt --- 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // 2: 47 15 | // yk-execution: enter-jit-code 16 | // 1: 47 17 | // yk-execution: deoptimise 18 | // ... 19 | 20 | // Check that tracing a cascading "if...else if...else" works. 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | __attribute__((noinline)) int f(int x) { 28 | if (x == 0) 29 | return 30; 30 | else if (x == 1) 31 | return 47; 32 | else 33 | return 52; 34 | } 35 | 36 | int main(int argc, char **argv) { 37 | YkMT *mt = yk_mt_new(NULL); 38 | yk_mt_hot_threshold_set(mt, 0); 39 | YkLocation loc = yk_location_new(); 40 | 41 | int i = 3, x = 1; 42 | NOOPT_VAL(i); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | NOOPT_VAL(x); 46 | fprintf(stderr, "%d: %d\n", i, f(x)); 47 | i--; 48 | } 49 | 50 | yk_location_drop(loc); 51 | yk_mt_shutdown(mt); 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /tests/c/conditionals.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG=4 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // stderr: 5 | // ... 6 | // yk-execution: enter-jit-code 7 | // res=2 8 | // ... 9 | 10 | // Check that conditional checks work. 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int main(int argc, char **argv) { 19 | YkMT *mt = yk_mt_new(NULL); 20 | yk_mt_hot_threshold_set(mt, 0); 21 | YkLocation loc = yk_location_new(); 22 | 23 | int cond = 1, i = 4; 24 | NOOPT_VAL(i); 25 | while (i > 0) { 26 | yk_mt_control_point(mt, &loc); 27 | int res = 0; 28 | NOOPT_VAL(cond); 29 | if (cond) { 30 | res = 2; 31 | } else { 32 | res = 4; 33 | } 34 | assert(res == 2); 35 | fprintf(stderr, "res=%d\n", res); 36 | i--; 37 | } 38 | 39 | yk_location_drop(loc); 40 | yk_mt_shutdown(mt); 41 | return (EXIT_SUCCESS); 42 | } 43 | -------------------------------------------------------------------------------- /tests/c/connector_trace.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_LOG=4 4 | // env-var: YKD_SERIALISE_COMPILATION=1 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 6 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // header_end ... 12 | // --- End jit-pre-opt --- 13 | // 5 14 | // yk-tracing: start-tracing 15 | // 4 16 | // yk-tracing: stop-tracing 17 | // --- Begin jit-pre-opt --- 18 | // ... 19 | // connector ... 20 | // --- End jit-pre-opt --- 21 | // 3 22 | // yk-execution: enter-jit-code 23 | // 2 24 | // yk-execution: deoptimise 25 | // yk-tracing: start-side-tracing 26 | // yk-tracing: stop-tracing 27 | // --- Begin jit-pre-opt --- 28 | // ... 29 | // sidetrace_end ... 30 | // --- End jit-pre-opt --- 31 | // 1 32 | // exit 33 | 34 | // Test connector trace creation. 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | int main(int argc, char **argv) { 44 | YkMT *mt = yk_mt_new(NULL); 45 | yk_mt_hot_threshold_set(mt, 0); 46 | yk_mt_sidetrace_threshold_set(mt, 0); 47 | YkLocation loc1 = yk_location_new(); 48 | YkLocation loc2 = yk_location_new(); 49 | 50 | int i = 6; 51 | NOOPT_VAL(loc1); 52 | NOOPT_VAL(loc2); 53 | NOOPT_VAL(i); 54 | while (i > 0) { 55 | YkLocation *loc; 56 | if (i > 4 || i == 3) 57 | loc = &loc1; 58 | else 59 | loc = &loc2; 60 | yk_mt_control_point(mt, loc); 61 | fprintf(stderr, "%d\n", i); 62 | i--; 63 | } 64 | fprintf(stderr, "exit"); 65 | yk_location_drop(loc1); 66 | yk_location_drop(loc2); 67 | yk_mt_shutdown(mt); 68 | return (EXIT_SUCCESS); 69 | } 70 | -------------------------------------------------------------------------------- /tests/c/const_global.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=4 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{12}}: i32 = add %{{11}}, 2i32 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // i=3 15 | // yk-execution: enter-jit-code 16 | // i=2 17 | // i=1 18 | // yk-execution: deoptimise 19 | // ... 20 | 21 | // Check that using a global constant works. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | const int add = 2; 31 | 32 | int main(int argc, char **argv) { 33 | YkMT *mt = yk_mt_new(NULL); 34 | yk_mt_hot_threshold_set(mt, 0); 35 | int res = 0; 36 | YkLocation loc = yk_location_new(); 37 | int i = 4; 38 | NOOPT_VAL(res); 39 | NOOPT_VAL(i); 40 | while (i > 0) { 41 | yk_mt_control_point(mt, &loc); 42 | fprintf(stderr, "i=%d\n", i); 43 | res += add; 44 | i--; 45 | } 46 | NOOPT_VAL(res); 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | 50 | return (EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /tests/c/constexpr.c: -------------------------------------------------------------------------------- 1 | // ## -O0 doesn't make a constant expression. 2 | // ignore-if: true 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_LOG=4 6 | // env-var: YKD_SERIALISE_COMPILATION=1 7 | // stderr: 8 | // ... 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // @.str = ... 12 | // ... 13 | // define void @__yk_compiled_trace_0(... 14 | // ... 15 | // ...store i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)... 16 | // ... 17 | // --- End jit-pre-opt --- 18 | // 2:97 19 | // yk-execution: enter-jit-code 20 | // 1:97 21 | // ... 22 | 23 | // Check that global variables inside constant expressions are handled. 24 | // FIXME: needs porting to Yk IR once we find out how to get a constexpr gep. 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | const volatile int global_int = 6; 33 | 34 | __attribute__((noinline)) char foo(char *str) { 35 | NOOPT_VAL(str); 36 | // At optimisation levels >O0 this makes a constant GEP expression. 37 | return str[0]; 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | YkMT *mt = yk_mt_new(NULL); 42 | yk_mt_hot_threshold_set(mt, 0); 43 | YkLocation loc = yk_location_new(); 44 | 45 | int res = 0, i = 3; 46 | NOOPT_VAL(i); 47 | while (i > 0) { 48 | yk_mt_control_point(mt, &loc); 49 | res = foo("abc"); 50 | assert(res == 97); 51 | fprintf(stderr, "%d:%d\n", i, res); 52 | i--; 53 | } 54 | 55 | yk_location_drop(loc); 56 | yk_mt_shutdown(mt); 57 | return (EXIT_SUCCESS); 58 | } 59 | -------------------------------------------------------------------------------- /tests/c/control_point_in_nested_loop.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | 4 | // Check that the system is OK with the control point being in a nested loop. 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char **argv) { 12 | YkMT *mt = yk_mt_new(NULL); 13 | int outers = 100; 14 | int inners = 100; 15 | YkLocation loc = yk_location_null(); 16 | NOOPT_VAL(outers); 17 | NOOPT_VAL(inners); 18 | for (int i = 0; i < outers; i++) { 19 | for (int j = 0; j < inners; j++) { 20 | yk_mt_control_point(mt, &loc); // In a nested loop! 21 | } 22 | } 23 | yk_mt_shutdown(mt); 24 | return (EXIT_SUCCESS); 25 | } 26 | -------------------------------------------------------------------------------- /tests/c/control_point_not_in_loop.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // status: error 3 | // stderr: 4 | // ... 5 | // ...error: yk_mt_control_point() must be called inside a loop. 6 | // ... 7 | 8 | // Check that the system crashes if the control point is not in a loop. 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char **argv) { 15 | YkMT *mt = yk_mt_new(NULL); 16 | yk_mt_control_point(mt, NULL); // Not in a loop! 17 | yk_mt_shutdown(mt); 18 | return (EXIT_SUCCESS); 19 | } 20 | -------------------------------------------------------------------------------- /tests/c/double.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // 4 -> 4.000000 10 | // yk-tracing: stop-tracing 11 | // --- Begin aot --- 12 | // ... 13 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 14 | // ... 15 | // %{{9_3}}: double = si_to_fp %{{9_2}}, double 16 | // ... 17 | // %{{9_7}}: i32 = call fprintf(%{{_}}, @{{_}}, %{{9_2}}, %{{9_3}}) 18 | // ... 19 | // --- End aot --- 20 | // --- Begin jit-pre-opt --- 21 | // ... 22 | // %{{12}}: double = si_to_fp %{{11}} 23 | // ... 24 | // %{{_}}: i32 = call @fprintf(%{{_}}, %{{_}}, %{{11}}, %{{12}}) 25 | // ... 26 | // --- End jit-pre-opt --- 27 | // 3 -> 3.000000 28 | // yk-execution: enter-jit-code 29 | // 2 -> 2.000000 30 | // 1 -> 1.000000 31 | // yk-execution: deoptimise 32 | 33 | // Check basic 64-bit float (double) support. 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | int main(int argc, char **argv) { 43 | YkMT *mt = yk_mt_new(NULL); 44 | yk_mt_hot_threshold_set(mt, 0); 45 | YkLocation loc = yk_location_new(); 46 | 47 | int i = 4; 48 | NOOPT_VAL(loc); 49 | NOOPT_VAL(i); 50 | while (i > 0) { 51 | yk_mt_control_point(mt, &loc); 52 | fprintf(stderr, "%d -> %f\n", i, (double)i); 53 | i--; 54 | } 55 | yk_location_drop(loc); 56 | yk_mt_shutdown(mt); 57 | return (EXIT_SUCCESS); 58 | } 59 | -------------------------------------------------------------------------------- /tests/c/dyn_ptradd_mixed.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // i=4, y=7 10 | // yk-tracing: stop-tracing 11 | // --- Begin aot --- 12 | // ... 13 | // %{{9_4}}: ptr = ptr_add @line, 4 + (%{{9_3}} * 8) 14 | // ... 15 | // --- End aot --- 16 | // --- Begin jit-pre-opt --- 17 | // ... 18 | // %{{14}}: ptr = ptr_add %{{_}}, 4 19 | // %{{_}}: ptr = dyn_ptr_add %{{14}}, %{{_}}, 8 20 | // ... 21 | // --- End jit-pre-opt --- 22 | // i=3, y=6 23 | // yk-execution: enter-jit-code 24 | // i=2, y=5 25 | // i=1, y=4 26 | // yk-execution: deoptimise 27 | 28 | // Check dynamic ptradd instructions work. 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | struct point { 38 | uint32_t x; 39 | uint32_t y; 40 | }; 41 | 42 | struct point line[] = { 43 | {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, 44 | }; 45 | 46 | int main(int argc, char **argv) { 47 | YkMT *mt = yk_mt_new(NULL); 48 | yk_mt_hot_threshold_set(mt, 0); 49 | YkLocation loc = yk_location_new(); 50 | 51 | int i = 4; 52 | NOOPT_VAL(loc); 53 | NOOPT_VAL(i); 54 | while (i > 0) { 55 | yk_mt_control_point(mt, &loc); 56 | fprintf(stderr, "i=%d, y=%d\n", i, line[i].y); 57 | i--; 58 | } 59 | yk_location_drop(loc); 60 | yk_mt_shutdown(mt); 61 | return (EXIT_SUCCESS); 62 | } 63 | -------------------------------------------------------------------------------- /tests/c/dyn_ptradd_simple.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=4, elem=14 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // %{{9_4}}: ptr = ptr_add @array, 0 + (%{{9_3}} * 4) 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{_}}: ptr = dyn_ptr_add %{{_}}, %{{_}}, 4 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // i=3, elem=13 20 | // yk-execution: enter-jit-code 21 | // i=2, elem=12 22 | // i=1, elem=11 23 | // yk-execution: deoptimise 24 | 25 | // Check dynamic ptradd instructions work. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | uint32_t array[] = {10, 11, 12, 13, 14}; 35 | 36 | int main(int argc, char **argv) { 37 | YkMT *mt = yk_mt_new(NULL); 38 | yk_mt_hot_threshold_set(mt, 0); 39 | YkLocation loc = yk_location_new(); 40 | 41 | int i = 4; 42 | NOOPT_VAL(loc); 43 | NOOPT_VAL(i); 44 | while (i > 0) { 45 | yk_mt_control_point(mt, &loc); 46 | fprintf(stderr, "i=%d, elem=%d\n", i, array[i]); 47 | i--; 48 | } 49 | yk_location_drop(loc); 50 | yk_mt_shutdown(mt); 51 | return (EXIT_SUCCESS); 52 | } 53 | -------------------------------------------------------------------------------- /tests/c/early_return1.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=jit-pre-opt 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // early return 8 | // 6 9 | // yk-warning: tracing-aborted: tracing went outside of starting frame 10 | // 5 11 | // 4 12 | // yk-tracing: start-tracing 13 | // 3 14 | // yk-tracing: stop-tracing 15 | // --- Begin jit-pre-opt --- 16 | // ... 17 | // --- End jit-pre-opt --- 18 | // 2 19 | // yk-execution: enter-jit-code 20 | // 1 21 | // yk-execution: deoptimise 22 | // return 23 | // exit 24 | 25 | // Check that early return from a recursive interpreter loop aborts tracing, 26 | // but doesn't stop a location being retraced. 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | void loop(YkMT *, YkLocation *, int); 36 | 37 | void loop(YkMT *mt, YkLocation *loc, int i) { 38 | NOOPT_VAL(i); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, loc); 41 | if (i == 7) { 42 | loop(mt, loc, i - 1); 43 | i--; 44 | } else if (i == 6) { 45 | fprintf(stderr, "early return\n"); 46 | return; 47 | } 48 | fprintf(stderr, "%d\n", i); 49 | i--; 50 | } 51 | fprintf(stderr, "return\n"); 52 | return; 53 | } 54 | 55 | int main(int argc, char **argv) { 56 | YkMT *mt = yk_mt_new(NULL); 57 | yk_mt_hot_threshold_set(mt, 1); 58 | YkLocation loc = yk_location_new(); 59 | 60 | NOOPT_VAL(loc); 61 | loop(mt, &loc, 7); 62 | fprintf(stderr, "exit\n"); 63 | yk_location_drop(loc); 64 | yk_mt_shutdown(mt); 65 | return (EXIT_SUCCESS); 66 | } 67 | -------------------------------------------------------------------------------- /tests/c/exit_and_reenter_interploop.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=3 4 | // stderr: 5 | // enter 6 | // yk-tracing: start-tracing 7 | // 1 8 | // exit 9 | // enter 10 | // yk-tracing: stop-tracing 11 | // yk-warning: trace-compilation-aborted: returned from function that started tracing 12 | // ... 13 | 14 | // Check that returning from the function that started tracing, then 15 | // re-entering it and stopping tracing, causes the trace to be aborted. 16 | // 17 | // This is an interesting case because the frame address of the place we start 18 | // and stop tracing is the same, so mt.rs cannot catch this. 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | void f(YkMT *mt, YkLocation *loc, int i) { 29 | fprintf(stderr, "enter\n"); 30 | while (i > 0) { 31 | yk_mt_control_point(mt, loc); 32 | fprintf(stderr, "%d\n", i); 33 | i -= 1; 34 | } 35 | fprintf(stderr, "exit\n"); 36 | } 37 | 38 | int main(int argc, char **argv) { 39 | YkMT *mt = yk_mt_new(NULL); 40 | yk_mt_hot_threshold_set(mt, 0); 41 | YkLocation loc = yk_location_new(); 42 | int i = 1; 43 | NOOPT_VAL(loc); 44 | NOOPT_VAL(i); 45 | f(mt, &loc, i); 46 | f(mt, &loc, i); 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | return (EXIT_SUCCESS); 50 | } 51 | -------------------------------------------------------------------------------- /tests/c/fib.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 4:21 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // --- End jit-pre-opt --- 12 | // 3:21 13 | // yk-execution: enter-jit-code 14 | // 2:21 15 | // 1:21 16 | // yk-execution: deoptimise 17 | // ... 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | __attribute__((noinline)) int fib(int num) { 25 | if (num == 0) 26 | return 0; 27 | if (num == 1) 28 | return 1; 29 | if (num == 2) 30 | return 1; 31 | int a = fib(num - 2); 32 | int b = fib(num - 1); 33 | int c = a + b; 34 | return c; 35 | } 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 0); 40 | YkLocation loc = yk_location_new(); 41 | 42 | int i = 4; 43 | NOOPT_VAL(i); 44 | while (i > 0) { 45 | yk_mt_control_point(mt, &loc); 46 | NOOPT_VAL(argc); 47 | fprintf(stderr, "%d:%d\n", i, fib(argc * 8)); 48 | i--; 49 | } 50 | 51 | yk_location_drop(loc); 52 | yk_mt_shutdown(mt); 53 | return (EXIT_SUCCESS); 54 | } 55 | -------------------------------------------------------------------------------- /tests/c/float.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // 4 -> 4.000000 10 | // yk-tracing: stop-tracing 11 | // --- Begin aot --- 12 | // ... 13 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 14 | // ... 15 | // %{{9_3}}: float = si_to_fp %{{9_2}}, float 16 | // %{{9_4}}: double = fp_ext %{{9_3}}, double 17 | // ... 18 | // %{{9_7}}: i32 = call fprintf(%{{_}}, @{{_}}, %{{9_2}}, %{{9_4}}) 19 | // ... 20 | // --- End aot --- 21 | // --- Begin jit-pre-opt --- 22 | // ... 23 | // %{{12}}: float = si_to_fp %{{11}} 24 | // %{{13}}: double = fp_ext %{{12}} 25 | // ... 26 | // %{{_}}: i32 = call @fprintf(%{{_}}, %{{_}}, %{{11}}, %{{13}}) 27 | // ... 28 | // --- End jit-pre-opt --- 29 | // 3 -> 3.000000 30 | // yk-execution: enter-jit-code 31 | // 2 -> 2.000000 32 | // 1 -> 1.000000 33 | // yk-execution: deoptimise 34 | 35 | // Check basic 32-bit float support. 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | int main(int argc, char **argv) { 45 | YkMT *mt = yk_mt_new(NULL); 46 | yk_mt_hot_threshold_set(mt, 0); 47 | YkLocation loc = yk_location_new(); 48 | 49 | int i = 4; 50 | NOOPT_VAL(loc); 51 | NOOPT_VAL(i); 52 | while (i > 0) { 53 | yk_mt_control_point(mt, &loc); 54 | fprintf(stderr, "%d -> %f\n", i, (float)i); 55 | i--; 56 | } 57 | yk_location_drop(loc); 58 | yk_mt_shutdown(mt); 59 | return (EXIT_SUCCESS); 60 | } 61 | -------------------------------------------------------------------------------- /tests/c/float_consts.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 4 -> 3.350000, 4.500000 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 12 | // ... 13 | // %{{_}}: i32 = call fprintf(%{{_}}, @{{_}}, %{{_}}, 3.3499999046325684double, 4.5double) 14 | // ... 15 | // --- End aot --- 16 | // --- Begin jit-pre-opt --- 17 | // ... 18 | // %{{_}}: i32 = call @fprintf(%{{_}}, %{{_}}, %{{_}}, 3.3499999046325684double, 4.5double) 19 | // ... 20 | // --- End jit-pre-opt --- 21 | // 3 -> 3.350000, 4.500000 22 | // yk-execution: enter-jit-code 23 | // 2 -> 3.350000, 4.500000 24 | // 1 -> 3.350000, 4.500000 25 | // yk-execution: deoptimise 26 | 27 | // Check 32- and 64-bit float constants work properly. 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | int main(int argc, char **argv) { 37 | YkMT *mt = yk_mt_new(NULL); 38 | yk_mt_hot_threshold_set(mt, 0); 39 | YkLocation loc = yk_location_new(); 40 | 41 | int i = 4; 42 | NOOPT_VAL(loc); 43 | NOOPT_VAL(i); 44 | while (i > 0) { 45 | yk_mt_control_point(mt, &loc); 46 | fprintf(stderr, "%d -> %f, %f\n", i, 3.35f, 4.5); 47 | i--; 48 | } 49 | yk_location_drop(loc); 50 | yk_mt_shutdown(mt); 51 | return (EXIT_SUCCESS); 52 | } 53 | -------------------------------------------------------------------------------- /tests/c/floats.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_SERIALISE_COMPILATION=1 5 | // status: success 6 | 7 | #include 8 | #include 9 | 10 | int main(int argc, char **argv) { 11 | YkMT *mt = yk_mt_new(NULL); 12 | yk_mt_hot_threshold_set(mt, 0); 13 | float i = 0; 14 | YkLocation loc = yk_location_new(); 15 | while (i < 3) { 16 | yk_mt_control_point(mt, &loc); 17 | i += 1.0; 18 | } 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /tests/c/floats_return.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O0 -Xclang -disable-O0-optnone -Xlinker --lto-newpm-passes=instcombine 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // stdout: 7 | // 0: 4.200000 8.400000 8 | // 1: 5.200000 9.400000 9 | // 2: 6.200000 10.400000 10 | // stderr: 11 | // ... 12 | // %{{_}}: float = call @float_rtn() 13 | // ... 14 | // %{{y}}: double = call @double_rtn() 15 | // ... 16 | // %{{z}}: double = fadd %{{y}}, %{{_}} 17 | // ... 18 | // %{{_}}: i32 = call @printf(%{{_}}, %{{_}}, %{{_}}, %{{z}}) 19 | // ... 20 | 21 | #include 22 | #include 23 | 24 | __attribute__((yk_outline)) 25 | float float_rtn() { 26 | return 4.2; 27 | } 28 | 29 | __attribute__((yk_outline)) 30 | double double_rtn() { 31 | return float_rtn() * 2; 32 | } 33 | 34 | int main(int argc, char **argv) { 35 | YkMT *mt = yk_mt_new(NULL); 36 | yk_mt_hot_threshold_set(mt, 0); 37 | float i = 0; 38 | YkLocation loc = yk_location_new(); 39 | while (i < 3) { 40 | yk_mt_control_point(mt, &loc); 41 | printf("%d: %f %f\n", (int) i, float_rtn() + i, double_rtn() + i); 42 | i += 1.0; 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /tests/c/fp_in_out.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // yk-tracing: start-tracing 6 | // 5.100000 7 | // 5.200000 8 | // yk-tracing: stop-tracing 9 | // 4.100000 10 | // 4.200000 11 | // yk-execution: enter-jit-code 12 | // 3.100000 13 | // 3.200000 14 | // 2.100000 15 | // 2.200000 16 | // yk-execution: deoptimise 17 | 18 | // Check that passing floats to/from a function works correctly. 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | __attribute__((yk_outline)) 28 | float f_f(float x) { 29 | return x + 1.1; 30 | } 31 | 32 | __attribute__((yk_outline)) 33 | double f_d(double x) { 34 | return x + 1.2; 35 | } 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 0); 40 | YkLocation loc = yk_location_new(); 41 | 42 | int res = 9998; 43 | int i = 4; 44 | NOOPT_VAL(loc); 45 | NOOPT_VAL(res); 46 | NOOPT_VAL(i); 47 | while (i > 0) { 48 | yk_mt_control_point(mt, &loc); 49 | fprintf(stderr, "%f\n", f_f((float) i)); 50 | fprintf(stderr, "%f\n", f_d((double) i)); 51 | i--; 52 | } 53 | NOOPT_VAL(res); 54 | yk_location_drop(loc); 55 | yk_mt_shutdown(mt); 56 | return (EXIT_SUCCESS); 57 | } 58 | -------------------------------------------------------------------------------- /tests/c/funcptrarg_hasir.c: -------------------------------------------------------------------------------- 1 | // ## hits a todo! 2 | // ignore-if: true 3 | // Run-time: 4 | // env-var: YKD_SERIALISE_COMPILATION=1 5 | // env-var: YKD_LOG=4 6 | // stderr: 7 | // ... 8 | // FIXME: match the indirect call 9 | // yk-execution: enter-jit-code 10 | // z=4 11 | // ... 12 | 13 | // Test indirect calls where we have IR for the callee. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | __attribute__((noinline)) int foo(int a) { 22 | NOOPT_VAL(a); 23 | return a + 1; 24 | } 25 | 26 | int bar(int (*func)(int)) { 27 | int a = func(3); 28 | return a; 29 | } 30 | 31 | int main(int argc, char **argv) { 32 | YkMT *mt = yk_mt_new(NULL); 33 | yk_mt_hot_threshold_set(mt, 0); 34 | YkLocation loc = yk_location_new(); 35 | 36 | int z = 0, i = 4; 37 | NOOPT_VAL(i); 38 | NOOPT_VAL(z); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, &loc); 41 | z = bar(foo); 42 | assert(z == 4); 43 | fprintf(stderr, "z=%d\n", z); 44 | i--; 45 | } 46 | 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | return (EXIT_SUCCESS); 50 | } 51 | -------------------------------------------------------------------------------- /tests/c/funcptrarg_noir.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=jit-pre-opt 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // z=3 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{17}}: i64 = icall %{{8}}(%{{16}}) 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // z=3 15 | // yk-execution: enter-jit-code 16 | // z=3 17 | // yk-execution: deoptimise 18 | 19 | // Test indirect calls where we don't have IR for the callee. 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | int bar(size_t (*func)(const char *)) { 29 | int a = func("abc"); 30 | return a; 31 | } 32 | 33 | int main(int argc, char **argv) { 34 | YkMT *mt = yk_mt_new(NULL); 35 | yk_mt_hot_threshold_set(mt, 0); 36 | YkLocation loc = yk_location_new(); 37 | 38 | int z = 0, i = 3; 39 | size_t (*f)(const char *) = strlen; 40 | NOOPT_VAL(i); 41 | NOOPT_VAL(z); 42 | NOOPT_VAL(f); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | z = bar(f); 46 | fprintf(stderr, "z=%d\n", z); 47 | i--; 48 | } 49 | NOOPT_VAL(z); 50 | assert(z == 3); 51 | 52 | yk_location_drop(loc); 53 | yk_mt_shutdown(mt); 54 | return (EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /tests/c/funcptrarg_pretrace.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=jit-pre-opt 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // ... 7 | // --- Begin jit-pre-opt --- 8 | // ... 9 | // --- End jit-pre-opt --- 10 | // ... 11 | 12 | // Test that indirect calls are only copied to the JITModule after we have seen 13 | // `start_tracing`. Since indirect calls are handled before our regular 14 | // are-we-tracing-yet check, and require an additional check, it makes sense to 15 | // test for this here. 16 | // 17 | // FIXME: since lang_tester cannot do negative matching, we can't check for the 18 | // absence of the indirect call. For now we are only checking that nothing 19 | // crashes. 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | int bar(size_t (*func)(const char *)) { 29 | YkMT *mt = yk_mt_new(NULL); 30 | yk_mt_hot_threshold_set(mt, 0); 31 | YkLocation loc = yk_location_new(); 32 | 33 | size_t pre = func("abc"); 34 | int i = 2; 35 | NOOPT_VAL(pre); 36 | NOOPT_VAL(i); 37 | while (i > 0) { 38 | yk_mt_control_point(mt, &loc); 39 | i--; 40 | } 41 | 42 | yk_location_drop(loc); 43 | yk_mt_shutdown(mt); 44 | return pre; 45 | } 46 | 47 | int main(int argc, char **argv) { 48 | int res = 0; 49 | res = bar(strlen); 50 | assert(res == 3); 51 | 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /tests/c/goto_loop.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // stdout: 1000 3 | // stderr: 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char **argv) { 12 | YkMT *mt = yk_mt_new(NULL); 13 | yk_mt_hot_threshold_set(mt, 0); 14 | YkLocation loc = yk_location_new(); 15 | 16 | int i = 0; 17 | NOOPT_VAL(i); 18 | loop: 19 | yk_mt_control_point(mt, &loc); 20 | if (i < 1000) { 21 | i++; 22 | goto loop; 23 | } 24 | printf("%d", i); 25 | yk_location_drop(loc); 26 | yk_mt_shutdown(mt); 27 | return (EXIT_SUCCESS); 28 | } 29 | -------------------------------------------------------------------------------- /tests/c/guard_consting.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // stderr: 5 | // ... 6 | // %{{30}}: i1 = sgt %{{_}}, 0i32 7 | // guard true, %{{22}}, [{{0}}:%{{0_8}}: %{{0}}, {{0}}:%{{0_9}}: %{{1}}, {{0}}:%{{0_10}}: %{{2}}, {{0}}:%{{0_11}}: %{{3}}, {{0}}:%{{9_1}}: 0i1] ; ... 8 | // ... 9 | 10 | // Check that if a guard's life variables include the condition operand, that 11 | // is converted to a constant. 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int main(int argc, char **argv) { 21 | YkMT *mt = yk_mt_new(NULL); 22 | yk_mt_hot_threshold_set(mt, 0); 23 | yk_mt_sidetrace_threshold_set(mt, 5); 24 | YkLocation loc = yk_location_new(); 25 | 26 | int res = 0; 27 | int i = 20; 28 | NOOPT_VAL(loc); 29 | NOOPT_VAL(res); 30 | NOOPT_VAL(i); 31 | while (i > 0) { 32 | yk_mt_control_point(mt, &loc); 33 | if (i % 2 == 0) 34 | res += 1; 35 | else 36 | res += i; 37 | fprintf(stderr, "%d\n", res); 38 | i--; 39 | } 40 | NOOPT_VAL(res); 41 | printf("%d\n", res); 42 | yk_location_drop(loc); 43 | yk_mt_shutdown(mt); 44 | return (EXIT_SUCCESS); 45 | } 46 | -------------------------------------------------------------------------------- /tests/c/hl_debug.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=3 4 | // stderr: 5 | // yk-tracing: start-tracing: somefile.lua:1234: for i = 0, 10 do 6 | // 4 7 | // 3 8 | // yk-tracing: stop-tracing: somefile.lua:1234: for i = 0, 10 do 9 | // 2 10 | // yk-tracing: start-tracing: someotherfile.lua:5678: while j < 1000 11 | // 1 12 | // exit 13 | 14 | // Check that basic trace compilation works. 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | int main(int argc, char **argv) { 24 | YkMT *mt = yk_mt_new(NULL); 25 | yk_mt_hot_threshold_set(mt, 0); 26 | 27 | YkLocation loc1 = yk_location_new(); 28 | yk_location_set_debug_str(&loc1, "somefile.lua:1234: for i = 0, 10 do"); 29 | 30 | YkLocation loc2 = yk_location_new(); 31 | yk_location_set_debug_str(&loc2, "someotherfile.lua:5678: while j < 1000"); 32 | 33 | int i = 4; 34 | NOOPT_VAL(i); 35 | while (i > 0) { 36 | YkLocation *loc = i % 2 == 0 ? &loc1 : &loc2; 37 | yk_mt_control_point(mt, loc); 38 | fprintf(stderr, "%d\n", i); 39 | i--; 40 | } 41 | fprintf(stderr, "exit\n"); 42 | yk_location_drop(loc1); 43 | yk_location_drop(loc2); 44 | yk_mt_shutdown(mt); 45 | return (EXIT_SUCCESS); 46 | } 47 | -------------------------------------------------------------------------------- /tests/c/icmp_ptr.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // ... 6 | // yk-execution: enter-jit-code 7 | // p1==p2: 1, p2==p3: 0 8 | // p1==p2: 1, p2==p3: 0 9 | // yk-execution: deoptimise 10 | // ... 11 | // 12 | 13 | // Check that pointer comparisons work. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) { 23 | YkMT *mt = yk_mt_new(NULL); 24 | yk_mt_hot_threshold_set(mt, 0); 25 | YkLocation loc = yk_location_new(); 26 | 27 | int i = 0, j = 0; 28 | int *p1 = &i, *p2 = &i, *p3 = &j; 29 | NOOPT_VAL(loc); 30 | NOOPT_VAL(i); 31 | NOOPT_VAL(j); 32 | NOOPT_VAL(p1); 33 | NOOPT_VAL(p2); 34 | NOOPT_VAL(p3); 35 | while (i < 4) { 36 | yk_mt_control_point(mt, &loc); 37 | fprintf(stderr, "p1==p2: %d, p2==p3: %d\n", p1 == p2, p2 == p3); 38 | i++; 39 | } 40 | yk_location_drop(loc); 41 | yk_mt_shutdown(mt); 42 | return (EXIT_SUCCESS); 43 | } 44 | -------------------------------------------------------------------------------- /tests/c/indirect_branch.c: -------------------------------------------------------------------------------- 1 | // ## crashes ykllvm's BlockDisambiguate pass. 2 | // ignore-if: true 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_LOG=3 6 | // stderr: 7 | // FIXME: match some IR/output 8 | // ... 9 | 10 | // Check that tracing an `indirectbr` works. 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main(int argc, char **argv) { 20 | YkMT *mt = yk_mt_new(NULL); 21 | YkLocation loc = yk_location_new(); 22 | int i = 5; 23 | int idx = 1; 24 | void *dispatch[] = {&&label1, &&label3, &&label2}; 25 | NOOPT_VAL(i); 26 | NOOPT_VAL(idx); 27 | while (i > 0) { 28 | yk_mt_control_point(mt, &loc); 29 | fprintf(stderr, "i=%d\n", i); 30 | goto *dispatch[idx]; 31 | label1: 32 | abort(); // unreachable. 33 | label2: 34 | abort(); // unreachable. 35 | label3: 36 | i--; 37 | } 38 | abort(); // FIXME: unreachable due to aborting guard failure earlier. 39 | 40 | return (EXIT_SUCCESS); 41 | } 42 | -------------------------------------------------------------------------------- /tests/c/indirect_call.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // foo 7 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{1}}: i32 = icall %{{2}}(%{{3}}) 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // foo 6 15 | // yk-execution: enter-jit-code 16 | // foo 5 17 | // foo 4 18 | // yk-execution: deoptimise 19 | // exit 20 | 21 | // Check that indirect calls work. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | __attribute__((noinline)) int foo(int i) { return i + 3; } 31 | 32 | int main(int argc, char **argv) { 33 | YkMT *mt = yk_mt_new(NULL); 34 | yk_mt_hot_threshold_set(mt, 0); 35 | YkLocation loc = yk_location_new(); 36 | 37 | int i = 4; 38 | int (*fn)(int) = foo; 39 | 40 | NOOPT_VAL(loc); 41 | NOOPT_VAL(i); 42 | NOOPT_VAL(fn); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | int x = fn(i); 46 | fprintf(stderr, "foo %d\n", x); 47 | i--; 48 | } 49 | fprintf(stderr, "exit\n"); 50 | yk_location_drop(loc); 51 | yk_mt_shutdown(mt); 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /tests/c/indirect_external_function_call.c: -------------------------------------------------------------------------------- 1 | // ## Hits a todo! 2 | // ignore-if: true 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 5 | // env-var: YKD_LOG=3 6 | // env-var: YKD_SERIALISE_COMPILATION=1 7 | // stdout: 8 | // 205 9 | // FIXME: match some IR/events 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // external function 19 | int call_callback(int (*callback)(int, int), int x, int y); 20 | 21 | // callbacks 22 | int add(int a, int b) { return a + b; } 23 | int mul(int a, int b) { return a * b; } 24 | 25 | int main(int argc, char **argv) { 26 | int i = 0; 27 | YkMT *mt = yk_mt_new(NULL); 28 | yk_mt_hot_threshold_set(mt, 0); 29 | YkLocation loc = yk_location_new(); 30 | int result = 0; 31 | while (i < 10) { 32 | yk_mt_control_point(mt, &loc); 33 | if (i % 2 == 0) { 34 | result += call_callback(add, i, i); 35 | } else { 36 | result += call_callback(mul, i, i); 37 | } 38 | i++; 39 | } 40 | printf("%d", result); 41 | yk_location_drop(loc); 42 | yk_mt_shutdown(mt); 43 | return (EXIT_SUCCESS); 44 | } 45 | -------------------------------------------------------------------------------- /tests/c/inline_asm.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // status: error 6 | 7 | // Check that we can handle inline asm properly (currently expectely fails 8 | // until we can deal with calls inside inline asm). 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char **argv) { 16 | 17 | YkMT *mt = yk_mt_new(NULL); 18 | yk_mt_hot_threshold_set(mt, 0); 19 | YkLocation loc = yk_location_new(); 20 | 21 | int res = 0; 22 | int i = 4; 23 | NOOPT_VAL(i); 24 | NOOPT_VAL(res); 25 | while (i > 0) { 26 | yk_mt_control_point(mt, &loc); 27 | #ifdef __x86_64__ 28 | // Stores the constant 5 into `res`. 29 | asm("mov $5, %0" 30 | : "=r"(res) // outputs. 31 | : // inputs. 32 | : // clobbers. 33 | ); 34 | fprintf(stderr, "res=%d\n", res); 35 | #else 36 | #error unknown platform 37 | #endif 38 | i--; 39 | } 40 | 41 | assert(res == 5); 42 | yk_location_drop(loc); 43 | yk_mt_shutdown(mt); 44 | return (EXIT_SUCCESS); 45 | } 46 | -------------------------------------------------------------------------------- /tests/c/inline_const.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // foo 3 10 | // yk-tracing: stop-tracing 11 | // --- Begin jit-pre-opt --- 12 | // ... 13 | // %{{2}}: i32 = call @fprintf(%{{3}}, %{{4}}, 3i32) 14 | // ... 15 | // --- End jit-pre-opt --- 16 | // foo 3 17 | // yk-execution: enter-jit-code 18 | // foo 3 19 | // foo 3 20 | // yk-execution: deoptimise 21 | // exit 22 | 23 | // Check that constant return values of functions inlined into a trace are 24 | // properly mapped. 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | __attribute__((noinline)) int foo(int i) { return 3; } 34 | 35 | int main(int argc, char **argv) { 36 | YkMT *mt = yk_mt_new(NULL); 37 | yk_mt_hot_threshold_set(mt, 0); 38 | YkLocation loc = yk_location_new(); 39 | 40 | int i = 4; 41 | NOOPT_VAL(loc); 42 | NOOPT_VAL(i); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | int x = foo(i); 46 | fprintf(stderr, "foo %d\n", x); 47 | i--; 48 | } 49 | fprintf(stderr, "exit\n"); 50 | yk_location_drop(loc); 51 | yk_mt_shutdown(mt); 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /tests/c/inst_type_depends_global.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O0 -Xclang -disable-O0-optnone -Xlinker --lto-newpm-passes=instcombine 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=3 7 | // stderr: 8 | // ... 9 | // --- Begin aot --- 10 | // ... 11 | // %{{_}}: ptr = phi bb{{_}} -> @global1, bb{{_}} -> @global2 12 | // ... 13 | // --- End aot --- 14 | // ... 15 | 16 | // Check that we can print and AOT IR instruction that requires asking the 17 | // type of a global variable. 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int global1 = 2000; 27 | int global2 = 3000; 28 | 29 | int main(int argc, char **argv) { 30 | YkMT *mt = yk_mt_new(NULL); 31 | yk_mt_hot_threshold_set(mt, 0); 32 | YkLocation loc = yk_location_new(); 33 | 34 | int i = 4; 35 | NOOPT_VAL(loc); 36 | while (i > 0) { 37 | yk_mt_control_point(mt, &loc); 38 | NOOPT_VAL(i); 39 | // makes a `phi` instruction whose type is determined by asking the type 40 | // of a global variable. 41 | int x = i % 2 == 0 ? global1 : global2; 42 | fprintf(stderr, "%i: %d\n", i, x); 43 | i--; 44 | } 45 | yk_location_drop(loc); 46 | yk_mt_shutdown(mt); 47 | return (EXIT_SUCCESS); 48 | } 49 | -------------------------------------------------------------------------------- /tests/c/internal_linkage_same_obj.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // x=0 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{12}}: i32 = call @call_me(%{{8}}) 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // ... 15 | // yk-execution: enter-jit-code 16 | // x=0 17 | // x=0 18 | // yk-execution: deoptimise 19 | 20 | // Check that we can call a static function with internal linkage from the same 21 | // compilation unit. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | __attribute__((noinline, yk_outline)) static int call_me(int x) { 29 | NOOPT_VAL(x); 30 | if (x == 5) 31 | return 1; 32 | else 33 | return 0; 34 | } 35 | 36 | int main(int argc, char **argv) { 37 | YkMT *mt = yk_mt_new(NULL); 38 | yk_mt_hot_threshold_set(mt, 0); 39 | YkLocation loc = yk_location_new(); 40 | 41 | int x = 999, i = 4; 42 | NOOPT_VAL(i); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | x = call_me(argc); 46 | fprintf(stderr, "x=%d\n", x); 47 | i--; 48 | } 49 | assert(x == 0); 50 | 51 | yk_location_drop(loc); 52 | yk_mt_shutdown(mt); 53 | return (EXIT_SUCCESS); 54 | } 55 | -------------------------------------------------------------------------------- /tests/c/intrinsic_noinline.c: -------------------------------------------------------------------------------- 1 | // ## Hits a todo! 2 | // ignore-if: true 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // yk-tracing: stop-tracing 10 | // --- Begin jit-pre-opt --- 11 | // ... 12 | // define ptr @__yk_compiled_trace_0(ptr %0, ptr %1... 13 | // ... 14 | // call void @llvm.memcpy... 15 | // ... 16 | // } 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // yk-execution: enter-jit-code 20 | // ... 21 | // yk-execution: deoptimise 22 | // ... 23 | // stdout: 24 | // 3 25 | 26 | // Check that intrinsics that aren't inlined are handled correctly. 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | int main(int argc, char **argv) { 36 | int res[100]; 37 | int src[100]; 38 | // Make the array big enough so that the memcpy won't get inlined by the 39 | // compiler. 40 | for (int i = 0; i < 100; i++) { 41 | src[i] = argc * i; 42 | } 43 | YkMT *mt = yk_mt_new(NULL); 44 | yk_mt_hot_threshold_set(mt, 0); 45 | YkLocation loc = yk_location_new(); 46 | int i = 5; 47 | NOOPT_VAL(res); 48 | NOOPT_VAL(i); 49 | NOOPT_VAL(src); 50 | while (i > 0) { 51 | yk_mt_control_point(mt, &loc); 52 | // Add observable effect to check the trace executes this memcpy. 53 | src[0] = i * 3; 54 | memcpy(&res, &src, sizeof(int) * 100); 55 | i--; 56 | } 57 | NOOPT_VAL(res); 58 | printf("%d", res[0]); 59 | yk_location_drop(loc); 60 | yk_mt_shutdown(mt); 61 | 62 | return (EXIT_SUCCESS); 63 | } 64 | -------------------------------------------------------------------------------- /tests/c/intrinsics.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O0 -Xclang -disable-O0-optnone -Xlinker --lto-newpm-passes=instcombine 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // yk-tracing: stop-tracing 10 | // --- Begin jit-pre-opt --- 11 | // ... 12 | // --- End jit-pre-opt --- 13 | // yk-execution: enter-jit-code 14 | // ... 15 | // yk-execution: deoptimise 16 | // ... 17 | // stdout: 18 | // 998 19 | 20 | // Check that inlined intrinsics are handled correctly. 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | int main(int argc, char **argv) { 30 | int res = 0; 31 | int src = 1000; 32 | YkMT *mt = yk_mt_new(NULL); 33 | yk_mt_hot_threshold_set(mt, 0); 34 | YkLocation loc = yk_location_new(); 35 | int i = 3; 36 | NOOPT_VAL(res); 37 | NOOPT_VAL(i); 38 | NOOPT_VAL(src); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, &loc); 41 | memcpy(&res, &src, 4); 42 | src--; 43 | i--; 44 | } 45 | NOOPT_VAL(res); 46 | printf("%d", res); 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | 50 | return (EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /tests/c/longjmp_from_foreign_into_trace1.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // we jumped 8 | // yk-tracing: stop-tracing 9 | // yk-warning: trace-compilation-aborted: irregular control flow detected 10 | // ... 11 | 12 | // Tests that we can deal with setjmp/longjmp when we jump from foreign code 13 | // into a different place in the function that started outlining. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | jmp_buf buf; 24 | 25 | // By annotating this `yk_outline` we don't serialise its IR and therefore 26 | // can't see the `longjmp` inside. The tracebuilder is expected to notice the 27 | // "odd" control flow that results. 28 | __attribute__((noinline, yk_outline)) 29 | void ljmp() { 30 | longjmp(buf, 1); 31 | } 32 | 33 | int main(int argc, char **argv) { 34 | YkMT *mt = yk_mt_new(NULL); 35 | yk_mt_hot_threshold_set(mt, 0); 36 | YkLocation loc = yk_location_new(); 37 | 38 | int i = 2; 39 | NOOPT_VAL(loc); 40 | NOOPT_VAL(i); 41 | if (setjmp(buf) != 0) { 42 | fprintf(stderr, "we jumped\n"); 43 | } 44 | while (i > 0) { 45 | i--; 46 | yk_mt_control_point(mt, &loc); 47 | ljmp(); 48 | fprintf(stderr, "i=%d\n", i); 49 | } 50 | printf("exit"); 51 | yk_location_drop(loc); 52 | yk_mt_shutdown(mt); 53 | return (EXIT_SUCCESS); 54 | } 55 | -------------------------------------------------------------------------------- /tests/c/longjmp_from_foreign_into_trace2.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // we jumped 8 | // yk-tracing: stop-tracing 9 | // yk-warning: trace-compilation-aborted: irregular control flow detected 10 | // we jumped 11 | // exit 12 | // ... 13 | 14 | // Tests that we can deal with setjmp/longjmp when we jump from foreign code 15 | // into a different function than started outlining. 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | jmp_buf buf; 25 | 26 | // By annotating this `yk_outline` we don't serialise its IR and therefore 27 | // can't see the `longjmp` inside. The tracebuilder is expected to notice the 28 | // "odd" control flow that results. 29 | __attribute__((noinline, yk_outline)) 30 | void ljmp() { 31 | longjmp(buf, 1); 32 | } 33 | 34 | __attribute__((noinline)) 35 | void inner() { 36 | ljmp(); 37 | } 38 | 39 | int main(int argc, char **argv) { 40 | YkMT *mt = yk_mt_new(NULL); 41 | yk_mt_hot_threshold_set(mt, 0); 42 | YkLocation loc = yk_location_new(); 43 | 44 | int i = 2; 45 | NOOPT_VAL(loc); 46 | NOOPT_VAL(i); 47 | if (setjmp(buf) != 0) { 48 | fprintf(stderr, "we jumped\n"); 49 | } 50 | while (i > 0) { 51 | i--; 52 | yk_mt_control_point(mt, &loc); 53 | inner(); 54 | fprintf(stderr, "unreachable\n"); 55 | } 56 | fprintf(stderr, "exit"); 57 | yk_location_drop(loc); 58 | yk_mt_shutdown(mt); 59 | return (EXIT_SUCCESS); 60 | } 61 | -------------------------------------------------------------------------------- /tests/c/longjmp_within_trace_confines.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // i=3 7 | // after setjmp 8 | // after setjmp 9 | // yk-tracing: start-tracing 10 | // i=2 11 | // after setjmp 12 | // after setjmp 13 | // yk-tracing: stop-tracing 14 | // yk-warning: trace-compilation-aborted: irregular control flow detected 15 | // i=1 16 | // after setjmp 17 | // after setjmp 18 | // exit 19 | 20 | // Check that something sensible happens when there's a longjmp within the 21 | // confines of the trace. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | int main(int argc, char **argv) { 31 | YkMT *mt = yk_mt_new(NULL); 32 | yk_mt_hot_threshold_set(mt, 1); 33 | YkLocation loc = yk_location_new(); 34 | jmp_buf buf; 35 | 36 | int i = 3; 37 | NOOPT_VAL(loc); 38 | NOOPT_VAL(i); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, &loc); 41 | fprintf(stderr, "i=%d\n", i); 42 | 43 | int r = setjmp(buf); 44 | fprintf(stderr, "after setjmp\n"); 45 | 46 | if (r == 0) { 47 | longjmp(buf, 1); 48 | fprintf(stderr, "we jumped\n"); 49 | } 50 | i--; 51 | } 52 | fprintf(stderr, "exit"); 53 | yk_location_drop(loc); 54 | yk_mt_shutdown(mt); 55 | return (EXIT_SUCCESS); 56 | } 57 | -------------------------------------------------------------------------------- /tests/c/loopy_funcs_not_inlined_by_default.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 4 | // stderr: 5 | // --- Begin aot --- 6 | // ... 7 | // func main(... 8 | // ... 9 | // call never_inline_into_trace(%{{9_0}})... 10 | // ... 11 | // } 12 | // ... 13 | // --- End aot --- 14 | // ... 15 | // --- Begin jit-pre-opt --- 16 | // ... 17 | // call @never_inline_into_trace(%{{6}}) 18 | // ... 19 | // --- End jit-pre-opt --- 20 | 21 | // Check a loopy function that is NOT annotated `yk_unroll_safe`: 22 | // - never gets linlined during AOT compilation. 23 | // - never gets inlined into the trace. 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int call_me(int x); // from extra_linkage/call_me.c 34 | 35 | // A function containing a loop, not marked `yk_unroll_safe`. 36 | void never_inline_into_trace(int x) { 37 | while (x--) 38 | call_me(x); 39 | } 40 | 41 | int main(int argc, char **argv) { 42 | YkMT *mt = yk_mt_new(NULL); 43 | yk_mt_hot_threshold_set(mt, 0); 44 | YkLocation loc = yk_location_new(); 45 | 46 | int i = 4; 47 | NOOPT_VAL(loc); 48 | NOOPT_VAL(i); 49 | while (i > 0) { 50 | yk_mt_control_point(mt, &loc); 51 | never_inline_into_trace(i); 52 | i--; 53 | } 54 | yk_location_drop(loc); 55 | yk_mt_shutdown(mt); 56 | return (EXIT_SUCCESS); 57 | } 58 | -------------------------------------------------------------------------------- /tests/c/missing_control_point.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // status: success 3 | // stderr: 4 | // ... 5 | // ...warning: ykllvm couldn't find the call to `yk_mt_control_point()` 6 | // ... 7 | 8 | // Check that the ykllvm warns if the control point is missing. 9 | 10 | #include 11 | 12 | int main(int argc, char **argv) { 13 | // Control point is missing! 14 | return (EXIT_SUCCESS); 15 | } 16 | -------------------------------------------------------------------------------- /tests/c/mutable_global.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=4, g=1000 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ..~ 11 | // %{{14}}: ptr = lookup_global @g 12 | // %{{15}}: i32 = load %{{14}} 13 | // %{{16}}: i32 = add %{{15}}, 5i32 14 | // ... 15 | // --- End jit-pre-opt --- 16 | // i=3, g=1005 17 | // yk-execution: enter-jit-code 18 | // i=2, g=1010 19 | // i=1, g=1015 20 | // yk-execution: deoptimise 21 | // ... 22 | 23 | // Check that mutating a global works. 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | int g = 1000; 33 | 34 | int main(int argc, char **argv) { 35 | YkMT *mt = yk_mt_new(NULL); 36 | yk_mt_hot_threshold_set(mt, 0); 37 | YkLocation loc = yk_location_new(); 38 | int i = 4; 39 | NOOPT_VAL(i); 40 | while (i > 0) { 41 | yk_mt_control_point(mt, &loc); 42 | NOOPT_VAL(g); 43 | fprintf(stderr, "i=%d, g=%d\n", i, g); 44 | g += 5; 45 | i--; 46 | } 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | 50 | return (EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /tests/c/neg_ptradd.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=9 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // %{{14_2}}: ptr = ptr_add %{{14_1}}, -{{4}} 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{14}}: ptr = ptr_add %{{13}}, -{{4i32}} 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // i=9 20 | // yk-execution: enter-jit-code 21 | // i=9 22 | // i=9 23 | // yk-execution: deoptimise 24 | 25 | // Check that basic trace compilation works. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | int main(int argc, char **argv) { 35 | YkMT *mt = yk_mt_new(NULL); 36 | yk_mt_hot_threshold_set(mt, 0); 37 | YkLocation loc = yk_location_new(); 38 | 39 | int arr[300]; 40 | for (int x = 0; x < 300; x++) { 41 | arr[x] = x; 42 | } 43 | 44 | int i = 0; 45 | int *ptr = &arr[10]; 46 | NOOPT_VAL(loc); 47 | NOOPT_VAL(i); 48 | while (i < 4) { 49 | yk_mt_control_point(mt, &loc); 50 | NOOPT_VAL(ptr); 51 | fprintf(stderr, "i=%d\n", ptr[-1]); 52 | i++; 53 | } 54 | yk_location_drop(loc); 55 | yk_mt_shutdown(mt); 56 | return (EXIT_SUCCESS); 57 | } 58 | -------------------------------------------------------------------------------- /tests/c/neg_ptradd_dyn.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=9 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // %{{15_4}}: ptr = ptr_add %{{15_1}}, 0 + (%{{15_3}} * {{4}}) 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{_}}: ptr = dyn_ptr_add %{{_}}, %{{_}}, {{4}} 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // i=9 20 | // yk-execution: enter-jit-code 21 | // i=9 22 | // i=9 23 | // yk-execution: deoptimise 24 | 25 | // Check that basic trace compilation works. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | int main(int argc, char **argv) { 35 | YkMT *mt = yk_mt_new(NULL); 36 | yk_mt_hot_threshold_set(mt, 0); 37 | YkLocation loc = yk_location_new(); 38 | 39 | int arr[300]; 40 | for (int x = 0; x < 300; x++) { 41 | arr[x] = x; 42 | } 43 | 44 | int i = 0; 45 | int *ptr = &arr[10]; 46 | int minus1 = -1; 47 | NOOPT_VAL(loc); 48 | NOOPT_VAL(i); 49 | while (i < 4) { 50 | yk_mt_control_point(mt, &loc); 51 | NOOPT_VAL(ptr); 52 | NOOPT_VAL(minus1); 53 | fprintf(stderr, "i=%d\n", ptr[minus1]); 54 | i++; 55 | } 56 | yk_location_drop(loc); 57 | yk_mt_shutdown(mt); 58 | return (EXIT_SUCCESS); 59 | } 60 | -------------------------------------------------------------------------------- /tests/c/neg_ptradd_dyn_ptr.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=0, deref=9 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // %{{15_3}}: ptr = ptr_add %{{15_1}}, 0 + (%{{15_2}} * {{4}}) 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{_}}: ptr = dyn_ptr_add %{{_}}, %{{_}}, 4 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // i=1, deref=8 20 | // yk-execution: enter-jit-code 21 | // i=2, deref=7 22 | // i=3, deref=6 23 | // yk-execution: deoptimise 24 | 25 | // Check that basic trace compilation works. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | int main(int argc, char **argv) { 36 | YkMT *mt = yk_mt_new(NULL); 37 | yk_mt_hot_threshold_set(mt, 0); 38 | YkLocation loc = yk_location_new(); 39 | 40 | int arr[300]; 41 | for (int x = 0; x < 300; x++) { 42 | arr[x] = x; 43 | } 44 | 45 | int i = 0; 46 | int *ptr = &arr[10]; 47 | int minus1 = -1; 48 | NOOPT_VAL(loc); 49 | NOOPT_VAL(i); 50 | while (i < 4) { 51 | yk_mt_control_point(mt, &loc); 52 | NOOPT_VAL(ptr); 53 | NOOPT_VAL(minus1); 54 | ptr += minus1; 55 | fprintf(stderr, "i=%d, deref=%" PRIu32 "\n", i, *ptr); 56 | i++; 57 | } 58 | yk_location_drop(loc); 59 | yk_mt_shutdown(mt); 60 | return (EXIT_SUCCESS); 61 | } 62 | -------------------------------------------------------------------------------- /tests/c/nested_writetoptr.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // yk-tracing: stop-tracing 8 | // --- Begin aot --- 9 | // ... 10 | // func foo(... 11 | // ... 12 | // *@shadowstack_0 = %{{1_1}} 13 | // ... 14 | // call bar(... 15 | // ... 16 | // *@shadowstack_0 = %{{0_1}} 17 | // ... 18 | // --- End aot --- 19 | // ... 20 | // stdout: 21 | // 2 22 | // 2 23 | // 2 24 | // 2 25 | // 2 26 | // 1 27 | // 2 28 | // 2 29 | // ... 30 | // exit 31 | 32 | // Check references created inside a trace are correctly read after deoptimisation. 33 | // Essentially tests that shadow stacks are working. 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | __attribute__((noinline)) void bar(int i, int *ptr) { 43 | int a = i * 2; 44 | int result; 45 | if (a == 10) { 46 | result = 1; 47 | } else { 48 | result = 2; 49 | } 50 | *ptr = result; 51 | } 52 | 53 | __attribute__((noinline)) void foo(int i) { 54 | int res = 0; 55 | bar(i, &res); 56 | printf("%d\n", res); 57 | } 58 | 59 | int main(int argc, char **argv) { 60 | YkMT *mt = yk_mt_new(NULL); 61 | yk_mt_hot_threshold_set(mt, 0); 62 | YkLocation loc = yk_location_new(); 63 | 64 | int i = 0; 65 | NOOPT_VAL(loc); 66 | NOOPT_VAL(i); 67 | while (i < 20) { 68 | yk_mt_control_point(mt, &loc); 69 | foo(i); 70 | i++; 71 | } 72 | printf("exit\n"); 73 | yk_location_drop(loc); 74 | yk_mt_shutdown(mt); 75 | return (EXIT_SUCCESS); 76 | } 77 | -------------------------------------------------------------------------------- /tests/c/no_trace_annotation.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt,jit-post-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // ... 7 | // --- Begin aot --- 8 | // ... 9 | // call call_me()... 10 | // ... 11 | // --- End aot --- 12 | // ... 13 | // --- Begin jit-pre-opt --- 14 | // ... 15 | // call @call_me()... 16 | // ... 17 | // --- End jit-pre-opt --- 18 | // ... 19 | // Can't JIT this! 20 | // yk-execution: enter-jit-code 21 | // Can't JIT this! 22 | // Can't JIT this! 23 | // Can't JIT this! 24 | // yk-execution: deoptimise 25 | // ... 26 | 27 | // Check that the `yk_outline` annotation works. 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | __attribute__((yk_outline)) void call_me(void) { 37 | fprintf(stderr, "Can't JIT this!\n"); 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | YkMT *mt = yk_mt_new(NULL); 42 | yk_mt_hot_threshold_set(mt, 0); 43 | YkLocation loc = yk_location_new(); 44 | 45 | int i = 5; 46 | NOOPT_VAL(loc); 47 | NOOPT_VAL(i); 48 | while (i > 0) { 49 | yk_mt_control_point(mt, &loc); 50 | call_me(); // This call must not be inlined. 51 | i--; 52 | } 53 | 54 | yk_location_drop(loc); 55 | yk_mt_shutdown(mt); 56 | return (EXIT_SUCCESS); 57 | } 58 | -------------------------------------------------------------------------------- /tests/c/no_trace_annotation2.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt,jit-post-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // ... 7 | // --- Begin aot --- 8 | // ... 9 | // call call_me()... 10 | // ... 11 | // --- End aot --- 12 | // ... 13 | // --- Begin jit-pre-opt --- 14 | // ... 15 | // call @call_me()... 16 | // ... 17 | // --- End jit-pre-opt --- 18 | // ... 19 | // Can't JIT this! 20 | // Or this! 21 | // yk-execution: enter-jit-code 22 | // Can't JIT this! 23 | // Or this! 24 | // Can't JIT this! 25 | // Or this! 26 | // Can't JIT this! 27 | // Or this! 28 | // yk-execution: deoptimise 29 | // ... 30 | 31 | // Check that the `yk_outline` annotation works when a `yk_outline` annotated 32 | // function calls another function. 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | void call_me2(void) { fprintf(stderr, "Or this!\n"); } 42 | 43 | __attribute__((yk_outline)) void call_me(void) { 44 | fprintf(stderr, "Can't JIT this!\n"); 45 | call_me2(); 46 | } 47 | 48 | int main(int argc, char **argv) { 49 | YkMT *mt = yk_mt_new(NULL); 50 | yk_mt_hot_threshold_set(mt, 0); 51 | YkLocation loc = yk_location_new(); 52 | 53 | int i = 5; 54 | NOOPT_VAL(loc); 55 | NOOPT_VAL(i); 56 | while (i > 0) { 57 | yk_mt_control_point(mt, &loc); 58 | call_me(); // This call must not be inlined. 59 | i--; 60 | } 61 | 62 | yk_location_drop(loc); 63 | yk_mt_shutdown(mt); 64 | return (EXIT_SUCCESS); 65 | } 66 | -------------------------------------------------------------------------------- /tests/c/noopts.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG=3 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG_IR=aot 5 | // stderr: 6 | // ... 7 | // --- Begin aot --- 8 | // ... 9 | // %{{9_1}}: i32 = add %{{9_0}}, 3i32 10 | // ... 11 | // --- End aot --- 12 | // ... 13 | 14 | // Check that our NOOPT_VAL macro blocks AOT optimisations. 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) { 23 | YkMT *mt = yk_mt_new(NULL); 24 | yk_mt_hot_threshold_set(mt, 0); 25 | YkLocation loc = yk_location_new(); 26 | 27 | int x, res = 0, i = 3; 28 | NOOPT_VAL(i); 29 | while (i > 0) { 30 | yk_mt_control_point(mt, &loc); 31 | x = 2; 32 | NOOPT_VAL(x); 33 | res = x + 3; // We don't want constant folding to happen here. 34 | i--; 35 | } 36 | NOOPT_VAL(res); 37 | assert(res == 5); 38 | yk_location_drop(loc); 39 | yk_mt_shutdown(mt); 40 | return (EXIT_SUCCESS); 41 | } 42 | -------------------------------------------------------------------------------- /tests/c/not_loopy_funcs_inlined_by_default.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=jit-pre-opt 4 | // stderr: 5 | // ... 6 | // --- Begin jit-pre-opt --- 7 | // ... 8 | // %{{12}}: i32 = call @call_me(%{{6}}) 9 | // ... 10 | // --- End jit-pre-opt --- 11 | 12 | // Check that functions containing no loops get inlined into the trace. 13 | // 14 | // We can only see a call to `call_me()` in the trace if `inline_into_trace()` 15 | // itself was also inlined into the trace. 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | int call_me(int x); // from extra_linkage/call_me.c 26 | 27 | // A function with no loops. 28 | __attribute__((noinline)) void inline_into_trace(int x) { call_me(x); } 29 | 30 | int main(int argc, char **argv) { 31 | YkMT *mt = yk_mt_new(NULL); 32 | yk_mt_hot_threshold_set(mt, 0); 33 | YkLocation loc = yk_location_new(); 34 | 35 | int i = 4; 36 | NOOPT_VAL(loc); 37 | NOOPT_VAL(i); 38 | while (i > 0) { 39 | yk_mt_control_point(mt, &loc); 40 | inline_into_trace(i); 41 | i--; 42 | } 43 | yk_location_drop(loc); 44 | yk_mt_shutdown(mt); 45 | return (EXIT_SUCCESS); 46 | } 47 | -------------------------------------------------------------------------------- /tests/c/outline.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=4, r=10 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // #[yk_outline] 12 | // func foo(%arg0: i32) -> i32; 13 | // ... 14 | // --- End aot --- 15 | // --- Begin jit-pre-opt --- 16 | // ... 17 | // %{{3}}: i32 = call @foo(%{{4}}) 18 | // ... 19 | // --- End jit-pre-opt --- 20 | // i=3, r=6 21 | // yk-execution: enter-jit-code 22 | // i=2, r=3 23 | // i=1, r=1 24 | // yk-execution: deoptimise 25 | // 0 26 | // exit 27 | 28 | // Check that the yk_outline attribute works. 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | int foo(int i) { 38 | int sum = 0; 39 | // the loop ensures this function is outlined. 40 | while (i > 0) { 41 | sum = sum + i; 42 | i--; 43 | } 44 | return sum; 45 | } 46 | 47 | int main(int argc, char **argv) { 48 | YkMT *mt = yk_mt_new(NULL); 49 | yk_mt_hot_threshold_set(mt, 0); 50 | YkLocation loc = yk_location_new(); 51 | 52 | int res = 9998; 53 | int i = 4; 54 | NOOPT_VAL(loc); 55 | NOOPT_VAL(res); 56 | NOOPT_VAL(i); 57 | while (i > 0) { 58 | yk_mt_control_point(mt, &loc); 59 | int r = foo(i); 60 | fprintf(stderr, "i=%d, r=%d\n", i, r); 61 | res += 2; 62 | i--; 63 | } 64 | fprintf(stderr, "%d\n", i); 65 | fprintf(stderr, "exit\n"); 66 | NOOPT_VAL(res); 67 | yk_location_drop(loc); 68 | yk_mt_shutdown(mt); 69 | return (EXIT_SUCCESS); 70 | } 71 | -------------------------------------------------------------------------------- /tests/c/outline_promoted_ptr.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // yk-tracing: start-tracing 6 | // 4: 0x... 7 | // yk-tracing: stop-tracing 8 | // 3: 0x... 9 | // yk-execution: enter-jit-code 10 | // 2: 0x... 11 | // 1: 0x... 12 | // yk-execution: deoptimise 13 | // exit 14 | 15 | // Check that outlining over a promoted pointer works. 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | __attribute__((noinline)) 24 | void *g(void *p) { 25 | p = yk_promote(p); 26 | return p; 27 | } 28 | 29 | __attribute__((yk_outline)) 30 | void *f(void *p) { 31 | return g(p); 32 | } 33 | 34 | int main(int argc, char **argv) { 35 | YkMT *mt = yk_mt_new(NULL); 36 | yk_mt_hot_threshold_set(mt, 0); 37 | YkLocation loc = yk_location_new(); 38 | 39 | int i = 4; 40 | NOOPT_VAL(loc); 41 | NOOPT_VAL(i); 42 | while (i > 0) { 43 | yk_mt_control_point(mt, &loc); 44 | fprintf(stderr, "%d: %p\n", i, f(&i)); 45 | i--; 46 | } 47 | fprintf(stderr, "exit\n"); 48 | yk_location_drop(loc); 49 | yk_mt_shutdown(mt); 50 | return (EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /tests/c/outline_recursion.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 0 8 | // 1 9 | // 2 10 | // 3 11 | // 4 12 | // yk-tracing: stop-tracing 13 | // --- Begin aot --- 14 | // ... 15 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 16 | // ... 17 | // --- End aot --- 18 | // --- Begin jit-pre-opt --- 19 | // ... 20 | // call @foo(%{{4}}) 21 | // ... 22 | // --- End jit-pre-opt --- 23 | // 0 24 | // 1 25 | // 2 26 | // 3 27 | // yk-execution: enter-jit-code 28 | // 0 29 | // 1 30 | // 2 31 | // 0 32 | // 1 33 | // yk-execution: deoptimise 34 | // 0 35 | // exit 36 | 37 | // Test outlining of recursive calls. 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | __attribute__((noinline)) void foo(int i) { 47 | if (i > 0) { 48 | foo(i - 1); 49 | fprintf(stderr, "%d\n", i); 50 | return; 51 | } 52 | fprintf(stderr, "%d\n", i); 53 | return; 54 | } 55 | 56 | int main(int argc, char **argv) { 57 | YkMT *mt = yk_mt_new(NULL); 58 | yk_mt_hot_threshold_set(mt, 0); 59 | YkLocation loc = yk_location_new(); 60 | 61 | int i = 4; 62 | NOOPT_VAL(loc); 63 | NOOPT_VAL(i); 64 | while (i > 0) { 65 | yk_mt_control_point(mt, &loc); 66 | foo(i); 67 | i--; 68 | } 69 | fprintf(stderr, "%d\n", i); 70 | fprintf(stderr, "exit\n"); 71 | yk_location_drop(loc); 72 | yk_mt_shutdown(mt); 73 | return (EXIT_SUCCESS); 74 | } 75 | -------------------------------------------------------------------------------- /tests/c/outline_recursion_indirect.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 0 8 | // 1 9 | // 2 10 | // 3 11 | // 4 12 | // yk-tracing: stop-tracing 13 | // --- Begin aot --- 14 | // ... 15 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 16 | // ... 17 | // --- End aot --- 18 | // --- Begin jit-pre-opt --- 19 | // ... 20 | // call @foo(%{{4}}) 21 | // ... 22 | // --- End jit-pre-opt --- 23 | // 0 24 | // 1 25 | // 2 26 | // 3 27 | // yk-execution: enter-jit-code 28 | // 0 29 | // 1 30 | // 2 31 | // 0 32 | // 1 33 | // yk-execution: deoptimise 34 | // 0 35 | // exit 36 | 37 | // Test outlining of recursive calls. 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | void bar(int i); 47 | 48 | __attribute__((noinline)) void foo(int i) { 49 | if (i > 0) { 50 | bar(i - 1); 51 | fprintf(stderr, "%d\n", i); 52 | return; 53 | } 54 | fprintf(stderr, "%d\n", i); 55 | return; 56 | } 57 | 58 | __attribute__((noinline)) void bar(int i) { foo(i); } 59 | 60 | int main(int argc, char **argv) { 61 | YkMT *mt = yk_mt_new(NULL); 62 | yk_mt_hot_threshold_set(mt, 0); 63 | YkLocation loc = yk_location_new(); 64 | 65 | int i = 4; 66 | NOOPT_VAL(loc); 67 | NOOPT_VAL(i); 68 | while (i > 0) { 69 | yk_mt_control_point(mt, &loc); 70 | foo(i); 71 | i--; 72 | } 73 | fprintf(stderr, "%d\n", i); 74 | fprintf(stderr, "exit\n"); 75 | yk_location_drop(loc); 76 | yk_mt_shutdown(mt); 77 | return (EXIT_SUCCESS); 78 | } 79 | -------------------------------------------------------------------------------- /tests/c/peel1.c: -------------------------------------------------------------------------------- 1 | // ## The sanitisers fiddle with the generated code and mean we can't write the 2 | // ## test we want. 3 | // ignore-if: echo $RUSTFLAGS | grep "sanitizer" 4 | // Compiler: 5 | // env-var: YKB_EXTRA_CC_FLAGS=-O2 6 | // Run-time: 7 | // env-var: YKD_SERIALISE_COMPILATION=1 8 | // env-var: YKD_LOG_IR=jit-post-opt 9 | // stderr: 10 | // 0 1 11 | // --- Begin jit-post-opt --- 12 | // ... 13 | // guard true, ... 14 | // ... 15 | // guard true, ... 16 | // header_end [1i32, ... 17 | // ... 18 | // body_start ... 19 | // ... 20 | // guard true, ... 21 | // body_end [1i32, ... 22 | // --- End jit-post-opt --- 23 | // 1 1 24 | // 2 1 25 | // 3 1 26 | // 4 1 27 | 28 | // Check that peeling works: a constant should be discovered by `header_end` 29 | // that allows the body to have only 1 guard where the header must have 2. 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | int main(int argc, char **argv) { 39 | YkMT *mt = yk_mt_new(NULL); 40 | yk_mt_hot_threshold_set(mt, 0); 41 | YkLocation loc = yk_location_new(); 42 | 43 | int i = 0; 44 | NOOPT_VAL(i); 45 | for (; i < 5; i++) { 46 | yk_mt_control_point(mt, &loc); 47 | int y = yk_promote(argc); 48 | 49 | fprintf(stderr, "%d %d\n", i, y); 50 | } 51 | 52 | yk_location_drop(loc); 53 | yk_mt_shutdown(mt); 54 | return (EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /tests/c/phi1.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O0 -Xclang -disable-O0-optnone -Xlinker --lto-newpm-passes=instcombine 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 5 | // env-var: YKD_LOG=4 6 | // env-var: YKD_LOG_STATS=/dev/null 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // i=4, val=1 10 | // yk-tracing: stop-tracing 11 | // --- Begin aot --- 12 | // ... 13 | // %{{_}}: i32 = phi bb{{_}} -> 2i32, bb{{_}} -> 1i32 14 | // ... 15 | // --- End aot --- 16 | // --- Begin jit-pre-opt --- 17 | // ... 18 | // %{{_}}: i32 = call @fprintf(%{{_}}, %{{_}}, %{{_}}, 1i32) 19 | // ... 20 | // --- End jit-pre-opt --- 21 | // i=3, val=1 22 | // yk-execution: enter-jit-code 23 | // i=2, val=1 24 | // i=1, val=1 25 | // yk-execution: deoptimise 26 | 27 | // Check that PHI nodes JIT properly. 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | bool test_compiled_event(YkCStats stats) { 35 | return stats.traces_compiled_ok == 1; 36 | } 37 | 38 | int main(int argc, char **argv) { 39 | YkMT *mt = yk_mt_new(NULL); 40 | yk_mt_hot_threshold_set(mt, 0); 41 | YkLocation loc = yk_location_new(); 42 | 43 | int val = 0; 44 | int cond = 2; 45 | int i = 4; 46 | NOOPT_VAL(loc); 47 | NOOPT_VAL(val); 48 | NOOPT_VAL(i); 49 | while (i > 0) { 50 | yk_mt_control_point(mt, &loc); 51 | if (i == 3) { 52 | __ykstats_wait_until(mt, test_compiled_event); 53 | } 54 | NOOPT_VAL(cond); 55 | if (cond > 0) { 56 | val = 1; 57 | } else { 58 | val = 2; 59 | } 60 | fprintf(stderr, "i=%d, val=%d\n", i, val); 61 | i--; 62 | } 63 | yk_location_drop(loc); 64 | yk_mt_shutdown(mt); 65 | return (EXIT_SUCCESS); 66 | } 67 | -------------------------------------------------------------------------------- /tests/c/promote.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // a=99 b=765 y=100 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // %{{_}}: i64 = promote %{{_}} ... 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{1}}: i1 = eq %{{_}}, 100i64 17 | // guard true, %{{1}}, ... 18 | // ... 19 | // --- End jit-pre-opt --- 20 | // a=99 b=765 y=200 21 | // yk-execution: enter-jit-code 22 | // a=99 b=765 y=300 23 | // a=99 b=765 y=400 24 | // a=99 b=765 y=500 25 | // yk-execution: deoptimise 26 | 27 | // Check that promotion works in traces. 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | int main(int argc, char **argv) { 37 | YkMT *mt = yk_mt_new(NULL); 38 | yk_mt_hot_threshold_set(mt, 0); 39 | YkLocation loc = yk_location_new(); 40 | 41 | int a = 99; 42 | long long b = 765; 43 | size_t x = 100; 44 | size_t y = 0; 45 | NOOPT_VAL(a); 46 | NOOPT_VAL(b); 47 | NOOPT_VAL(x); 48 | NOOPT_VAL(y); 49 | 50 | for (int i = 0; i < 5; i++) { 51 | yk_mt_control_point(mt, &loc); 52 | a = yk_promote(a); 53 | b = yk_promote(b); 54 | x = yk_promote(x); 55 | y += x; 56 | fprintf(stderr, "a=%d b=%lld y=%" PRIu64 "\n", a, b, y); 57 | } 58 | 59 | NOOPT_VAL(y); 60 | yk_location_drop(loc); 61 | yk_mt_shutdown(mt); 62 | return (EXIT_SUCCESS); 63 | } 64 | -------------------------------------------------------------------------------- /tests/c/promote_expr.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // y=50 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{16}}: i1 = eq %{{_}}, 50i64 12 | // guard true, %{{16}}, ... 13 | // ... 14 | // --- End jit-pre-opt --- 15 | // y=100 16 | // yk-execution: enter-jit-code 17 | // y=150 18 | // y=200 19 | // y=250 20 | // yk-execution: deoptimise 21 | 22 | // Check that expression promotion works in traces. 23 | // 24 | // FIXME: at the time of writing, there's a guard for the promoted value, but 25 | // the promoted value sadly isn't forwarded to printf. Looks like the shadow 26 | // stack is in the way? 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | __attribute__((__noinline__)) size_t inner(size_t x) { 36 | yk_promote(x + 25); 37 | return x + 25; 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | YkMT *mt = yk_mt_new(NULL); 42 | yk_mt_hot_threshold_set(mt, 0); 43 | YkLocation loc = yk_location_new(); 44 | 45 | size_t x = 25; 46 | size_t y = 0; 47 | NOOPT_VAL(x); 48 | 49 | for (int i = 0; i < 5; i++) { 50 | yk_mt_control_point(mt, &loc); 51 | y += inner(x); 52 | fprintf(stderr, "y=%" PRIu64 "\n", y); 53 | } 54 | 55 | NOOPT_VAL(y); 56 | yk_location_drop(loc); 57 | yk_mt_shutdown(mt); 58 | return (EXIT_SUCCESS); 59 | } 60 | -------------------------------------------------------------------------------- /tests/c/promote_guard.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // yk-tracing: start-tracing 6 | // y=100 7 | // yk-tracing: stop-tracing 8 | // y=200 9 | // yk-execution: enter-jit-code 10 | // y=300 11 | // y=400 12 | // y=500 13 | // yk-execution: deoptimise 14 | // y=700 15 | // yk-execution: enter-jit-code 16 | // y=800 17 | // y=900 18 | // y=1000 19 | // yk-execution: deoptimise 20 | // y=1999 21 | 22 | // Check that promotions are guarded correctly. 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define ELEMS 10 32 | 33 | size_t inner(size_t x, size_t y) { 34 | yk_promote(x); 35 | y += x; 36 | return y; 37 | } 38 | 39 | int main(int argc, char **argv) { 40 | YkMT *mt = yk_mt_new(NULL); 41 | yk_mt_hot_threshold_set(mt, 0); 42 | YkLocation loc = yk_location_new(); 43 | 44 | // We will trace 100 baked into the trace, and every iteration where there's 45 | // a 200 we should guard fail. 46 | size_t xs[ELEMS] = {100, 100, 100, 100, 100, 200, 100, 100, 100, 999}; 47 | size_t y = 0; 48 | NOOPT_VAL(xs); 49 | 50 | // On the third iteration, a guard must fail to stop us blindly adding 100 51 | // instead of 200. 52 | for (int i = 0; i < ELEMS; i++) { 53 | yk_mt_control_point(mt, &loc); 54 | y = inner(xs[i], y); 55 | fprintf(stderr, "y=%" PRIu64 "\n", y); 56 | } 57 | 58 | NOOPT_VAL(y); 59 | yk_location_drop(loc); 60 | yk_mt_shutdown(mt); 61 | return (EXIT_SUCCESS); 62 | } 63 | -------------------------------------------------------------------------------- /tests/c/pt_zero_len_call.c: -------------------------------------------------------------------------------- 1 | // ignore-if: test ${YK_ARCH} != "x86_64" 2 | // Run-time: 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // ... 7 | // yk-execution: enter-jit-code 8 | // ... 9 | // stdout: 10 | // exit 11 | 12 | // Check that disassembly-based PT decoding does the right thing with 13 | // zero-length calls. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | extern uintptr_t zero_len_call(void); 23 | 24 | int main(int argc, char **argv) { 25 | YkMT *mt = yk_mt_new(NULL); 26 | yk_mt_hot_threshold_set(mt, 0); 27 | YkLocation loc = yk_location_new(); 28 | 29 | int sum = 0; 30 | int i = 20; 31 | NOOPT_VAL(loc); 32 | NOOPT_VAL(sum); 33 | NOOPT_VAL(i); 34 | while (i > 0) { 35 | yk_mt_control_point(mt, &loc); 36 | sum += zero_len_call(); 37 | i--; 38 | } 39 | printf("exit"); 40 | NOOPT_VAL(sum); 41 | yk_location_drop(loc); 42 | yk_mt_shutdown(mt); 43 | return (EXIT_SUCCESS); 44 | } 45 | -------------------------------------------------------------------------------- /tests/c/ptr_global.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // ... 6 | // i=12 7 | // i=13 8 | // i=14 9 | // yk-execution: deoptimise 10 | // ... 11 | 12 | // Check that tracing mutation of a global pointer works. 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | char *p = "constant string"; 22 | 23 | int main(int argc, char **argv) { 24 | YkMT *mt = yk_mt_new(NULL); 25 | yk_mt_hot_threshold_set(mt, 0); 26 | int i = 0; 27 | YkLocation loc = yk_location_new(); 28 | NOOPT_VAL(i); 29 | NOOPT_VAL(p); 30 | while (*p != '\0') { 31 | yk_mt_control_point(mt, &loc); 32 | fprintf(stderr, "i=%d\n", i); 33 | i++; 34 | p++; 35 | } 36 | NOOPT_VAL(i); 37 | NOOPT_VAL(p); 38 | yk_location_drop(loc); 39 | yk_mt_shutdown(mt); 40 | 41 | return (EXIT_SUCCESS); 42 | } 43 | -------------------------------------------------------------------------------- /tests/c/ptrtoint.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // ptr: {{ptr}} 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{1}}: i64 = ptr_to_int %{{2}} 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // ptr: {{ptr}} 15 | // yk-execution: enter-jit-code 16 | // ptr: {{ptr}} 17 | // ptr: {{ptr}} 18 | // yk-execution: deoptimise 19 | // exit 20 | 21 | // Check that pointer to integer conversion works. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | int main(int argc, char **argv) { 31 | YkMT *mt = yk_mt_new(NULL); 32 | yk_mt_hot_threshold_set(mt, 0); 33 | YkLocation loc = yk_location_new(); 34 | 35 | int i = 4; 36 | NOOPT_VAL(loc); 37 | NOOPT_VAL(i); 38 | while (i > 0) { 39 | yk_mt_control_point(mt, &loc); 40 | long ptr = (long)&loc; 41 | fprintf(stderr, "ptr: %ld\n", ptr); 42 | i--; 43 | } 44 | fprintf(stderr, "exit\n"); 45 | yk_location_drop(loc); 46 | yk_mt_shutdown(mt); 47 | return (EXIT_SUCCESS); 48 | } 49 | -------------------------------------------------------------------------------- /tests/c/qsort.c: -------------------------------------------------------------------------------- 1 | // ## FIXME: Test fails for both hwt and swt. 2 | // ignore-if: test true 3 | // Run-time: 4 | // env-var: YKD_SERIALISE_COMPILATION=1 5 | // env-var: YKD_LOG=4 6 | // stderr: 7 | // yk-tracing: start-tracing 8 | // i=2 9 | // 4 6 1 3 2 5 end 10 | // yk-tracing: stop-tracing 11 | // i=3 12 | // 1 4 6 3 2 5 end 13 | // yk-execution: enter-jit-code 14 | // i=4 15 | // 1 3 4 6 2 5 end 16 | // i=5 17 | // 1 2 3 4 6 5 end 18 | // yk-execution: deoptimise 19 | 20 | // Check that foreign code calling back to "native" code works. 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define N_ELEMS 6 30 | 31 | int cmp(const void *a, const void *b) { 32 | int aa = *(int *)a; 33 | int bb = *(int *)b; 34 | 35 | if (aa < bb) 36 | return -1; 37 | else if (aa == bb) 38 | return 0; 39 | else 40 | return 1; 41 | } 42 | 43 | void print_elems(int elems[]) { 44 | for (int i = 0; i < N_ELEMS; i++) 45 | fprintf(stderr, "%d ", elems[i]); 46 | fprintf(stderr, "end\n"); 47 | } 48 | 49 | int main(int argc, char **argv) { 50 | YkMT *mt = yk_mt_new(NULL); 51 | yk_mt_hot_threshold_set(mt, 0); 52 | YkLocation loc = yk_location_new(); 53 | 54 | int i = 2; 55 | int elems[N_ELEMS] = {6, 4, 1, 3, 2, 5}; 56 | NOOPT_VAL(elems); 57 | NOOPT_VAL(i); 58 | NOOPT_VAL(loc); 59 | 60 | while (i < N_ELEMS) { 61 | yk_mt_control_point(mt, &loc); 62 | // sort the first `i` elements. 63 | qsort(elems, i, sizeof(elems[0]), cmp); 64 | fprintf(stderr, "i=%d\n", i); 65 | print_elems(elems); 66 | i++; 67 | } 68 | 69 | yk_location_drop(loc); 70 | yk_mt_shutdown(mt); 71 | return (EXIT_SUCCESS); 72 | } 73 | -------------------------------------------------------------------------------- /tests/c/reentrant.c: -------------------------------------------------------------------------------- 1 | // ## FIXME: Test fails for both hwt and swt. 2 | // ignore-if: test true 3 | // Run-time: 4 | // env-var: YKD_SERIALISE_COMPILATION=1 5 | // env-var: YKD_LOG_IR=jit-pre-opt 6 | // env-var: YKD_LOG=3 7 | 8 | // Check that we can reliably deal with "foreign" (not compiled with ykllvm) 9 | // code that calls back into "native code". 10 | // 11 | // FIXME: actually match some IR/output. 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int call_callback(int (*callback)(int, int), int x, int y); 21 | 22 | __attribute((noinline)) int callback(int x, int y) { return (x + y) / 2; } 23 | 24 | int main(int argc, char **argv) { 25 | YkMT *mt = yk_mt_new(NULL); 26 | yk_mt_hot_threshold_set(mt, 0); 27 | YkLocation loc = yk_location_new(); 28 | 29 | int x = 0; 30 | int i = 4; 31 | NOOPT_VAL(loc); 32 | NOOPT_VAL(x); 33 | NOOPT_VAL(i); 34 | while (i > 0) { 35 | yk_mt_control_point(mt, &loc); 36 | fprintf(stderr, "i=%d, x=%d\n", i, x); 37 | call_callback(&callback, i, i); 38 | i--; 39 | } 40 | NOOPT_VAL(x); 41 | yk_location_drop(loc); 42 | yk_mt_shutdown(mt); 43 | return (EXIT_SUCCESS); 44 | } 45 | -------------------------------------------------------------------------------- /tests/c/rel_path.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // Run-time: 3 | // env-var: YKD_LOG=4 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // stderr: 7 | // ... 8 | // yk-execution: enter-jit-code 9 | // ... 10 | 11 | // Check that running a traced binary via a relative path works. 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | int main(int argc, char **argv) { 22 | if (*argv[0] == '/') { 23 | // Reinvoke ourself with a relative path. 24 | char *base = basename(argv[0]); 25 | if (base == NULL) 26 | err(EXIT_FAILURE, "basename"); 27 | 28 | char *dir = dirname(argv[0]); 29 | if (dir == NULL) 30 | err(EXIT_FAILURE, "dirname"); 31 | if (chdir(dir) != 0) 32 | err(EXIT_FAILURE, "chdir"); 33 | 34 | if (execl(base, base, NULL) == -1) 35 | err(EXIT_FAILURE, "execl"); 36 | // NOREACH 37 | } 38 | 39 | YkMT *mt = yk_mt_new(NULL); 40 | yk_mt_hot_threshold_set(mt, 0); 41 | YkLocation loc = yk_location_new(); 42 | 43 | int i = 3; 44 | NOOPT_VAL(i); 45 | while (i > 0) { 46 | yk_mt_control_point(mt, &loc); 47 | i--; 48 | } 49 | 50 | assert(i == 0); 51 | yk_location_drop(loc); 52 | yk_mt_shutdown(mt); 53 | return (EXIT_SUCCESS); 54 | } 55 | -------------------------------------------------------------------------------- /tests/c/resume_and_branch.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // ... 7 | // yk-execution: enter-jit-code 8 | // x=2 9 | // ... 10 | 11 | // Check that a call followed immediately by an unconditional branch doesn't 12 | // confuse the block mapping due to fallthrough optimisations. 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | __attribute__((noinline)) void f(int x) { fprintf(stderr, "x=%d\n", x); } 22 | 23 | int main(int argc, char **argv) { 24 | YkMT *mt = yk_mt_new(NULL); 25 | yk_mt_hot_threshold_set(mt, 0); 26 | YkLocation loc = yk_location_new(); 27 | 28 | int x = 0; 29 | int i = 4; 30 | NOOPT_VAL(loc); 31 | NOOPT_VAL(x); 32 | NOOPT_VAL(i); 33 | while (i > 0) { 34 | yk_mt_control_point(mt, &loc); 35 | f(i); 36 | goto more; 37 | 38 | more: 39 | i--; 40 | } 41 | 42 | yk_location_drop(loc); 43 | yk_mt_shutdown(mt); 44 | return (EXIT_SUCCESS); 45 | } 46 | -------------------------------------------------------------------------------- /tests/c/safepoint_const.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | 6 | // Check deopt of constants works. 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | __attribute__((noinline)) int f(int x, int i) { 16 | int y; 17 | if (i == 1) { 18 | y = 10; 19 | } else { 20 | y = 20; 21 | } 22 | // Force deoptimisation of a constant. 23 | fprintf(stderr, "%d %d %d\n", x, y, i); 24 | return y; 25 | } 26 | 27 | __attribute__((noinline)) int g(int x, int i) { return f(x, i); } 28 | 29 | int main(int argc, char **argv) { 30 | YkMT *mt = yk_mt_new(NULL); 31 | yk_mt_hot_threshold_set(mt, 0); 32 | YkLocation loc = yk_location_new(); 33 | 34 | int i = 4; 35 | NOOPT_VAL(loc); 36 | NOOPT_VAL(i); 37 | while (i > 0) { 38 | yk_mt_control_point(mt, &loc); 39 | fprintf(stderr, ">%d\n", g(4, i)); 40 | i--; 41 | } 42 | fprintf(stderr, "exit\n"); 43 | yk_location_drop(loc); 44 | yk_mt_shutdown(mt); 45 | return (EXIT_SUCCESS); 46 | } 47 | -------------------------------------------------------------------------------- /tests/c/select.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 4 1 1 8 | // yk-tracing: stop-tracing 9 | // --- Begin jit-pre-opt --- 10 | // ... 11 | // %{{13}}: i32 = %{{12}} ? 1i32 : 2i32 12 | // ... 13 | // --- End jit-pre-opt --- 14 | // 3 2 3 15 | // yk-execution: enter-jit-code 16 | // 2 1 4 17 | // 1 2 6 18 | // yk-execution: deoptimise 19 | // exit 20 | 21 | // Check that select instructions work. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | int main(int argc, char **argv) { 31 | YkMT *mt = yk_mt_new(NULL); 32 | yk_mt_hot_threshold_set(mt, 0); 33 | YkLocation loc = yk_location_new(); 34 | 35 | int res = 0; 36 | int i = 4; 37 | NOOPT_VAL(loc); 38 | NOOPT_VAL(res); 39 | NOOPT_VAL(i); 40 | while (i > 0) { 41 | yk_mt_control_point(mt, &loc); 42 | int v = i % 2 == 0 ? 1 : 2; 43 | res += v; 44 | fprintf(stderr, "%d %d %d\n", i, v, res); 45 | i--; 46 | } 47 | fprintf(stderr, "exit\n"); 48 | NOOPT_VAL(res); 49 | yk_location_drop(loc); 50 | yk_mt_shutdown(mt); 51 | return (EXIT_SUCCESS); 52 | } 53 | -------------------------------------------------------------------------------- /tests/c/shadow_longjmp.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // 11 7 | // 10 8 | // 9 9 | // longjmp 10 | // 8 11 | // 7 12 | // 6 13 | // longjmp 14 | // 5 15 | // 4 16 | // 3 17 | // longjmp 18 | // 2 19 | // 1 20 | // 0 21 | // longjmp 22 | 23 | // Check that the ykllvm shadow stack pass works at runtime in the presence of 24 | // setjmp and longjump. 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | __attribute__((noinline)) 35 | void g(int i, jmp_buf *env) { 36 | fprintf(stderr, "%d\n", i); 37 | if (i % 3 == 0) { 38 | fprintf(stderr, "longjmp\n"); 39 | longjmp(*env, 1); 40 | } 41 | } 42 | 43 | __attribute__((noinline)) 44 | void f(int i, jmp_buf *env) { 45 | while (i >= 0) { 46 | g(i, env); 47 | i--; 48 | } 49 | } 50 | 51 | int main(int argc, char **argv) { 52 | YkMT *mt = yk_mt_new(NULL); 53 | jmp_buf env; 54 | 55 | int i = 11; 56 | YkLocation loc = yk_location_null(); 57 | NOOPT_VAL(i); 58 | while (i > 0) { 59 | // Passing a NULL location. We never JIT. Just checking AOT behaviour. 60 | yk_mt_control_point(mt, &loc); 61 | if (setjmp(env) != 0) { 62 | i -= 3; 63 | } 64 | f(i, &env); 65 | i--; 66 | } 67 | yk_mt_shutdown(mt); 68 | return (EXIT_SUCCESS); 69 | } 70 | -------------------------------------------------------------------------------- /tests/c/shadow_reentrant.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=3 4 | // stderr: 5 | // i=4, x=0, argc=1 6 | // i=3, x=0, argc=1 7 | // i=2, x=0, argc=1 8 | // i=1, x=0, argc=1 9 | 10 | // Check that the shadow stack is properly allocated when we "call-back" from 11 | // external code. 12 | // 13 | // An earlier bug meant that we didn't allocate shadow stack for calls to 14 | // external code, meaning that when we called back we trashed the shadow stack 15 | // of the previous frame. In this test that manifested as argc being mutated! 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | int call_callback(int (*callback)(int, int), int x, int y); 25 | 26 | __attribute((noinline)) int callback(int x, int y) { return (x + y) / 2; } 27 | 28 | int main(int argc, char **argv) { 29 | YkMT *mt = yk_mt_new(NULL); 30 | yk_mt_hot_threshold_set(mt, 100); 31 | YkLocation loc = yk_location_new(); 32 | 33 | int x = 0; 34 | int i = 4; 35 | NOOPT_VAL(loc); 36 | NOOPT_VAL(x); 37 | NOOPT_VAL(i); 38 | while (i > 0) { 39 | yk_mt_control_point(mt, &loc); 40 | fprintf(stderr, "i=%d, x=%d, argc=%d\n", i, x, argc); 41 | call_callback(&callback, i, i); 42 | i--; 43 | } 44 | NOOPT_VAL(x); 45 | yk_location_drop(loc); 46 | yk_mt_shutdown(mt); 47 | return (EXIT_SUCCESS); 48 | } 49 | -------------------------------------------------------------------------------- /tests/c/sidetrace_phinode.old.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=3 4 | // stdout: 5 | // exit 6 | 7 | // Test case extracted from lua. 8 | // Testing sidetraces where the first traced block contains a PHI node. We need 9 | // to make sure to set LastBB when initialising the CallStack. There's nothing 10 | // specific we want to check here, except that this doesn't crash. 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | struct CallInfo { 20 | void *savedpc; 21 | }; 22 | 23 | struct lua_State { 24 | struct CallInfo *ci; 25 | int hookmask; 26 | }; 27 | 28 | int luaG_traceexec(struct lua_State *L, void *pc, int hookcount) { 29 | struct CallInfo *ci = L->ci; 30 | int mask = L->hookmask; 31 | int counthook; 32 | ci->savedpc = pc; /* save 'pc' */ 33 | counthook = (hookcount > 10 && mask); 34 | if (counthook) 35 | return 2; /* reset count */ 36 | return 1; /* keep 'trap' on */ 37 | } 38 | 39 | int main(int argc, char **argv) { 40 | YkMT *mt = yk_mt_new(NULL); 41 | yk_mt_hot_threshold_set(mt, 0); 42 | yk_mt_sidetrace_threshold_set(mt, 5); 43 | YkLocation loc = yk_location_new(); 44 | 45 | int i = 20; 46 | struct CallInfo ci = {NULL}; 47 | struct lua_State L = {&ci, 0}; 48 | NOOPT_VAL(loc); 49 | NOOPT_VAL(i); 50 | while (i > 0) { 51 | yk_mt_control_point(mt, &loc); 52 | luaG_traceexec(&L, NULL, i); 53 | i--; 54 | } 55 | printf("exit"); 56 | yk_location_drop(loc); 57 | yk_mt_shutdown(mt); 58 | return (EXIT_SUCCESS); 59 | } 60 | -------------------------------------------------------------------------------- /tests/c/sidetrace_while.old.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // ... 7 | // yk-jit-event: execute-side-trace 8 | // ... 9 | // 500 10 | // stdout: 11 | // exit 12 | 13 | // Test side tracing inside an unrolled while loop. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | __attribute__((yk_unroll_safe)) int foo(int i) { 23 | int z = 10; 24 | int res = 0; 25 | while (z > 0) { 26 | z--; 27 | if (i > 20) { 28 | res++; 29 | } else { 30 | res += 2; 31 | } 32 | } 33 | return res; 34 | } 35 | 36 | int main(int argc, char **argv) { 37 | YkMT *mt = yk_mt_new(NULL); 38 | yk_mt_hot_threshold_set(mt, 0); 39 | yk_mt_sidetrace_threshold_set(mt, 5); 40 | YkLocation loc = yk_location_new(); 41 | 42 | int res = 0; 43 | int i = 30; 44 | NOOPT_VAL(loc); 45 | NOOPT_VAL(res); 46 | NOOPT_VAL(i); 47 | while (i > 0) { 48 | yk_mt_control_point(mt, &loc); 49 | res += foo(i); 50 | fprintf(stderr, "%d\n", res); 51 | i--; 52 | } 53 | printf("exit"); 54 | NOOPT_VAL(res); 55 | yk_location_drop(loc); 56 | yk_mt_shutdown(mt); 57 | return (EXIT_SUCCESS); 58 | } 59 | -------------------------------------------------------------------------------- /tests/c/signal_handler_interrupts_trace.c: -------------------------------------------------------------------------------- 1 | // ## FIXME: currently we can't distinguish a signal handler from a regular 2 | // ## call (or call back from unmappable code). In this test the signal handler 3 | // ## is INLINED into trace! 4 | // ignore-if: true 5 | // Run-time: 6 | // env-var: YKD_LOG_IR=jit-pre-opt,aot 7 | // env-var: YKD_SERIALISE_COMPILATION=1 8 | // env-var: YKD_LOG=3 9 | // stderr: 10 | // i=3 11 | // yk-tracing: start-tracing 12 | // i=2 13 | // yk-tracing: stop-tracing 14 | // yk-warning: trace-compilation-aborted: irregular control flow detected 15 | // i=1 16 | // exit 17 | 18 | // Check that something sensible happens when a signal handler interrupts 19 | // execution during tracing. 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | int flag = 0; 31 | 32 | __attribute__((yk_outline)) 33 | void handler(int sig) { 34 | flag = 1; 35 | } 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 1); 40 | YkLocation loc = yk_location_new(); 41 | 42 | signal(SIGUSR1, handler); 43 | pid_t self = getpid(); 44 | 45 | int i = 3; 46 | NOOPT_VAL(loc); 47 | NOOPT_VAL(i); 48 | while (i > 0) { 49 | yk_mt_control_point(mt, &loc); 50 | fprintf(stderr, "i=%d\n", i); 51 | 52 | flag = 0; 53 | if (kill(self, SIGUSR1) != 0) { 54 | errx(EXIT_FAILURE, "kill"); 55 | } 56 | while (flag == 0) { 57 | usleep(1000); // attempt to not blow the trace buffer. 58 | } 59 | 60 | i--; 61 | } 62 | fprintf(stderr, "exit"); 63 | yk_location_drop(loc); 64 | yk_mt_shutdown(mt); 65 | return (EXIT_SUCCESS); 66 | } 67 | -------------------------------------------------------------------------------- /tests/c/signextend_negative.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // neg=-1 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // ... = sext ... 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{22}}: i64 = sext %{{21}} 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // neg=-2 20 | // yk-execution: enter-jit-code 21 | // neg=-3 22 | // neg=-4 23 | // yk-execution: deoptimise 24 | 25 | // Check that sign extending a negative value works. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main(int argc, char **argv) { 34 | YkMT *mt = yk_mt_new(NULL); 35 | yk_mt_hot_threshold_set(mt, 0); 36 | YkLocation loc = yk_location_new(); 37 | 38 | int8_t neg = -1; 39 | NOOPT_VAL(loc); 40 | while (neg > -5) { 41 | NOOPT_VAL(neg); 42 | yk_mt_control_point(mt, &loc); 43 | fprintf(stderr, "neg=%" PRIi64 "\n", (int64_t)neg); 44 | neg--; 45 | } 46 | 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | return (EXIT_SUCCESS); 50 | } 51 | -------------------------------------------------------------------------------- /tests/c/signextend_positive.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // pos=1 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // ... = sext ... 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{22}}: i64 = sext %{{21}} 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // pos=2 20 | // yk-execution: enter-jit-code 21 | // pos=3 22 | // pos=4 23 | // yk-execution: deoptimise 24 | 25 | // Check that sign extending with a positive value works. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main(int argc, char **argv) { 34 | YkMT *mt = yk_mt_new(NULL); 35 | yk_mt_hot_threshold_set(mt, 0); 36 | YkLocation loc = yk_location_new(); 37 | 38 | int32_t pos = 1; 39 | NOOPT_VAL(loc); 40 | while (pos < 5) { 41 | NOOPT_VAL(pos); 42 | yk_mt_control_point(mt, &loc); 43 | fprintf(stderr, "pos=%" PRIi64 "\n", 44 | (int64_t)pos); // cast causes sign extend. 45 | pos++; 46 | } 47 | yk_location_drop(loc); 48 | yk_mt_shutdown(mt); 49 | return (EXIT_SUCCESS); 50 | } 51 | -------------------------------------------------------------------------------- /tests/c/simple.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // 4 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // --- End jit-pre-opt --- 17 | // 3 18 | // yk-execution: enter-jit-code 19 | // 2 20 | // 1 21 | // yk-execution: deoptimise 22 | // exit 23 | 24 | // Check that basic trace compilation works. 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main(int argc, char **argv) { 34 | YkMT *mt = yk_mt_new(NULL); 35 | yk_mt_hot_threshold_set(mt, 0); 36 | YkLocation loc = yk_location_new(); 37 | 38 | int res = 9998; 39 | int i = 4; 40 | NOOPT_VAL(loc); 41 | NOOPT_VAL(res); 42 | NOOPT_VAL(i); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | fprintf(stderr, "%d\n", i); 46 | i--; 47 | } 48 | fprintf(stderr, "exit\n"); 49 | NOOPT_VAL(res); 50 | yk_location_drop(loc); 51 | yk_mt_shutdown(mt); 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /tests/c/simple_fprintf.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=4 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{17}}: i32 = call @fprintf(%{{11}}, %{{16}}, %{{12}}) 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // i=3 20 | // yk-execution: enter-jit-code 21 | // i=2 22 | // i=1 23 | // ... 24 | // yk-execution: deoptimise 25 | // ... 26 | // exit 27 | 28 | // Check that a call to fprintf works. 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 0); 40 | YkLocation loc = yk_location_new(); 41 | 42 | int res = 9998; 43 | int i = 4; 44 | NOOPT_VAL(loc); 45 | NOOPT_VAL(res); 46 | NOOPT_VAL(i); 47 | while (i > 0) { 48 | yk_mt_control_point(mt, &loc); 49 | fprintf(stderr, "i=%d\n", i); 50 | res += 2; 51 | i--; 52 | } 53 | fprintf(stderr, "exit\n"); 54 | NOOPT_VAL(res); 55 | yk_location_drop(loc); 56 | yk_mt_shutdown(mt); 57 | return (EXIT_SUCCESS); 58 | } 59 | -------------------------------------------------------------------------------- /tests/c/simple_inline.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // foo 7 10 | // yk-tracing: stop-tracing 11 | // --- Begin jit-pre-opt --- 12 | // ... 13 | // %{{result}}: i32 = add %{{1}}, 3i32 14 | // ... 15 | // %{{2}}: i32 = call @fprintf(%{{3}}, %{{4}}, %{{result}}) 16 | // ... 17 | // --- End jit-pre-opt --- 18 | // foo 6 19 | // yk-execution: enter-jit-code 20 | // foo 5 21 | // foo 4 22 | // yk-execution: deoptimise 23 | // exit 24 | 25 | // Check that return values of fucntions inlined into the trace are properly 26 | // mapped. 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | __attribute__((noinline)) int foo(int i) { return i + 3; } 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 0); 40 | YkLocation loc = yk_location_new(); 41 | 42 | int i = 4; 43 | NOOPT_VAL(loc); 44 | NOOPT_VAL(i); 45 | while (i > 0) { 46 | yk_mt_control_point(mt, &loc); 47 | int x = foo(i); 48 | fprintf(stderr, "foo %d\n", x); 49 | i--; 50 | } 51 | fprintf(stderr, "exit\n"); 52 | yk_location_drop(loc); 53 | yk_mt_shutdown(mt); 54 | return (EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /tests/c/simple_nested.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // yk-tracing: start-tracing 6 | // i=5 7 | // yk-tracing: stop-tracing 8 | // i=4 9 | // yk-execution: enter-jit-code 10 | // i=3 11 | // i=2 12 | // yk-execution: deoptimise 13 | // ... 14 | 15 | // Check that basic trace compilation works with nested calls. 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | int foo(int arg) { 25 | if (arg < 3) { 26 | arg = 0; 27 | } else { 28 | arg--; 29 | } 30 | return arg; 31 | } 32 | 33 | int bar(int arg) { return foo(arg); } 34 | 35 | int main(int argc, char **argv) { 36 | YkMT *mt = yk_mt_new(NULL); 37 | yk_mt_hot_threshold_set(mt, 0); 38 | YkLocation loc = yk_location_new(); 39 | 40 | int i = 5; 41 | NOOPT_VAL(loc); 42 | NOOPT_VAL(i); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | fprintf(stderr, "i=%d\n", i); 46 | i = bar(i); 47 | } 48 | yk_location_drop(loc); 49 | yk_mt_shutdown(mt); 50 | return (EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /tests/c/simple_non_serialised.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG=4 3 | // env-var: YKD_LOG_STATS=/dev/null 4 | // stderr: 5 | // yk-tracing: start-tracing 6 | // i=4 7 | // yk-tracing: stop-tracing 8 | // i=3 9 | // yk-execution: enter-jit-code 10 | // i=2 11 | // i=1 12 | // yk-execution: deoptimise 13 | 14 | // Check that basic trace compilation in a thread works. 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | bool test_compiled_event(YkCStats); 24 | 25 | int main(int argc, char **argv) { 26 | YkMT *mt = yk_mt_new(NULL); 27 | yk_mt_hot_threshold_set(mt, 0); 28 | YkLocation loc = yk_location_new(); 29 | 30 | int i = 4; 31 | NOOPT_VAL(loc); 32 | NOOPT_VAL(i); 33 | while (i > 0) { 34 | yk_mt_control_point(mt, &loc); 35 | if (i == 3) 36 | __ykstats_wait_until(mt, test_compiled_event); 37 | fprintf(stderr, "i=%d\n", i); 38 | i--; 39 | } 40 | yk_location_drop(loc); 41 | yk_mt_shutdown(mt); 42 | return (EXIT_SUCCESS); 43 | } 44 | 45 | bool test_compiled_event(YkCStats stats) { 46 | return stats.traces_compiled_ok == 1; 47 | } 48 | -------------------------------------------------------------------------------- /tests/c/simple_peeling.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-post-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // ... 7 | // --- Begin jit-post-opt --- 8 | // ... 9 | // header_start ... 10 | // ... 11 | // header_end [%{{0}}, %{{1}}, %{{2}}, %{{3}}] 12 | // ... 13 | // body_start [%{{19}}, %{{20}}, %{{21}}, %{{22}}] 14 | // ... 15 | // body_end ... 16 | // ... 17 | // --- End jit-post-opt --- 18 | // ... 19 | 20 | // Check that basic trace peeling works. 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | int main(int argc, char **argv) { 30 | YkMT *mt = yk_mt_new(NULL); 31 | yk_mt_hot_threshold_set(mt, 0); 32 | YkLocation loc = yk_location_new(); 33 | 34 | int res = 9998; 35 | int i = 4; 36 | NOOPT_VAL(loc); 37 | NOOPT_VAL(res); 38 | NOOPT_VAL(i); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, &loc); 41 | fprintf(stderr, "%d\n", i); 42 | i--; 43 | } 44 | fprintf(stderr, "exit\n"); 45 | NOOPT_VAL(res); 46 | yk_location_drop(loc); 47 | yk_mt_shutdown(mt); 48 | return (EXIT_SUCCESS); 49 | } 50 | -------------------------------------------------------------------------------- /tests/c/simplecall.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // 4 10 | // foo 11 | // yk-tracing: stop-tracing 12 | // --- Begin aot --- 13 | // ... 14 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 15 | // ... 16 | // --- End aot --- 17 | // --- Begin jit-pre-opt --- 18 | // ... 19 | // %{{1}}: i1 = sgt %{{2}}, 1i32 20 | // ... 21 | // %{{3}}: i64 = call @fwrite(%{{4}}, 4i64, 1i64, %{{5}}) 22 | // ... 23 | // --- End jit-pre-opt --- 24 | // 3 25 | // foo 26 | // yk-execution: enter-jit-code 27 | // 2 28 | // foo 29 | // 1 30 | // bar 31 | // yk-execution: deoptimise 32 | // 0 33 | // exit 34 | 35 | // Check that call inlining works. 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | void foo(int i) { 45 | if (i > 1) { 46 | fputs("foo\n", stderr); 47 | } else { 48 | fputs("bar\n", stderr); 49 | } 50 | } 51 | 52 | int main(int argc, char **argv) { 53 | YkMT *mt = yk_mt_new(NULL); 54 | yk_mt_hot_threshold_set(mt, 0); 55 | YkLocation loc = yk_location_new(); 56 | 57 | int res = 9998; 58 | int i = 4; 59 | NOOPT_VAL(loc); 60 | NOOPT_VAL(res); 61 | NOOPT_VAL(i); 62 | while (i > 0) { 63 | yk_mt_control_point(mt, &loc); 64 | fprintf(stderr, "%d\n", i); 65 | foo(i); 66 | res += 2; 67 | i--; 68 | } 69 | fprintf(stderr, "%d\n", i); 70 | fprintf(stderr, "exit\n"); 71 | NOOPT_VAL(res); 72 | yk_location_drop(loc); 73 | yk_mt_shutdown(mt); 74 | return (EXIT_SUCCESS); 75 | } 76 | -------------------------------------------------------------------------------- /tests/c/stats1.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_STATS=- 4 | // stderr: 5 | // { 6 | // ... 7 | // "trace_executions": 1, 8 | // "traces_compiled_err": 0, 9 | // "traces_compiled_ok": 1, 10 | // "traces_recorded_err": 0, 11 | // "traces_recorded_ok": 1 12 | // ... 13 | // } 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) { 23 | YkMT *mt = yk_mt_new(NULL); 24 | yk_mt_hot_threshold_set(mt, 0); 25 | YkLocation loc = yk_location_new(); 26 | 27 | int i = 4; 28 | NOOPT_VAL(loc); 29 | NOOPT_VAL(i); 30 | while (i > 0) { 31 | yk_mt_control_point(mt, &loc); 32 | fprintf(stdout, "i=%d\n", i); 33 | i--; 34 | } 35 | yk_location_drop(loc); 36 | yk_mt_shutdown(mt); 37 | return (EXIT_SUCCESS); 38 | } 39 | -------------------------------------------------------------------------------- /tests/c/stats3.c: -------------------------------------------------------------------------------- 1 | // ## Crashes on unimplemneted setjmp instruction. 2 | // ignore-if: true 3 | // Run-time: 4 | // env-var: YKD_SERIALISE_COMPILATION=1 5 | // env-var: YKD_LOG_STATS=- 6 | // stderr: 7 | // { 8 | // ... 9 | // "trace_executions": 0, 10 | // "traces_compiled_err": 1, 11 | // "traces_compiled_ok": 0, 12 | // "traces_recorded_err": 0, 13 | // "traces_recorded_ok": 1 14 | // ... 15 | // } 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | int main(int argc, char **argv) { 26 | YkMT *mt = yk_mt_new(NULL); 27 | yk_mt_hot_threshold_set(mt, 0); 28 | YkLocation loc = yk_location_new(); 29 | 30 | for (int i = 0; i < 2; i += 1) { 31 | yk_mt_control_point(mt, &loc); 32 | jmp_buf env; 33 | setjmp(env); 34 | } 35 | 36 | yk_location_drop(loc); 37 | yk_mt_shutdown(mt); 38 | return (EXIT_SUCCESS); 39 | } 40 | -------------------------------------------------------------------------------- /tests/c/stats4.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_STATS=- 3 | // stderr: 4 | // { 5 | // ... 6 | // "traces_compiled_ok": ... 7 | // ... 8 | // } 9 | 10 | // This tests that spun-up compile workers still cause stats to be printed out 11 | // (i.e. that, because of reference counting, they don't keep `Mt` alive 12 | // forever). 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | int main(int argc, char **argv) { 24 | YkMT *mt = yk_mt_new(NULL); 25 | yk_mt_hot_threshold_set(mt, 0); 26 | YkLocation loc = yk_location_new(); 27 | 28 | for (uint64_t i = 0; i < 2; i += 1) { 29 | yk_mt_control_point(mt, &loc); 30 | } 31 | 32 | yk_location_drop(loc); 33 | yk_mt_shutdown(mt); 34 | return (EXIT_SUCCESS); 35 | } 36 | -------------------------------------------------------------------------------- /tests/c/strarray.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // pepper 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // global_decl @fruits 12 | // global_decl @.str 13 | // global_decl @.str.1 14 | // ... 15 | // --- End aot --- 16 | // cucumber 17 | // yk-execution: enter-jit-code 18 | // tomato 19 | // banana 20 | // yk-execution: deoptimise 21 | // stdout: 22 | // exit 23 | 24 | // Check that when we clone a `GlobalVariable` into the JITMod, and that global 25 | // references other `GlobalVariables`, the other globals are cloned as well. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | static const char *const fruits[] = {"apple", "banana", "tomato", "cucumber", 35 | "pepper"}; 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 0); 40 | YkLocation loc = yk_location_new(); 41 | 42 | int res = 9998; 43 | int i = 4; 44 | NOOPT_VAL(loc); 45 | NOOPT_VAL(res); 46 | NOOPT_VAL(i); 47 | while (i > 0) { 48 | yk_mt_control_point(mt, &loc); 49 | fprintf(stderr, "%s\n", fruits[i]); 50 | res += 2; 51 | i--; 52 | } 53 | printf("exit"); 54 | NOOPT_VAL(res); 55 | yk_location_drop(loc); 56 | yk_mt_shutdown(mt); 57 | return (EXIT_SUCCESS); 58 | } 59 | -------------------------------------------------------------------------------- /tests/c/struct_simple.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // ... 7 | // yk-tracing: start-tracing 8 | // 3:1 9 | // yk-tracing: stop-tracing 10 | // --- Begin jit-pre-opt --- 11 | // ... 12 | // --- End jit-pre-opt --- 13 | // 2:1 14 | // yk-execution: enter-jit-code 15 | // 1:1 16 | // yk-execution: deoptimise 17 | // ... 18 | 19 | // Check that we can handle struct field accesses. 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | struct s { 28 | int x; 29 | }; 30 | 31 | int main(int argc, char **argv) { 32 | YkMT *mt = yk_mt_new(NULL); 33 | yk_mt_hot_threshold_set(mt, 0); 34 | YkLocation loc = yk_location_new(); 35 | 36 | struct s s1 = {argc}; 37 | int y1 = 0, i = 3; 38 | NOOPT_VAL(i); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, &loc); 41 | NOOPT_VAL(s1); 42 | y1 = s1.x; 43 | fprintf(stderr, "%d:%d\n", i, s1.x); 44 | i--; 45 | } 46 | assert(y1 == 1); 47 | 48 | yk_location_drop(loc); 49 | yk_mt_shutdown(mt); 50 | return (EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /tests/c/switch_default.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=3 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // switch %{{10_1}}, bb{{bb15}}, [299 -> bb{{bb11}}, 298 -> bb{{bb13}}]... 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{21}}: i1 = eq %{{20}}, 299i32 17 | // %{{22}}: i1 = eq %{{20}}, 298i32 18 | // %{{23}}: i1 = or %{{21}}, %{{22}} 19 | // guard false, %{{23}}, ... 20 | // ... 21 | // --- End jit-pre-opt --- 22 | // i=2 23 | // yk-execution: enter-jit-code 24 | // i=1 25 | // yk-execution: deoptimise 26 | // ... 27 | 28 | // Check that tracing the default arm of a switch works correctly. 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 0); 40 | YkLocation loc = yk_location_new(); 41 | int i = 3; 42 | int j = 300; 43 | NOOPT_VAL(i); 44 | NOOPT_VAL(j); 45 | while (i > 0) { 46 | yk_mt_control_point(mt, &loc); 47 | fprintf(stderr, "i=%d\n", i); 48 | switch (j) { 49 | case 299: 50 | exit(1); 51 | case 298: 52 | exit(1); 53 | default: 54 | i--; 55 | break; 56 | } 57 | } 58 | yk_location_drop(loc); 59 | yk_mt_shutdown(mt); 60 | 61 | return (EXIT_SUCCESS); 62 | } 63 | -------------------------------------------------------------------------------- /tests/c/switch_many_guards_failing.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=3 4 | // env-var: YKD_LOG_IR=jit-pre-opt 5 | // stdout: 6 | // jihgfedcbajihgfedcbajihgfedcbajihgfedcbajihgfedcbajihgfedcbajihgfedcbajihgfedcbajihgfedcbajihgfedcba 7 | 8 | // Check that guard failures in switches work as expected. 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | int main(int argc, char **argv) { 18 | YkMT *mt = yk_mt_new(NULL); 19 | yk_mt_hot_threshold_set(mt, 3); 20 | YkLocation loc = yk_location_new(); 21 | int i = 100; 22 | int j = 10; 23 | NOOPT_VAL(i); 24 | NOOPT_VAL(j); 25 | while (i > 0) { 26 | yk_mt_control_point(mt, &loc); 27 | char c; 28 | switch (j % 10) { 29 | case 9: 30 | c = 'a'; 31 | break; 32 | case 8: 33 | c = 'b'; 34 | break; 35 | case 7: 36 | c = 'c'; 37 | break; 38 | case 6: 39 | c = 'd'; 40 | break; 41 | case 5: 42 | c = 'e'; 43 | break; 44 | case 4: 45 | c = 'f'; 46 | break; 47 | case 3: 48 | c = 'g'; 49 | break; 50 | case 2: 51 | c = 'h'; 52 | break; 53 | case 1: 54 | c = 'i'; 55 | break; 56 | case 0: 57 | c = 'j'; 58 | break; 59 | } 60 | printf("%c", c); 61 | i--; 62 | j++; 63 | } 64 | yk_location_drop(loc); 65 | yk_mt_shutdown(mt); 66 | printf("\n"); 67 | 68 | return (EXIT_SUCCESS); 69 | } 70 | -------------------------------------------------------------------------------- /tests/c/switch_nested_guard.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // stdout: 4 | // gfedcblagfedcbjagfedcbmagfedcbkagfedcbiagfedcblagfedcbjagfedcbmagfedcbkagfedcbiagfedcblagfedcbjagfedcbmagfedcbkagf 5 | 6 | // Check that guard failures in nested switches work as expected. 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char **argv) { 16 | YkMT *mt = yk_mt_new(NULL); 17 | yk_mt_hot_threshold_set(mt, 3); 18 | YkLocation loc = yk_location_new(); 19 | int i = 100; 20 | int j = 0; 21 | int k = 0; 22 | NOOPT_VAL(i); 23 | NOOPT_VAL(j); 24 | while (i > 0) { 25 | yk_mt_control_point(mt, &loc); 26 | char c, d; 27 | switch (j % 7) { 28 | case 6: 29 | switch (k % 5) { 30 | case 4: 31 | d = 'i'; 32 | break; 33 | case 3: 34 | d = 'j'; 35 | break; 36 | case 2: 37 | d = 'k'; 38 | break; 39 | case 1: 40 | d = 'l'; 41 | break; 42 | case 0: 43 | d = 'm'; 44 | break; 45 | } 46 | printf("%c", d); 47 | c = 'a'; 48 | break; 49 | case 5: 50 | c = 'b'; 51 | break; 52 | case 4: 53 | c = 'c'; 54 | break; 55 | case 3: 56 | c = 'd'; 57 | break; 58 | case 2: 59 | c = 'e'; 60 | break; 61 | case 1: 62 | c = 'f'; 63 | break; 64 | case 0: 65 | c = 'g'; 66 | break; 67 | } 68 | printf("%c", c); 69 | i--; 70 | j++; 71 | k++; 72 | } 73 | yk_location_drop(loc); 74 | yk_mt_shutdown(mt); 75 | printf("\n"); 76 | 77 | return (EXIT_SUCCESS); 78 | } 79 | -------------------------------------------------------------------------------- /tests/c/switch_non_default.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // i=3 8 | // yk-tracing: stop-tracing 9 | // --- Begin aot --- 10 | // ... 11 | // switch %{{10_1}}, bb{{bb14}}, [300 -> bb{{bb11}}, 299 -> bb{{bb12}}]... 12 | // ... 13 | // --- End aot --- 14 | // --- Begin jit-pre-opt --- 15 | // ... 16 | // %{{cond}}: i1 = eq %{{20}}, 300i32 17 | // guard true, %{{cond}}, ... 18 | // ... 19 | // --- End jit-pre-opt --- 20 | // i=2 21 | // yk-execution: enter-jit-code 22 | // i=1 23 | // yk-execution: deoptimise 24 | // ... 25 | 26 | // Check that tracing a non-default switch arm works correctly. 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | int main(int argc, char **argv) { 36 | YkMT *mt = yk_mt_new(NULL); 37 | yk_mt_hot_threshold_set(mt, 0); 38 | YkLocation loc = yk_location_new(); 39 | int i = 3; 40 | int j = 300; 41 | NOOPT_VAL(i); 42 | NOOPT_VAL(j); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | fprintf(stderr, "i=%d\n", i); 46 | switch (j) { 47 | case 300: // This case is traced. 48 | i--; 49 | break; 50 | case 299: 51 | exit(1); 52 | default: 53 | exit(1); 54 | } 55 | } 56 | yk_location_drop(loc); 57 | yk_mt_shutdown(mt); 58 | 59 | return (EXIT_SUCCESS); 60 | } 61 | -------------------------------------------------------------------------------- /tests/c/trace_too_long.c: -------------------------------------------------------------------------------- 1 | // ## This tests that traces that generate too many blocks cause "trace too 2 | // ## long" warnings. This can be very slow (e.g. on swt), so ignore it except 3 | // ## where we know it'll run fast enough. 4 | // ignore-if: test "$YKB_TRACER" != "swt" 5 | // Run-time: 6 | // env-var: YKD_SERIALISE_COMPILATION=1 7 | // env-var: YKD_LOG=3 8 | // stderr: 9 | // ... 10 | // yk-warning: stop-tracing-aborted: Trace overflowed recorder's storage 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main(int argc, char **argv) { 20 | YkMT *mt = yk_mt_new(NULL); 21 | yk_mt_hot_threshold_set(mt, 0); 22 | YkLocation loc = yk_location_new(); 23 | 24 | int i = 10; 25 | int t = 0; 26 | NOOPT_VAL(loc); 27 | NOOPT_VAL(i); 28 | NOOPT_VAL(t); 29 | while (i > 0) { 30 | yk_mt_control_point(mt, &loc); 31 | if (i == 10) { 32 | int j = 10000; 33 | while (j > 0) { 34 | t++; 35 | j--; 36 | } 37 | } 38 | NOOPT_VAL(i); 39 | i--; 40 | } 41 | printf("exit"); 42 | NOOPT_VAL(i); 43 | yk_location_drop(loc); 44 | yk_mt_shutdown(mt); 45 | return (EXIT_SUCCESS); 46 | } 47 | -------------------------------------------------------------------------------- /tests/c/trace_too_long_hwt.c: -------------------------------------------------------------------------------- 1 | // ## This test checks that an overflowing PT buffer is caught at the point 2 | // ## where a trace is stopped, not after trace mapping. It therefore only works 3 | // ## on hwt. 4 | // Run-time: 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=3 7 | // stderr: 8 | // ... 9 | // yk-warning: stop-tracing-aborted: Trace overflowed recorder's storage 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int main(int argc, char **argv) { 19 | YkMT *mt = yk_mt_new(NULL); 20 | yk_mt_hot_threshold_set(mt, 0); 21 | YkLocation loc = yk_location_new(); 22 | 23 | int i = 10; 24 | int t = 0; 25 | NOOPT_VAL(loc); 26 | NOOPT_VAL(i); 27 | NOOPT_VAL(t); 28 | while (i > 0) { 29 | yk_mt_control_point(mt, &loc); 30 | if (i == 10) { 31 | int j = 100000000; 32 | while (j > 0) { 33 | t++; 34 | j--; 35 | } 36 | } 37 | NOOPT_VAL(i); 38 | i--; 39 | } 40 | printf("exit"); 41 | NOOPT_VAL(i); 42 | yk_location_drop(loc); 43 | yk_mt_shutdown(mt); 44 | return (EXIT_SUCCESS); 45 | } 46 | -------------------------------------------------------------------------------- /tests/c/tracing_recursion1.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=jit-pre-opt 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // 6 7 | // yk-tracing: start-tracing 8 | // 5 9 | // yk-warning: tracing-aborted: tracing went outside of starting frame 10 | // ... 11 | 12 | // Check that traces that end in a different frame than they started in are 13 | // rejected. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | void loop(YkMT *, YkLocation *, int); 23 | 24 | void loop(YkMT *mt, YkLocation *loc, int i) { 25 | NOOPT_VAL(i); 26 | while (i > 0) { 27 | yk_mt_control_point(mt, loc); 28 | fprintf(stderr, "%d\n", i); 29 | if (i == 5) 30 | loop(mt, loc, i - 1); 31 | i--; 32 | } 33 | fprintf(stderr, "return\n"); 34 | return; 35 | } 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 1); 40 | yk_mt_sidetrace_threshold_set(mt, 2); 41 | YkLocation loc = yk_location_new(); 42 | 43 | loop(mt, &loc, 6); 44 | fprintf(stderr, "exit\n"); 45 | yk_location_drop(loc); 46 | yk_mt_shutdown(mt); 47 | return (EXIT_SUCCESS); 48 | } 49 | -------------------------------------------------------------------------------- /tests/c/truncate.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // yk-tracing: start-tracing 6 | // u64 18446744073709551615 7 | // u32 4294967295 8 | // u16 65535 9 | // u8 255 10 | // yk-tracing: stop-tracing 11 | // u64 18446744073709551615 12 | // u32 4294967295 13 | // u16 65535 14 | // u8 255 15 | // yk-execution: enter-jit-code 16 | // u64 18446744073709551615 17 | // u32 4294967295 18 | // u16 65535 19 | // u8 255 20 | // yk-execution: deoptimise 21 | // exit 22 | 23 | // Test truncation. 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main(int argc, char **argv) { 34 | YkMT *mt = yk_mt_new(NULL); 35 | yk_mt_hot_threshold_set(mt, 0); 36 | YkLocation loc = yk_location_new(); 37 | 38 | int i = 3; 39 | uint64_t x = UINT64_MAX; 40 | NOOPT_VAL(loc); 41 | NOOPT_VAL(i); 42 | NOOPT_VAL(x); 43 | while (i > 0) { 44 | yk_mt_control_point(mt, &loc); 45 | fprintf(stderr, "u64 %lu\n", x); 46 | fprintf(stderr, "u32 %u\n", (uint32_t)x); 47 | fprintf(stderr, "u16 %hu\n", (uint16_t)x); 48 | fprintf(stderr, "u8 %hhu\n", (uint8_t)x); 49 | i--; 50 | } 51 | fprintf(stderr, "exit\n"); 52 | yk_location_drop(loc); 53 | yk_mt_shutdown(mt); 54 | return (EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /tests/c/unintptr_t_to_ptr.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O1 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // 4: 0x4 10 | // yk-tracing: stop-tracing 11 | // --- Begin aot --- 12 | // ... 13 | // %{{11_2}}: ptr = int_to_ptr %{{11_1}}, ptr 14 | // ... 15 | // %{{11_3}}: i32 = call fprintf(%{{_}}, @{{_}}, %{{11_1}}, %{{11_2}}) 16 | // ... 17 | // --- End aot --- 18 | // 3: 0x3 19 | // yk-execution: enter-jit-code 20 | // 2: 0x2 21 | // 1: 0x1 22 | // yk-execution: deoptimise 23 | 24 | // Check that converting an integer to a pointer works. 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | int main(int argc, char **argv) { 33 | YkMT *mt = yk_mt_new(NULL); 34 | yk_mt_hot_threshold_set(mt, 0); 35 | YkLocation loc = yk_location_new(); 36 | 37 | uintptr_t i = 4; 38 | NOOPT_VAL(loc); 39 | NOOPT_VAL(i); 40 | while (i > 0) { 41 | yk_mt_control_point(mt, &loc); 42 | fprintf(stderr, "%" PRIuPTR ": %p\n", i, (void *) i); 43 | i--; 44 | } 45 | yk_location_drop(loc); 46 | yk_mt_shutdown(mt); 47 | return (EXIT_SUCCESS); 48 | } 49 | -------------------------------------------------------------------------------- /tests/c/unmapped_setjmp.c: -------------------------------------------------------------------------------- 1 | // ## FIXME: PT IP filtering means we can't reliably detect longjmp() in 2 | // ## external code. 3 | // ## FIXME: Implement setjmp/longjmp detection for swt. 4 | // ignore-if: true || test "$YKB_TRACER" = "swt" 5 | // Run-time: 6 | // env-var: YKD_SERIALISE_COMPILATION=1 7 | // env-var: YKD_LOG=3 8 | // stderr: 9 | // yk-tracing: start-tracing 10 | // set jump point 11 | // jumped! 12 | // yk-tracing: stop-tracing 13 | // yk-warning: trace-compilation-aborted: longjmp encountered 14 | // ... 15 | 16 | // Check that we bork on a call to setjmp in unmapped code. 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | void unmapped_setjmp(void); 26 | 27 | int main(int argc, char **argv) { 28 | YkMT *mt = yk_mt_new(NULL); 29 | yk_mt_hot_threshold_set(mt, 0); 30 | YkLocation loc = yk_location_new(); 31 | 32 | int i = 4; 33 | NOOPT_VAL(loc); 34 | NOOPT_VAL(i); 35 | while (i > 0) { 36 | yk_mt_control_point(mt, &loc); 37 | unmapped_setjmp(); 38 | i--; 39 | } 40 | 41 | yk_location_drop(loc); 42 | yk_mt_shutdown(mt); 43 | return (EXIT_SUCCESS); 44 | } 45 | -------------------------------------------------------------------------------- /tests/c/unroll_safe_implies_noinline.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=aot 4 | // stderr: 5 | // ... 6 | // --- Begin aot --- 7 | // ... 8 | // call never_aot_inline(... 9 | // ... 10 | // --- End aot --- 11 | // ... 12 | 13 | // Check that `yk_unroll_safe` implies `noinline` (thus blocking AOT inlining). 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | int call_me(int x); // from extra_linkage/call_me.c 24 | 25 | // A function containing a loop and marked `yk_unroll_safe`. 26 | __attribute__((yk_unroll_safe)) void never_aot_inline(int x) { 27 | while (x--) 28 | call_me(x); 29 | } 30 | 31 | int main(int argc, char **argv) { 32 | YkMT *mt = yk_mt_new(NULL); 33 | yk_mt_hot_threshold_set(mt, 0); 34 | YkLocation loc = yk_location_new(); 35 | 36 | int i = 4; 37 | NOOPT_VAL(loc); 38 | NOOPT_VAL(i); 39 | while (i > 0) { 40 | yk_mt_control_point(mt, &loc); 41 | never_aot_inline(i); 42 | i--; 43 | } 44 | yk_location_drop(loc); 45 | yk_mt_shutdown(mt); 46 | return (EXIT_SUCCESS); 47 | } 48 | -------------------------------------------------------------------------------- /tests/c/unroll_safe_inlines.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=jit-pre-opt 4 | // stderr: 5 | // ... 6 | // --- Begin jit-pre-opt --- 7 | // ... 8 | // %{{12}}: i32 = call @call_me(... 9 | // ... 10 | // --- End jit-pre-opt --- 11 | 12 | // Check that a loopy function annotated `yk_unroll_safe` always gets inlined 13 | // into the trace. 14 | // 15 | // We can only see a call to `call_me()` in the trace if `inline_into_trace()` 16 | // itself was also inlined into the trace. 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int call_me(int x); // from extra_linkage/call_me.c 27 | 28 | // A function containing a loop and marked `yk_unroll_safe`. 29 | // 30 | // We mark is `noinline` as well because we want to test that it gets inlined 31 | // during tracing, not during AOT compilation. 32 | __attribute__((yk_unroll_safe, noinline)) void inline_into_trace(int x) { 33 | while (x--) 34 | call_me(x); 35 | } 36 | 37 | int main(int argc, char **argv) { 38 | YkMT *mt = yk_mt_new(NULL); 39 | yk_mt_hot_threshold_set(mt, 0); 40 | YkLocation loc = yk_location_new(); 41 | 42 | int i = 7; 43 | NOOPT_VAL(loc); 44 | NOOPT_VAL(i); 45 | while (i > 0) { 46 | yk_mt_control_point(mt, &loc); 47 | inline_into_trace(i); 48 | i--; 49 | } 50 | yk_location_drop(loc); 51 | yk_mt_shutdown(mt); 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /tests/c/varargs.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG=4 4 | // stderr: 5 | // yk-tracing: start-tracing 6 | // i=6 7 | // yk-tracing: stop-tracing 8 | // i=6 9 | // yk-execution: enter-jit-code 10 | // i=6 11 | // i=6 12 | // yk-execution: deoptimise 13 | 14 | // Check varargs calls work. 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | int varargfunc(int len, ...) { 25 | int acc = 0; 26 | va_list argp; 27 | va_start(argp, len); 28 | for (int i = 0; i < len; i++) { 29 | int arg = va_arg(argp, int); 30 | acc += arg; 31 | } 32 | va_end(argp); 33 | return acc; 34 | } 35 | 36 | int main(int argc, char **argv) { 37 | YkMT *mt = yk_mt_new(NULL); 38 | yk_mt_hot_threshold_set(mt, 0); 39 | YkLocation loc = yk_location_new(); 40 | 41 | int i = 4; 42 | NOOPT_VAL(loc); 43 | NOOPT_VAL(i); 44 | while (i > 0) { 45 | yk_mt_control_point(mt, &loc); 46 | int res = varargfunc(3, argc, 2, 3); 47 | fprintf(stderr, "i=%d\n", res); 48 | i--; 49 | } 50 | yk_location_drop(loc); 51 | yk_mt_shutdown(mt); 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /tests/c/varargs_inlined.c: -------------------------------------------------------------------------------- 1 | // ## trace-compilation-aborted: dlsym("llvm.va_start") returned NULL 2 | // ignore-if: true 3 | // Run-time: 4 | // env-var: YKD_LOG_IR=aot 5 | // env-var: YKD_SERIALISE_COMPILATION=1 6 | // env-var: YKD_LOG=4 7 | // stderr: 8 | // yk-tracing: start-tracing 9 | // i=1 10 | // yk-tracing: stop-tracing 11 | // --- Begin aot --- 12 | // ... 13 | // call llvm.va_start... 14 | // ... 15 | // call llvm.va_end... 16 | // ... 17 | // --- End aot --- 18 | // i=1 19 | // yk-execution: enter-jit-code 20 | // i=1 21 | // i=1 22 | // yk-execution: deoptimise 23 | 24 | // Check that inlining works when the function is vararg. 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | int varargfunc(int len, ...) { 35 | int acc = 0; 36 | va_list argp; 37 | va_start(argp, len); 38 | int arg = va_arg(argp, int); 39 | acc += arg; 40 | va_end(argp); 41 | return acc; 42 | } 43 | 44 | int foo(int argc) { return varargfunc(3, argc, 2, 3); } 45 | 46 | int main(int argc, char **argv) { 47 | YkMT *mt = yk_mt_new(NULL); 48 | yk_mt_hot_threshold_set(mt, 0); 49 | YkLocation loc = yk_location_new(); 50 | 51 | int i = 4; 52 | NOOPT_VAL(loc); 53 | NOOPT_VAL(i); 54 | while (i > 0) { 55 | yk_mt_control_point(mt, &loc); 56 | int res = foo(argc); 57 | fprintf(stderr, "i=%d\n", res); 58 | i--; 59 | } 60 | yk_location_drop(loc); 61 | yk_mt_shutdown(mt); 62 | return (EXIT_SUCCESS); 63 | } 64 | -------------------------------------------------------------------------------- /tests/c/void_ret.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=jit-pre-opt 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // ... 7 | // yk-execution: enter-jit-code 8 | // inside f 9 | // inside f 10 | // yk-execution: deoptimise 11 | // ... 12 | 13 | // Check inlining a function into the trace that has a void return type. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void __attribute__((noinline)) f() { 22 | fputs("inside f\n", stderr); 23 | return; 24 | } 25 | 26 | int main(int argc, char **argv) { 27 | 28 | YkMT *mt = yk_mt_new(NULL); 29 | yk_mt_hot_threshold_set(mt, 0); 30 | YkLocation loc = yk_location_new(); 31 | 32 | int i = 4; 33 | NOOPT_VAL(i); 34 | while (i > 0) { 35 | yk_mt_control_point(mt, &loc); 36 | f(); 37 | i--; 38 | } 39 | 40 | NOOPT_VAL(i); 41 | yk_location_drop(loc); 42 | yk_mt_shutdown(mt); 43 | return (EXIT_SUCCESS); 44 | } 45 | -------------------------------------------------------------------------------- /tests/c/yk_debug_str.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt,jit-post-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=3 5 | // stderr: 6 | // ... 7 | // --- Begin aot --- 8 | // ... 9 | // debug_str %{{10_0}} 10 | // ... 11 | // ...call fprintf(... 12 | // ... 13 | // debug_str %{{13_0}} 14 | // ... 15 | // --- End aot --- 16 | // ... 17 | // --- Begin jit-pre-opt --- 18 | // ... 19 | // ; debug_str: before fprintf: 4 20 | // ... 21 | // ...call @fprintf(... 22 | // ... 23 | // ; debug_str: after fprintf: 5 24 | // ... 25 | // --- End jit-pre-opt --- 26 | // ... 27 | // --- Begin jit-post-opt --- 28 | // ... 29 | // ; debug_str: before fprintf: 4 30 | // ... 31 | // ...call @fprintf(... 32 | // ... 33 | // ; debug_str: after fprintf: 5 34 | // ... 35 | // --- End jit-post-opt --- 36 | // ... 37 | 38 | // Check that yk_debug_str() works and is not optimised out. 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #define MAX_MSG 128 48 | 49 | int main(int argc, char **argv) { 50 | YkMT *mt = yk_mt_new(NULL); 51 | yk_mt_hot_threshold_set(mt, 0); 52 | YkLocation loc = yk_location_new(); 53 | char msg[MAX_MSG]; 54 | 55 | int i = 4; 56 | NOOPT_VAL(loc); 57 | NOOPT_VAL(i); 58 | while (i > 0) { 59 | yk_mt_control_point(mt, &loc); 60 | snprintf(msg, MAX_MSG, "before fprintf: %d", i); 61 | yk_debug_str(msg); 62 | fprintf(stderr, "%d\n", i); 63 | snprintf(msg, MAX_MSG, "after fprintf: %d", i + 1); 64 | yk_debug_str(msg); 65 | i--; 66 | } 67 | yk_location_drop(loc); 68 | yk_mt_shutdown(mt); 69 | return (EXIT_SUCCESS); 70 | } 71 | -------------------------------------------------------------------------------- /tests/c/yk_outline_dynamic_with_promote.c: -------------------------------------------------------------------------------- 1 | // Compiler: 2 | // env-var: YKB_EXTRA_CC_FLAGS=-O2 3 | // Run-time: 4 | // env-var: YKD_SERIALISE_COMPILATION=1 5 | 6 | // Check that promotes in indirect callees of outlined functions are consumed 7 | // properly during outlining. If we failed to consume them, an assertion would 8 | // fail in the trace builder. 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | __attribute__((noinline)) 17 | uintptr_t g(uintptr_t x) { 18 | return yk_promote(x) + 1; 19 | } 20 | 21 | __attribute__((yk_outline)) 22 | uintptr_t f(uintptr_t x) { 23 | // force an indirect call. 24 | uintptr_t (*fptr)(uintptr_t) = g; 25 | NOOPT_VAL(fptr); 26 | return fptr(x); 27 | } 28 | 29 | int main(int argc, char **argv) { 30 | YkMT *mt = yk_mt_new(NULL); 31 | yk_mt_hot_threshold_set(mt, 0); 32 | YkLocation loc = yk_location_new(); 33 | 34 | size_t i = 4; 35 | NOOPT_VAL(loc); 36 | NOOPT_VAL(i); 37 | while (i > 0) { 38 | yk_mt_control_point(mt, &loc); 39 | fprintf(stderr, "%" PRIuPTR ": %" PRIuPTR "\n", i, f(1)); 40 | i--; 41 | } 42 | yk_location_drop(loc); 43 | yk_mt_shutdown(mt); 44 | return (EXIT_SUCCESS); 45 | } 46 | -------------------------------------------------------------------------------- /tests/c/yk_unroll_safe_vs_yk_outline.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_SERIALISE_COMPILATION=1 3 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 4 | // stderr: 5 | // ... 6 | // --- Begin aot --- 7 | // ... 8 | // #[yk_outline] 9 | // func never_inline_into_trace(... 10 | // ... 11 | // --- End aot --- 12 | // --- Begin jit-pre-opt --- 13 | // ... 14 | // call @never_inline_into_trace(... 15 | // ... 16 | // --- End jit-pre-opt --- 17 | 18 | // Check that `yk_outline` wins over `yk_unroll_safe`. 19 | // 20 | // Although it is tempting to have clang emit an error when these conflicting attributes are used 21 | // together, the idiomatic "clang way" is to have one attribute win out over the other. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | int call_me(int x); // from extra_linkage/call_me.c 32 | 33 | // Both `yk_outline` and `yk_unroll_safe`! 34 | __attribute__((yk_outline, yk_unroll_safe)) void 35 | never_inline_into_trace(int x) { 36 | while (x--) 37 | call_me(x); 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | YkMT *mt = yk_mt_new(NULL); 42 | yk_mt_hot_threshold_set(mt, 0); 43 | YkLocation loc = yk_location_new(); 44 | 45 | int i = 4; 46 | NOOPT_VAL(loc); 47 | NOOPT_VAL(i); 48 | while (i > 0) { 49 | yk_mt_control_point(mt, &loc); 50 | never_inline_into_trace(i); 51 | i--; 52 | } 53 | yk_location_drop(loc); 54 | yk_mt_shutdown(mt); 55 | return (EXIT_SUCCESS); 56 | } 57 | -------------------------------------------------------------------------------- /tests/c/ykd_opt_off.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_OPT=0 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // stdout: 5 | // 10 6 | // 9 7 | // 8 8 | // 7 9 | // 7: 6 10 | // 7: 5 11 | // 7: 4 12 | // 7: 4: 3 13 | // 7: 4: 2 14 | // 7: 4: 1 15 | 16 | 17 | // Check that basic trace compilation works. 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int main(int argc, char **argv) { 27 | YkMT *mt = yk_mt_new(NULL); 28 | yk_mt_hot_threshold_set(mt, 0); 29 | yk_mt_sidetrace_threshold_set(mt, 1); 30 | YkLocation loc = yk_location_new(); 31 | 32 | int i = 10; 33 | NOOPT_VAL(loc); 34 | NOOPT_VAL(i); 35 | while (i > 0) { 36 | yk_mt_control_point(mt, &loc); 37 | if (i < 7) 38 | printf("7: "); 39 | if (i < 4) 40 | printf("4: "); 41 | printf("%d\n", i); 42 | i--; 43 | } 44 | yk_location_drop(loc); 45 | yk_mt_shutdown(mt); 46 | return (EXIT_SUCCESS); 47 | } 48 | -------------------------------------------------------------------------------- /tests/c/zext.c: -------------------------------------------------------------------------------- 1 | // Run-time: 2 | // env-var: YKD_LOG_IR=aot,jit-pre-opt 3 | // env-var: YKD_SERIALISE_COMPILATION=1 4 | // env-var: YKD_LOG=4 5 | // stderr: 6 | // yk-tracing: start-tracing 7 | // int to long 4 8 | // long to long long 4 9 | // uint8_t to uint32_t 3 10 | // yk-tracing: stop-tracing 11 | // --- Begin aot --- 12 | // ... 13 | // func main(%arg0: i32, %arg1: ptr) -> i32 { 14 | // ... 15 | // --- End aot --- 16 | // --- Begin jit-pre-opt --- 17 | // ... 18 | // --- End jit-pre-opt --- 19 | // int to long 3 20 | // long to long long 3 21 | // uint8_t to uint32_t 3 22 | // yk-execution: enter-jit-code 23 | // int to long 2 24 | // long to long long 2 25 | // uint8_t to uint32_t 3 26 | // int to long 1 27 | // long to long long 1 28 | // uint8_t to uint32_t 3 29 | // yk-execution: deoptimise 30 | // exit 31 | 32 | // Test zero extend. 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | int main(int argc, char **argv) { 43 | YkMT *mt = yk_mt_new(NULL); 44 | yk_mt_hot_threshold_set(mt, 0); 45 | YkLocation loc = yk_location_new(); 46 | 47 | unsigned int i = 4; 48 | uint8_t j = 3; 49 | NOOPT_VAL(loc); 50 | NOOPT_VAL(i); 51 | while (i > 0) { 52 | yk_mt_control_point(mt, &loc); 53 | long x = i; 54 | long long y = x; 55 | uint32_t z = j; 56 | fprintf(stderr, "int to long %ld\n", x); 57 | fprintf(stderr, "long to long long %lld\n", y); 58 | fprintf(stderr, "uint8_t to uint32_t %d\n", z); 59 | i--; 60 | } 61 | fprintf(stderr, "exit\n"); 62 | yk_location_drop(loc); 63 | yk_mt_shutdown(mt); 64 | return (EXIT_SUCCESS); 65 | } 66 | -------------------------------------------------------------------------------- /tests/extra_linkage/call_me.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "yk_testing.h" 6 | 7 | int call_me(int x) { return 5; } 8 | 9 | int call_me_add(int x) { return x + 1; } 10 | 11 | int call_callback(int (*callback)(int, int), int x, int y) { 12 | return callback(x, y); 13 | } 14 | 15 | jmp_buf jbuf; 16 | void unmapped_setjmp(void) { 17 | if (setjmp(jbuf) == 0) { 18 | fprintf(stderr, "set jump point\n"); 19 | NOOPT_VAL(jbuf); 20 | longjmp(jbuf, 1); 21 | } else { 22 | fprintf(stderr, "jumped!\n"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/extra_linkage/fudge.s: -------------------------------------------------------------------------------- 1 | .global fudge_return_address 2 | .intel_syntax 3 | 4 | # Function that returns to the address stored in its first argument. 5 | fudge_return_address: 6 | pop rax 7 | push rdi 8 | ret 9 | -------------------------------------------------------------------------------- /tests/extra_linkage/pt_zero_len_call.s: -------------------------------------------------------------------------------- 1 | .global zero_len_call 2 | .intel_syntax 3 | 4 | # A little function that returns the value of RIP via (what Intel calls) a 5 | # "zero-length call". 6 | zero_len_call: 7 | mov rax, 0 8 | call y # zero-length return. 9 | y: 10 | # FIXME: There have to be an equal number of calls and returns or the 11 | # outliner's frame counter will get confused. We've already done a `call` 12 | # with no matching `ret`, so now we have to do a `ret` with no matching 13 | # `call`. 14 | # 15 | # Once https://github.com/ykjit/yk/issues/818 is fixed, we can hopefully 16 | # remove this hack. 17 | # 18 | # Note that `push z` doesn't do what you think it would! 19 | lea rdi, [z] 20 | push rdi 21 | ret 22 | z: 23 | pop rax 24 | ret 25 | -------------------------------------------------------------------------------- /tests/ir_lowering/after_alloca.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main(%arg0: i32, %arg1: ptr) -> i32 { 5 | ; bb0: 6 | ; %0_0: i32 = arg(0) 7 | ; %0_1: ptr = arg(1) 8 | ; %0_2: ptr = alloca i32, 1, 4 9 | ; *%0_2 = 1i32 10 | ; %0_4: i1 = eq %0_0, 1i32 11 | ; condbr %0_4, bb1, bb2 [safepoint: 1i64, ()] 12 | ; ... 13 | 14 | 15 | ; Check that a instructions following a call are correctly lowered. 16 | 17 | declare void @llvm.experimental.stackmap(i64, i32, ...); 18 | 19 | define i32 @f(i32 %0) noinline { 20 | ret i32 %0 21 | } 22 | 23 | define i32 @main(i32 %argc, ptr %argv) { 24 | entry: 25 | %0 = alloca i32 26 | store i32 1, ptr %0 27 | %1 = icmp eq i32 %argc, 1 28 | call void (i64, i32, ...) @llvm.experimental.stackmap(i64 1, i32 0); 29 | br i1 %1, label %bb1, label %bb2 30 | 31 | bb1: 32 | ret i32 0 33 | 34 | bb2: 35 | ret i32 1 36 | } 37 | -------------------------------------------------------------------------------- /tests/ir_lowering/after_call.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main(%arg0: i32, %arg1: ptr) -> i32 { 5 | ; bb0: 6 | ; %0_0: i32 = arg(0) 7 | ; %0_1: ptr = arg(1) 8 | ; %0_2: i32 = call f(%0_0) [safepoint: 1i64, ()] 9 | ; %0_3: i1 = eq %0_0, 1i32 10 | ; condbr %0_3, bb1, bb2 [safepoint: 2i64, ()] 11 | ; ... 12 | 13 | ; Check that a instructions following a call are correctly lowered. 14 | 15 | declare void @llvm.experimental.stackmap(i64, i32, ...); 16 | 17 | define i32 @f(i32 %0) noinline { 18 | ret i32 %0 19 | } 20 | 21 | define i32 @main(i32 %argc, ptr %argv) { 22 | entry: 23 | %0 = call i32 @f(i32 %argc) 24 | call void (i64, i32, ...) @llvm.experimental.stackmap(i64 1, i32 0); 25 | %1 = icmp eq i32 %argc, 1 26 | call void (i64, i32, ...) @llvm.experimental.stackmap(i64 2, i32 0); 27 | br i1 %1, label %bb1, label %bb2 28 | 29 | bb1: 30 | ret i32 0 31 | 32 | bb2: 33 | ret i32 1 34 | } 35 | -------------------------------------------------------------------------------- /tests/ir_lowering/call_operands.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main() -> i32 { 5 | ; bb0: 6 | ; call f(1i32, 2i32, 3i32) [safepoint: 1i64, ()] 7 | ; ret 0i32 8 | ; } 9 | ; 10 | ; func llvm.experimental.stackmap(%arg0: i64, %arg1: i32, ...); 11 | 12 | ; Check a call instruction lowers and prints correctly. 13 | ; 14 | ; The reason for this is that in LLVM's IR data structures the call target is 15 | ; the last operand, but in Yk's IR it's the first. A generic lowering would do 16 | ; the wrong thing. 17 | 18 | declare void @llvm.experimental.stackmap(i64, i32, ...); 19 | 20 | define void @f(i32 %0, i32 %1, i32 %2) { ret void } 21 | 22 | define i32 @main() { 23 | entry: 24 | call void @f(i32 1, i32 2, i32 3); 25 | call void (i64, i32, ...) @llvm.experimental.stackmap(i64 1, i32 0); 26 | ret i32 0 27 | } 28 | -------------------------------------------------------------------------------- /tests/ir_lowering/const_floats.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; %{{_}}: float = fadd 3.5float, %{{_}} 5 | ; %{{_}}: double = fadd 4.35double, %{{_}} 6 | ; ... 7 | 8 | ; Check that lowering floating point constants works. 9 | 10 | define void @main(float %x, double %y) { 11 | entry: 12 | %a = fadd float 3.5, %x 13 | %b = fadd double 4.35, %y 14 | ret void 15 | } 16 | -------------------------------------------------------------------------------- /tests/ir_lowering/empty.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; # IR format version: 0 4 | ; # Num funcs: 1 5 | ; # Num consts: 0 6 | ; # Num global decls: 0 7 | ; # Num types: 2 8 | ; 9 | ; func main() { 10 | ; bb0: 11 | ; ret 12 | ; } 13 | 14 | ; The simplest test you could write. Checks an empty module lowers correctly. 15 | 16 | define void @main() { 17 | entry: 18 | ret void 19 | } 20 | -------------------------------------------------------------------------------- /tests/ir_lowering/func_ty.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main(%arg0: i32, %arg1: ptr) -> i32 { 5 | ; ... 6 | 7 | ; Check function type lowering. 8 | 9 | define i32 @main(i32 %argc, ptr %argv) { 10 | ret i32 1 11 | } 12 | -------------------------------------------------------------------------------- /tests/ir_lowering/icmp_predicates.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; bb0: 5 | ; %0_0: i1 = arg(0) 6 | ; %0_1: i1 = arg(1) 7 | ; %0_2: i1 = eq %0_0, %0_1 8 | ; %0_3: i1 = ne %0_2, %0_1 9 | ; %0_4: i1 = ult %0_2, %0_3 10 | ; %0_5: i1 = ule %0_3, %0_4 11 | ; %0_6: i1 = ugt %0_4, %0_5 12 | ; %0_7: i1 = uge %0_5, %0_6 13 | ; %0_8: i1 = slt %0_6, %0_7 14 | ; %0_9: i1 = sle %0_7, %0_8 15 | ; %0_10: i1 = sgt %0_8, %0_9 16 | ; %0_11: i1 = sge %0_9, %0_10 17 | ; ret %0_11 18 | ; ... 19 | 20 | ; Check that icmp predicates lower correctly. 21 | 22 | define i1 @main(i1 %op1, i1 %op2) { 23 | entry: 24 | %0 = icmp eq i1 %op1, %op2 25 | %1 = icmp ne i1 %0, %op2 26 | %2 = icmp ult i1 %0, %1 27 | %3 = icmp ule i1 %1, %2 28 | %4 = icmp ugt i1 %2, %3 29 | %5 = icmp uge i1 %3, %4 30 | %6 = icmp slt i1 %4, %5 31 | %7 = icmp sle i1 %5, %6 32 | %8 = icmp sgt i1 %6, %7 33 | %9 = icmp sge i1 %7, %8 34 | ret i1 %9 35 | } 36 | -------------------------------------------------------------------------------- /tests/ir_lowering/mem_access.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main(%arg0: ptr) { 5 | ; bb0: 6 | ; %0_0: ptr = arg(0) 7 | ; %0_1: i8 = load %0_0 8 | ; %0_2: i8 = load %0_0, volatile 9 | ; %0_3: i8 = load %0_0 10 | ; %0_4: i8 = load %0_0 11 | ; %0_5: i16 = unimplemented << %6 = load i16, ptr %0, align 1>> 12 | ; *%0_0 = 0i8 13 | ; *%0_0 = 0i8, volatile 14 | ; *%0_0 = 0i8 15 | ; *%0_0 = 0i8 16 | ; unimplemented << store i16 0, ptr %0, align 1>> 17 | ; ret 18 | ; } 19 | 20 | ; Check that loads and stores lower OK. 21 | 22 | define void @main(ptr %p) optnone noinline { 23 | entry: 24 | %l0 = load i8, ptr %p 25 | %l1 = load volatile i8, ptr %p 26 | %l2 = load i8, ptr %p, align 1 27 | %l3 = load i8, ptr %p, align 8 28 | %l4 = load i16, ptr %p, align 1 ; potentially misaligned 29 | store i8 0, ptr %p 30 | store volatile i8 0, ptr %p 31 | store i8 0, ptr %p, align 1 32 | store i8 0, ptr %p, align 8 33 | store i16 0, ptr %p, align 1 ; potentially misaligned 34 | ret void 35 | } 36 | -------------------------------------------------------------------------------- /tests/ir_lowering/non_byte_sized_int_constant.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main() -> i1 { 5 | ; bb0: 6 | ; ret 0i1 7 | ; } 8 | ; ... 9 | 10 | ; Check that lowering non-byte-sized integer constants works. 11 | 12 | define i1 @main() { 13 | entry: 14 | ; Here we return a 1-bit constant integer. 15 | ret i1 0 16 | } 17 | -------------------------------------------------------------------------------- /tests/ir_lowering/null_ptr.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main() -> ptr { 5 | ; bb0: 6 | ; ret 0x0 7 | ; } 8 | 9 | ; Check null pointer constants lower OK. 10 | 11 | define ptr @main() { 12 | ret ptr null 13 | } 14 | -------------------------------------------------------------------------------- /tests/ir_lowering/struct.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func main(%arg0: {0: i32, 64: i64}) { 5 | ; bb0: 6 | ; %0_0: {0: i32, 64: i64} = arg(0) 7 | ; %0_1: {0: i32, 64: i64} = insert_val %0_0, 100i32 8 | ; ret 9 | ; } 10 | 11 | ; Check that a structure type lowers correctly. 12 | 13 | %s = type { i32, i64 } 14 | 15 | define void @main(%s %val) { 16 | entry: 17 | %0 = insertvalue %s %val, i32 100, 0 18 | ret void 19 | } 20 | -------------------------------------------------------------------------------- /tests/ir_lowering/vararg_call.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func f(%arg0: i32, ...) -> i32 { 5 | ; ... 6 | ; func main(... 7 | ; bb0: 8 | ; %0_0: i32 = arg(0) 9 | ; ... 10 | ; %0_2: i32 = call f(%0_0) [safepoint: 1i64, ()] 11 | ; ... 12 | 13 | 14 | ; Check that varargs calls lower properly. 15 | 16 | declare void @llvm.experimental.stackmap(i64, i32, ...); 17 | define i32 @f(i32 %0, ...) noinline { ret i32 6 } 18 | 19 | define i32 @main(i32 %argc, ptr %argv) { 20 | entry: 21 | %0 = call i32 (i32, ...) @f(i32 %argc) 22 | call void (i64, i32, ...) @llvm.experimental.stackmap(i64 1, i32 0); 23 | ret i32 1 24 | } 25 | -------------------------------------------------------------------------------- /tests/ir_lowering/vararg_func_ty.ll: -------------------------------------------------------------------------------- 1 | ; Dump: 2 | ; stdout: 3 | ; ... 4 | ; func f(%arg0: i32, ...) -> i32 { 5 | ; ... 6 | 7 | ; Check a vararg function type lowers correctly. 8 | 9 | declare void @llvm.experimental.stackmap(i64, i32, ...); 10 | 11 | define i32 @f(i32 %0, ...) { 12 | ret i32 %0 13 | } 14 | 15 | define i32 @main() { 16 | %1 = call i32 (i32, ...) @f(i32 1, i32 2, i32 3); 17 | call void (i64, i32, ...) @llvm.experimental.stackmap(i64 1, i32 0); 18 | ret i32 %1 19 | } 20 | -------------------------------------------------------------------------------- /tests/lua/for_loop.lua: -------------------------------------------------------------------------------- 1 | -- ignore-if: test "$YKB_TRACER" = "swt" 2 | -- Run-time: 3 | -- env-var: YK_HOT_THRESHOLD=3 4 | -- env-var: YKD_LOG=4 5 | -- env-var: YKD_LOG_IR=debugstrs 6 | -- env-var: YKD_SERIALISE_COMPILATION=1 7 | -- stderr: 8 | -- 0 9 | -- 1 10 | -- 2 11 | -- yk-tracing: start-tracing: for_loop.lua:35: GETTABUP 12 | -- 3 13 | -- yk-tracing: stop-tracing: for_loop.lua:35: GETTABUP 14 | -- --- Begin debugstrs: header: for_loop.lua:35: GETTABUP --- 15 | -- for_loop.lua:35: GETTABUP 16 | -- for_loop.lua:35: GETFIELD 17 | -- for_loop.lua:35: SELF 18 | -- for_loop.lua:35: GETTABUP 19 | -- for_loop.lua:35: MOVE 20 | -- for_loop.lua:35: CALL 21 | -- for_loop.lua:35: LOADK 22 | -- for_loop.lua:35: CALL 23 | -- for_loop.lua:36: ADDI 24 | -- for_loop.lua:34: FORLOOP 25 | -- --- End debugstrs --- 26 | -- 4 27 | -- yk-execution: enter-jit-code: for_loop.lua:35: GETTABUP 28 | -- 5 29 | -- 6 30 | -- yk-execution: deoptimise 31 | -- exit 32 | 33 | local x = 0 34 | for _ = 0, 6 do 35 | io.stderr:write(tostring(x), "\n") 36 | x = x + 1 37 | end 38 | io.stderr:write("exit\n") 39 | -------------------------------------------------------------------------------- /tests/lua/inline_indirect_call.lua: -------------------------------------------------------------------------------- 1 | -- ignore-if: test "$YKB_TRACER" = "swt" 2 | -- Run-time: 3 | -- env-var: YK_HOT_THRESHOLD=3 4 | -- env-var: YKD_LOG=4 5 | -- env-var: YKD_LOG_IR=jit-pre-opt 6 | -- env-var: YKD_SERIALISE_COMPILATION=1 7 | 8 | -- FIXME: I don't think there's any output we could easily check to ensure 9 | -- luaB_assert has been inlined? 10 | 11 | for i = 0, 100 do 12 | A = {} 13 | assert(A) -- causes an icall in the trace. 14 | end 15 | 16 | io.stderr:write("exit\n") 17 | -------------------------------------------------------------------------------- /tests/lua/recursive_function.lua: -------------------------------------------------------------------------------- 1 | -- ignore-if: test "$YKB_TRACER" = "swt" 2 | -- Run-time: 3 | -- env-var: YK_HOT_THRESHOLD=2 4 | -- env-var: YKD_LOG=4 5 | -- env-var: YKD_LOG_IR=debugstrs 6 | -- env-var: YKD_SERIALISE_COMPILATION=1 7 | -- stderr: 8 | -- 6 9 | -- 5 10 | -- 4 11 | -- yk-tracing: start-tracing: recursive_function.lua:36: GETTABUP 12 | -- 3 13 | -- yk-tracing: stop-tracing: recursive_function.lua:36: GETTABUP 14 | -- --- Begin debugstrs: header: recursive_function.lua:36: GETTABUP --- 15 | -- recursive_function.lua:36: GETTABUP 16 | -- recursive_function.lua:36: GETFIELD 17 | -- recursive_function.lua:36: SELF 18 | -- recursive_function.lua:36: GETTABUP 19 | -- recursive_function.lua:36: MOVE 20 | -- recursive_function.lua:36: CALL 21 | -- recursive_function.lua:36: LOADK 22 | -- recursive_function.lua:36: CALL 23 | -- recursive_function.lua:37: GTI 24 | -- recursive_function.lua:38: GETTABUP 25 | -- recursive_function.lua:38: ADDI 26 | -- recursive_function.lua:38: CALL 27 | -- --- End debugstrs --- 28 | -- 2 29 | -- yk-execution: enter-jit-code: recursive_function.lua:36: GETTABUP 30 | -- 1 31 | -- 0 32 | -- yk-execution: deoptimise 33 | -- exit 34 | 35 | function f(x) 36 | io.stderr:write(tostring(x), "\n") 37 | if x > 0 then 38 | f(x - 1) 39 | end 40 | end 41 | 42 | f(6) 43 | io.stderr:write("exit\n") 44 | -------------------------------------------------------------------------------- /tests/lua/while_loop.lua: -------------------------------------------------------------------------------- 1 | -- ignore-if: test "$YKB_TRACER" = "swt" 2 | -- Run-time: 3 | -- env-var: YK_HOT_THRESHOLD=3 4 | -- env-var: YKD_LOG=4 5 | -- env-var: YKD_LOG_IR=debugstrs 6 | -- env-var: YKD_SERIALISE_COMPILATION=1 7 | -- stderr: 8 | -- 0 9 | -- 1 10 | -- 2 11 | -- yk-tracing: start-tracing: while_loop.lua:35: LEI 12 | -- 3 13 | -- yk-tracing: stop-tracing: ... 14 | -- --- Begin debugstrs: header: while_loop.lua:35: LEI --- 15 | -- while_loop.lua:35: LEI 16 | -- while_loop.lua:36: GETTABUP 17 | -- while_loop.lua:36: GETFIELD 18 | -- while_loop.lua:36: SELF 19 | -- while_loop.lua:36: GETTABUP 20 | -- while_loop.lua:36: MOVE 21 | -- while_loop.lua:36: CALL 22 | -- while_loop.lua:36: LOADK 23 | -- while_loop.lua:36: CALL 24 | -- while_loop.lua:37: ADDI 25 | -- while_loop.lua:37: JMP 26 | -- --- End debugstrs --- 27 | -- 4 28 | -- yk-execution: enter-jit-code: while_loop.lua:35: LEI 29 | -- 5 30 | -- 6 31 | -- yk-execution: deoptimise 32 | -- exit 33 | 34 | local x = 0 35 | while x <= 6 do 36 | io.stderr:write(tostring(x), "\n") 37 | x = x + 1 38 | end 39 | io.stderr:write("exit\n") 40 | -------------------------------------------------------------------------------- /tests/src/bin/dump_ir.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | env, 3 | error::Error, 4 | path::PathBuf, 5 | process::{exit, Command}, 6 | }; 7 | use tempfile::TempDir; 8 | use ykrt::compile::jitc_yk::aot_ir; 9 | 10 | const OUTFILE: &str = "ykir"; 11 | 12 | #[cfg(target_family = "unix")] 13 | fn extract_bytecode(tempdir: &TempDir, fname: &str) -> Result> { 14 | let mut out_file = tempdir.path().to_owned(); 15 | out_file.push(OUTFILE); 16 | let output = Command::new("objcopy") 17 | .args([ 18 | "--dump-section", 19 | &format!(".yk_ir={}", out_file.to_str().unwrap()), 20 | fname, 21 | ]) 22 | .output()?; 23 | 24 | if !output.status.success() { 25 | return Err(String::from_utf8(output.stderr)?.into()); 26 | } 27 | 28 | Ok(out_file) 29 | } 30 | 31 | fn inner() -> Result<(), Box> { 32 | if let Some(exe) = env::args().nth(1) { 33 | let tempdir = TempDir::new()?; 34 | let bcfile = extract_bytecode(&tempdir, &exe)?; 35 | aot_ir::print_from_file(&bcfile)?; 36 | drop(tempdir); // hold it live until here so we can read from it. 37 | Ok(()) 38 | } else { 39 | Err(String::from("Dumps Yk IR from an executable binary.\n\nusage: dump_ir ").into()) 40 | } 41 | } 42 | 43 | fn main() { 44 | if let Err(e) = inner() { 45 | eprintln!("{e}"); 46 | exit(1); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "Apache-2.0 OR MIT" 6 | 7 | [dependencies] 8 | walkdir = "2.4" 9 | ykbuild = { path = "../ykbuild" } 10 | -------------------------------------------------------------------------------- /ykaddr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ykaddr" 3 | version = "0.1.0" 4 | authors = ["The Yk Developers"] 5 | edition = "2021" 6 | license = "Apache-2.0 OR MIT" 7 | 8 | [dependencies] 9 | cached = { version = "0.55.1", features = ["proc_macro"] } 10 | libc = "0.2" 11 | memmap2 = "0.9.4" 12 | phdrs = { git = "https://github.com/softdevteam/phdrs" } 13 | 14 | [build-dependencies] 15 | cc = "1.0.83" 16 | -------------------------------------------------------------------------------- /ykaddr/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut comp = cc::Build::new(); 3 | comp.file("src/find_main.c"); 4 | comp.compile("find_main"); 5 | } 6 | -------------------------------------------------------------------------------- /ykaddr/src/find_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Find the address of main. 3 | * 4 | * This is done in C due to this Rust bug: 5 | * https://github.com/rust-lang/rust/issues/101906 6 | */ 7 | 8 | extern int main(int argc, char **argv); 9 | 10 | void *find_main() { return main; } 11 | -------------------------------------------------------------------------------- /ykaddr/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Miscellaneous utilities. 2 | 3 | pub mod addr; 4 | pub mod obj; 5 | -------------------------------------------------------------------------------- /ykbuild/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ykbuild" 3 | version = "0.1.0" 4 | authors = ["The Yk Developers"] 5 | edition = "2021" 6 | license = "Apache-2.0 OR MIT" 7 | # The following makes ykbuild's cargo metadata available to any crate which 8 | # depends on it, providing depedents with the location of the ykllvm install dir. 9 | links = "ykbuild" 10 | 11 | [dependencies] 12 | glob = "0.3.1" 13 | tempfile = "3.8" 14 | 15 | [build-dependencies] 16 | fs4 = { version="0.13.1", features=["sync"] } 17 | rerun_except = "1.0.0" 18 | which = "7.0.3" 19 | -------------------------------------------------------------------------------- /ykbuild/completion-wrapper: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # This wrapper script is used to record compiler invocations in sub-builds. 4 | # That information can then be used for e.g. code completion purposes. 5 | # 6 | # It is also used to allow tests to insert extra flags into the compiler 7 | # invocation. 8 | 9 | set -e 10 | 11 | echo "${YK_COMPILER_PATH} ${YKB_EXTRA_CC_FLAGS} $@" > $(mktemp -p ${YK_COMPILER_TEMPDIR}) 12 | ${YK_COMPILER_PATH} ${YKB_EXTRA_CC_FLAGS} $@ 13 | -------------------------------------------------------------------------------- /ykbuild/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for the yk build system. 2 | 3 | use std::{ 4 | env, 5 | path::{Path, PathBuf}, 6 | }; 7 | 8 | pub mod completion_wrapper; 9 | 10 | /// Return the subdirectory of Cargo's `target` directory where we should be building things. 11 | /// 12 | /// There are no guarantees about where this directory will be or what its name is. 13 | pub fn target_dir() -> PathBuf { 14 | Path::new(env!("OUT_DIR")) 15 | .parent() 16 | .unwrap() 17 | .parent() 18 | .unwrap() 19 | .parent() 20 | .unwrap() 21 | .to_owned() 22 | } 23 | 24 | /// Return a [Path] to the directory containing a ykllvm installation. 25 | pub fn ykllvm_bin_dir() -> PathBuf { 26 | match env::var("YKB_YKLLVM_BIN_DIR") { 27 | Ok(x) => Path::new(&x).to_owned(), 28 | Err(_) => { 29 | // The directory returned here *must* be exactly the same as that produced by 30 | // `ykbuild/build.rs`. 31 | let mut ykllvm_dir = target_dir(); 32 | ykllvm_dir.push("ykllvm"); 33 | ykllvm_dir.push("bin"); 34 | ykllvm_dir 35 | } 36 | } 37 | } 38 | 39 | /// Return the location of the ykllvm binary `bin_name`. 40 | /// 41 | /// # Panics 42 | /// 43 | /// If `bin_name` is not found. 44 | pub fn ykllvm_bin(bin_name: &str) -> PathBuf { 45 | let mut p = ykllvm_bin_dir(); 46 | p.push(bin_name); 47 | if p.exists() { 48 | return p; 49 | } 50 | panic!("ykllvm binary {} not found", p.to_str().unwrap_or(bin_name)) 51 | } 52 | -------------------------------------------------------------------------------- /ykcapi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ykcapi" 3 | version = "0.1.0" 4 | authors = ["The Yk Developers"] 5 | edition = "2021" 6 | license = "Apache-2.0 OR MIT" 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | libc = "0.2.148" 13 | ykrt = { path = "../ykrt" } 14 | 15 | [build-dependencies] 16 | ykbuild = { path = "../ykbuild" } 17 | 18 | [features] 19 | yk_testing = ["ykrt/yk_testing"] 20 | ykd = [] 21 | -------------------------------------------------------------------------------- /ykcapi/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | pub fn main() { 4 | println!("cargo::rerun-if-env-changed=YKB_TRACER"); 5 | match env::var("YKB_TRACER") { 6 | Ok(ref tracer) if tracer == "swt" => println!("cargo::rustc-cfg=tracer_swt"), 7 | Ok(ref tracer) if tracer == "hwt" => println!("cargo::rustc-cfg=tracer_hwt"), 8 | #[cfg(all(target_arch = "x86_64", target_os = "linux"))] 9 | Err(env::VarError::NotPresent) => println!("cargo::rustc-cfg=tracer_hwt"), 10 | #[cfg(not(all(target_arch = "x86_64", target_os = "linux")))] 11 | Err(env::VarError::NotPresent) => println!("cargo::rustc-cfg=tracer_swt"), 12 | Ok(x) => panic!("Unknown tracer {x}"), 13 | Err(_) => panic!("Invalid value for YKB_TRACER"), 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ykrt/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /ykrt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ykrt" 3 | version = "0.1.0" 4 | authors = ["The Yk Developers"] 5 | edition = "2021" 6 | license = "Apache-2.0 OR MIT" 7 | 8 | [dependencies] 9 | atomic_enum = "0.3.0" 10 | byteorder = "1.4.3" 11 | deku = { version = "0.18.1", features = ["std"] } 12 | dynasmrt = "3.0.0" 13 | indexmap = "2.2.6" 14 | libc = "0.2.148" 15 | memmap2 = "0.9" 16 | num-traits = "0.2.16" 17 | num_cpus = "1.13.1" 18 | page_size = "0.6.0" 19 | cache-size = "0.7.0" 20 | parking_lot = "0.12.0" 21 | parking_lot_core = "0.9.1" 22 | static_assertions = "1.1.0" 23 | strum = { version = "0.27.1", features = ["derive"] } 24 | strum_macros = "0.27.1" 25 | tempfile = "3.8" 26 | thiserror = "2.0.12" 27 | typed-index-collections = "3.1.0" 28 | vob = "3.0.3" 29 | ykaddr = { path = "../ykaddr" } 30 | yksmp = { path = "../yksmp" } 31 | zydis = "4.1.0" 32 | 33 | [target.'cfg(all(target_arch = "x86_64", target_os = "linux"))'.dependencies] 34 | hwtracer = { path = "../hwtracer" } 35 | 36 | [dependencies.object] 37 | version = "0.36.7" 38 | default-features = false 39 | features = ["read_core", "elf"] 40 | 41 | [build-dependencies] 42 | cfgrammar = "0.13" 43 | lrlex = "0.13" 44 | lrpar = "0.13" 45 | regex = "1.9" 46 | ykbuild = { path = "../ykbuild" } 47 | which = "7.0" 48 | 49 | [features] 50 | # When set, the `ykd` feature enables a number of features that are helpful for 51 | # debugging the correctness and performance of an interpreter, most controlled 52 | # by `YKD_*` environment variables. 53 | ykd = [] 54 | # The `yk_testing` feature is purely for yk's internal use: do not use it 55 | # externally. 56 | yk_testing = [] 57 | 58 | [dev-dependencies] 59 | cfgrammar = "0.13" 60 | fm = "0.4.0" 61 | lazy_static = "1.5.0" 62 | lrlex = "0.13" 63 | lrpar = "0.13" 64 | rand = "0.9.0" 65 | regex = { version = "1.9", features = ["std"] } 66 | proptest = "1.6.0" 67 | -------------------------------------------------------------------------------- /ykrt/src/compile/jitc_yk/codegen/mod.rs: -------------------------------------------------------------------------------- 1 | //! The JIT's Code Generator. 2 | 3 | // FIXME: eventually delete. 4 | #![allow(dead_code)] 5 | 6 | use super::CompilationError; 7 | use crate::{ 8 | compile::{jitc_yk::jit_ir::Module, CompiledTrace}, 9 | location::HotLocation, 10 | MT, 11 | }; 12 | use parking_lot::Mutex; 13 | use std::{error::Error, sync::Arc}; 14 | 15 | mod abs_stack; 16 | pub(crate) mod reg_alloc; 17 | 18 | #[cfg(target_arch = "x86_64")] 19 | pub(crate) mod x64; 20 | 21 | /// A code generator. 22 | /// 23 | /// This must be capable of generating code for multiple modules, possibly in parallel. 24 | pub(crate) trait CodeGen: Send + Sync { 25 | /// Generate code for the module `m`. 26 | /// 27 | /// # Arguments 28 | /// 29 | /// * `sp_offset` - Stack pointer offset from the base pointer of the interpreter frame as 30 | /// defined in [super::YkSideTraceInfo::sp_offset]. 31 | /// * `root_offset` - Stack pointer offset of the root trace as defined in 32 | /// [super::YkSideTraceInfo::sp_offset]. 33 | /// * `prevguards` - List of [GuardIdx]'s of previous guards failures leading up to this trace. 34 | fn codegen( 35 | &self, 36 | m: Module, 37 | mt: Arc, 38 | hl: Arc>, 39 | ) -> Result, CompilationError>; 40 | } 41 | 42 | pub(crate) fn default_codegen() -> Result, Box> { 43 | #[cfg(target_arch = "x86_64")] 44 | return Ok(x64::X64CodeGen::new()?); 45 | 46 | #[cfg(not(target_arch = "x86_64"))] 47 | return Err("No code generator available for this platform".into()); 48 | } 49 | -------------------------------------------------------------------------------- /ykrt/src/compile/jitc_yk/codegen/reg_alloc.rs: -------------------------------------------------------------------------------- 1 | //! Register allocation. 2 | //! 3 | //! This module: 4 | //! - describes the generic interface to register allocators. 5 | //! - contains concrete implementations of register allocators. 6 | 7 | /// Where is an SSA variable stored? 8 | #[derive(Debug, Clone, Copy, PartialEq)] 9 | pub(crate) enum VarLocation { 10 | /// The SSA variable is on the stack of the of the executed trace or the main interpreter loop. 11 | /// Since we execute the trace on the main interpreter frame we can't distinguish the two. 12 | /// 13 | /// Note: two SSA variables can alias to the same `Stack` location. 14 | Stack { 15 | /// The offset from the base of the trace's function frame. 16 | frame_off: u32, 17 | /// Size in bytes of the allocation. 18 | size: usize, 19 | }, 20 | /// The SSA variable is a stack pointer with the value `RBP-frame_off`. 21 | /// 22 | /// Note: two SSA variables can alias to the same `Direct` location. 23 | Direct { 24 | /// The offset from the base of the trace's function frame. 25 | frame_off: i32, 26 | /// Size in bytes of the allocation. 27 | size: usize, 28 | }, 29 | /// The SSA variable is in a register. 30 | /// 31 | /// Note: two SSA variables can alias to the same `Register` location. 32 | Register(R), 33 | /// A constant integer `bits` wide (see [jit_ir::Const::ConstInt] for the constraints on the 34 | /// bit width) and with value `v`. 35 | ConstInt { bits: u32, v: u64 }, 36 | /// A constant float. 37 | ConstFloat(f64), 38 | /// A constant pointer. 39 | ConstPtr(usize), 40 | } 41 | -------------------------------------------------------------------------------- /ykrt/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Interpreter-facing API to the Yk meta-tracer. 2 | 3 | #![cfg_attr(test, feature(test))] 4 | #![feature(assert_matches)] 5 | #![feature(int_roundings)] 6 | #![feature(let_chains)] 7 | #![allow(clippy::too_many_arguments)] 8 | #![allow(clippy::type_complexity)] 9 | #![allow(clippy::upper_case_acronyms)] 10 | 11 | pub(crate) mod aotsmp; 12 | pub mod compile; 13 | mod job_queue; 14 | mod location; 15 | mod log; 16 | pub(crate) mod mt; 17 | pub mod promote; 18 | pub(crate) mod stack; 19 | pub(crate) mod thread_intercept; 20 | pub mod trace; 21 | 22 | pub use self::location::Location; 23 | pub use self::mt::{HotThreshold, MTThread, MT}; 24 | use std::ffi::{c_char, CStr}; 25 | 26 | #[allow(clippy::missing_safety_doc)] 27 | #[no_mangle] 28 | pub unsafe extern "C" fn yk_debug_str(msg: *const c_char) { 29 | MTThread::with_borrow_mut(|mtt| { 30 | mtt.insert_debug_str(unsafe { CStr::from_ptr(msg).to_string_lossy().into_owned() }); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /ykrt/src/stack.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | /// Which direction does the CPU stack grow when more room is required? 4 | pub(crate) enum StackDirection { 5 | /// The CPU stack grows "downwards" i.e. growth changes it to a lower address. 6 | GrowsToHigherAddress, 7 | /// The CPU stack grows "upwards" i.e. growth changes it to a higher address. 8 | GrowsToLowerAddress, 9 | } 10 | 11 | #[cfg(target_arch = "x86_64")] 12 | pub(crate) const STACK_DIRECTION: StackDirection = StackDirection::GrowsToLowerAddress; 13 | -------------------------------------------------------------------------------- /ykrt/src/trace/hwt/mod.rs: -------------------------------------------------------------------------------- 1 | //! Hardware tracing via hwtracer. 2 | 3 | use super::{AOTTraceIterator, TraceRecorder, TraceRecorderError}; 4 | use hwtracer::{HWTracerError, TemporaryErrorKind}; 5 | use std::{error::Error, sync::Arc}; 6 | 7 | pub(crate) mod mapper; 8 | pub(crate) use mapper::HWTTraceIterator; 9 | mod testing; 10 | 11 | pub(crate) struct HWTracer { 12 | backend: Arc, 13 | } 14 | 15 | impl HWTracer { 16 | pub fn new() -> Result> { 17 | Ok(HWTracer { 18 | backend: hwtracer::TracerBuilder::new().build()?, 19 | }) 20 | } 21 | } 22 | 23 | impl super::Tracer for HWTracer { 24 | fn start_recorder(self: Arc) -> Result, Box> { 25 | Ok(Box::new(HWTTraceRecorder { 26 | thread_tracer: Arc::clone(&self.backend).start_collector()?, 27 | })) 28 | } 29 | } 30 | 31 | /// Hardware thread tracer. 32 | #[derive(Debug)] 33 | struct HWTTraceRecorder { 34 | thread_tracer: Box, 35 | } 36 | 37 | impl TraceRecorder for HWTTraceRecorder { 38 | fn stop(self: Box) -> Result, TraceRecorderError> { 39 | match self.thread_tracer.stop_collector() { 40 | Ok(x) => Ok(Box::new(HWTTraceIterator::new(x)?)), 41 | Err(HWTracerError::Temporary(TemporaryErrorKind::TraceBufferOverflow)) => { 42 | Err(TraceRecorderError::TraceTooLong) 43 | } 44 | _ => todo!(), 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ykrt/src/trace/hwt/testing.rs: -------------------------------------------------------------------------------- 1 | //! This module is only enabled when the `yk_testing` feature is enabled. It contains functions 2 | //! that are only needed when testing internal yk code. 3 | 4 | use hwtracer::llvm_blockmap::LLVM_BLOCK_MAP; 5 | 6 | #[no_mangle] 7 | pub extern "C" fn __yktrace_hwt_mapper_blockmap_len() -> usize { 8 | LLVM_BLOCK_MAP.len() 9 | } 10 | -------------------------------------------------------------------------------- /ykrt/yk_gdb_plugin/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-I/usr/include/ -I/usr/local/include/ 2 | CFLAGS=-fPIC -g -Wextra -Wpedantic 3 | 4 | ../../target/yk_gdb_plugin.so: yk_gdb_plugin.c 5 | ${CC} ${CFLAGS} ${CPPFLAGS} -shared $< -o $@ 6 | 7 | .PHONY: clean 8 | clean: 9 | -rm ../../target/yk_gdb_plugin.so 10 | -------------------------------------------------------------------------------- /yksmp/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target/ 3 | -------------------------------------------------------------------------------- /yksmp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yksmp" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["The Yk Developers"] 6 | license = "Apache-2.0 OR MIT" 7 | --------------------------------------------------------------------------------