mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-02 19:32:17 +00:00
fix for bugged setjmp/longjmp on windows/llvm
This commit is contained in:
parent
08ab7996a0
commit
b9b19d6054
4 changed files with 105 additions and 7 deletions
|
@ -287,6 +287,82 @@ fn __roc_force_longjmp(a0: [*c]c_int, a1: c_int) callconv(.C) noreturn {
|
|||
longjmp(a0, a1);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .windows) {
|
||||
asm (
|
||||
\\.global windows_longjmp;
|
||||
\\windows_longjmp:
|
||||
\\ movq 0x00(%rcx), %rdx
|
||||
\\ movq 0x08(%rcx), %rbx
|
||||
\\ # note 0x10 is not used yet!
|
||||
\\ movq 0x18(%rcx), %rbp
|
||||
\\ movq 0x20(%rcx), %rsi
|
||||
\\ movq 0x28(%rcx), %rdi
|
||||
\\ movq 0x30(%rcx), %r12
|
||||
\\ movq 0x38(%rcx), %r13
|
||||
\\ movq 0x40(%rcx), %r14
|
||||
\\ movq 0x48(%rcx), %r15
|
||||
\\
|
||||
\\ # restore stack pointer
|
||||
\\ movq 0x10(%rcx), %rsp
|
||||
\\
|
||||
\\ # load jmp address
|
||||
\\ movq 0x50(%rcx), %r8
|
||||
\\
|
||||
\\ # set up return value
|
||||
\\ movq %rbx, %rax
|
||||
\\
|
||||
\\ movdqu 0x60(%rcx), %xmm6
|
||||
\\ movdqu 0x70(%rcx), %xmm7
|
||||
\\ movdqu 0x80(%rcx), %xmm8
|
||||
\\ movdqu 0x90(%rcx), %xmm9
|
||||
\\ movdqu 0xa0(%rcx), %xmm10
|
||||
\\ movdqu 0xb0(%rcx), %xmm11
|
||||
\\ movdqu 0xc0(%rcx), %xmm12
|
||||
\\ movdqu 0xd0(%rcx), %xmm13
|
||||
\\ movdqu 0xe0(%rcx), %xmm14
|
||||
\\ movdqu 0xf0(%rcx), %xmm15
|
||||
\\
|
||||
\\ jmp *%r8
|
||||
\\
|
||||
\\.global windows_setjmp;
|
||||
\\windows_setjmp:
|
||||
\\ movq %rdx, 0x00(%rcx)
|
||||
\\ movq %rbx, 0x08(%rcx)
|
||||
\\ # note 0x10 is not used yet!
|
||||
\\ movq %rbp, 0x18(%rcx)
|
||||
\\ movq %rsi, 0x20(%rcx)
|
||||
\\ movq %rdi, 0x28(%rcx)
|
||||
\\ movq %r12, 0x30(%rcx)
|
||||
\\ movq %r13, 0x38(%rcx)
|
||||
\\ movq %r14, 0x40(%rcx)
|
||||
\\ movq %r15, 0x48(%rcx)
|
||||
\\
|
||||
\\ # the stack location right after the windows_setjmp call
|
||||
\\ leaq 0x08(%rsp), %r8
|
||||
\\ movq %r8, 0x10(%rcx)
|
||||
\\
|
||||
\\ movq (%rsp), %r8
|
||||
\\ movq %r8, 0x50(%rcx)
|
||||
\\
|
||||
\\ movdqu %xmm6, 0x60(%rcx)
|
||||
\\ movdqu %xmm7, 0x70(%rcx)
|
||||
\\ movdqu %xmm8, 0x80(%rcx)
|
||||
\\ movdqu %xmm9, 0x90(%rcx)
|
||||
\\ movdqu %xmm10, 0xa0(%rcx)
|
||||
\\ movdqu %xmm11, 0xb0(%rcx)
|
||||
\\ movdqu %xmm12, 0xc0(%rcx)
|
||||
\\ movdqu %xmm13, 0xd0(%rcx)
|
||||
\\ movdqu %xmm14, 0xe0(%rcx)
|
||||
\\ movdqu %xmm15, 0xf0(%rcx)
|
||||
\\
|
||||
\\ xorl %eax, %eax
|
||||
\\ ret
|
||||
\\
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Export helpers - Must be run inside a comptime
|
||||
fn exportBuiltinFn(comptime func: anytype, comptime func_name: []const u8) void {
|
||||
@export(func, .{ .name = "roc_builtins." ++ func_name, .linkage = .Strong });
|
||||
|
|
|
@ -445,6 +445,9 @@ pub const NOTIFY_PARENT_EXPECT: &str = "roc_builtins.utils.notify_parent_expect"
|
|||
pub const UTILS_LONGJMP: &str = "longjmp";
|
||||
pub const UTILS_SETJMP: &str = "setjmp";
|
||||
|
||||
pub const UTILS_WINDOWS_LONGJMP: &str = "windows_longjmp";
|
||||
pub const UTILS_WINDOWS_SETJMP: &str = "windows_setjmp";
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct IntToIntrinsicName {
|
||||
pub options: [IntrinsicName; 10],
|
||||
|
|
|
@ -5066,6 +5066,11 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx>(
|
|||
}
|
||||
|
||||
pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
|
||||
let word_type = match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes4 => env.context.i32_type(),
|
||||
PtrWidth::Bytes8 => env.context.i64_type(),
|
||||
};
|
||||
|
||||
// The size of jump_buf is target-dependent.
|
||||
// - AArch64 needs 3 machine-sized words
|
||||
// - LLVM says the following about the SJLJ intrinsic:
|
||||
|
@ -5077,11 +5082,15 @@ pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
|
|||
// The following three words are available for use in a target-specific manner.
|
||||
//
|
||||
// So, let's create a 5-word buffer.
|
||||
let word_type = match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes4 => env.context.i32_type(),
|
||||
PtrWidth::Bytes8 => env.context.i64_type(),
|
||||
let size = if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
|
||||
// Due to https://github.com/llvm/llvm-project/issues/72908
|
||||
// on windows, we store the register contents into this buffer directly!
|
||||
30
|
||||
} else {
|
||||
5
|
||||
};
|
||||
let type_ = word_type.array_type(5);
|
||||
|
||||
let type_ = word_type.array_type(size);
|
||||
|
||||
let global = match env.module.get_global("roc_sjlj_buffer") {
|
||||
Some(global) => global,
|
||||
|
@ -5099,9 +5108,12 @@ pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
|
|||
|
||||
pub fn build_setjmp_call<'ctx>(env: &Env<'_, 'ctx, '_>) -> BasicValueEnum<'ctx> {
|
||||
let jmp_buf = get_sjlj_buffer(env);
|
||||
if cfg!(target_arch = "aarch64") {
|
||||
if env.target_info.architecture == roc_target::Architecture::Aarch64 {
|
||||
// Due to https://github.com/roc-lang/roc/issues/2965, we use a setjmp we linked in from Zig
|
||||
call_bitcode_fn(env, &[jmp_buf.into()], bitcode::UTILS_SETJMP)
|
||||
} else if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
|
||||
// Due to https://github.com/llvm/llvm-project/issues/72908, we use a setjmp defined as asm in Zig
|
||||
call_bitcode_fn(env, &[jmp_buf.into()], bitcode::UTILS_WINDOWS_SETJMP)
|
||||
} else {
|
||||
// Anywhere else, use the LLVM intrinsic.
|
||||
// https://llvm.org/docs/ExceptionHandling.html#llvm-eh-sjlj-setjmp
|
||||
|
|
|
@ -315,11 +315,18 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
|||
|
||||
pub fn build_longjmp_call(env: &Env) {
|
||||
let jmp_buf = get_sjlj_buffer(env);
|
||||
if cfg!(target_arch = "aarch64") {
|
||||
// Call the Zig-linked longjmp: `void longjmp(i32*, i32)`
|
||||
if env.target_info.architecture == roc_target::Architecture::Aarch64 {
|
||||
// Due to https://github.com/roc-lang/roc/issues/2965, we use a setjmp we linked in from Zig
|
||||
let tag = env.context.i32_type().const_int(1, false);
|
||||
let _call =
|
||||
call_void_bitcode_fn(env, &[jmp_buf.into(), tag.into()], bitcode::UTILS_LONGJMP);
|
||||
} else if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
|
||||
let tag = env.context.i32_type().const_int(1, false);
|
||||
let _call = call_void_bitcode_fn(
|
||||
env,
|
||||
&[jmp_buf.into(), tag.into()],
|
||||
bitcode::UTILS_WINDOWS_LONGJMP,
|
||||
);
|
||||
} else {
|
||||
// Call the LLVM-intrinsic longjmp: `void @llvm.eh.sjlj.longjmp(i8* %setjmp_buf)`
|
||||
let jmp_buf_i8p = env.builder.new_build_pointer_cast(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue