Merge pull request #5731 from roc-lang/folkert-windows-branch

Fix 2 bugs in windows dev backend
This commit is contained in:
Brendan Hansknecht 2023-08-08 21:54:59 +00:00 committed by GitHub
commit 713afc71c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 21 deletions

1
Cargo.lock generated
View File

@ -4784,7 +4784,6 @@ dependencies = [
"criterion",
"indoc",
"inkwell",
"lazy_static",
"libc",
"libloading",
"roc_bitcode",

View File

@ -985,7 +985,8 @@ impl<
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
ASM::mov_freg64_freg64(&mut self.buf, dst_reg, CC::FLOAT_RETURN_REGS[0]);
}
LayoutRepr::I128 | LayoutRepr::U128 => {
// Note that on windows there is only 1 general return register so we can't use this optimisation
LayoutRepr::I128 | LayoutRepr::U128 if CC::GENERAL_RETURN_REGS.len() > 1 => {
let offset = self.storage_manager.claim_stack_area(dst, 16);
ASM::mov_base32_reg64(&mut self.buf, offset, CC::GENERAL_RETURN_REGS[0]);

View File

@ -8,7 +8,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_mono::layout::{
Builtin, InLayout, LayoutInterner, LayoutRepr, STLayoutInterner, UnionLayout,
Builtin, InLayout, Layout, LayoutInterner, LayoutRepr, STLayoutInterner, UnionLayout,
};
use super::{CompareOperation, RegisterWidth};
@ -1130,6 +1130,9 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
];
const SHADOW_SPACE_SIZE: u8 = 32;
// Refer https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#callercallee-saved-registers
// > The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15 nonvolatile.
// > They must be saved and restored by a function that uses them.
#[inline(always)]
fn general_callee_saved(reg: &X86_64GeneralReg) -> bool {
matches!(
@ -1146,16 +1149,23 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
)
}
// Refer https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#callercallee-saved-registers
// > The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15 nonvolatile.
// > They must be saved and restored by a function that uses them.
#[inline(always)]
fn float_callee_saved(reg: &X86_64FloatReg) -> bool {
matches!(
reg,
X86_64FloatReg::XMM0
| X86_64FloatReg::XMM1
| X86_64FloatReg::XMM2
| X86_64FloatReg::XMM3
| X86_64FloatReg::XMM4
| X86_64FloatReg::XMM5
X86_64FloatReg::XMM6
| X86_64FloatReg::XMM7
| X86_64FloatReg::XMM8
| X86_64FloatReg::XMM9
| X86_64FloatReg::XMM10
| X86_64FloatReg::XMM11
| X86_64FloatReg::XMM12
| X86_64FloatReg::XMM13
| X86_64FloatReg::XMM14
| X86_64FloatReg::XMM15
)
}
@ -1286,6 +1296,16 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
single_register_layouts!() => {
internal_error!("single register layouts are not complex symbols");
}
// For windows (and zig 0.9 changes in zig 0.10) we need to match what zig does,
// in this case uses RAX & RDX to return the value
LayoutRepr::I128 | LayoutRepr::U128 => {
let (base_offset, size) = storage_manager.stack_offset_and_size(sym);
debug_assert_eq!(base_offset % 8, 0);
debug_assert_eq!(size, 16);
X86_64Assembler::mov_reg64_base32(buf, X86_64GeneralReg::RAX, base_offset);
X86_64Assembler::mov_reg64_base32(buf, X86_64GeneralReg::RDX, base_offset + 0x08);
}
_ if layout_interner.stack_size(*layout) == 0 => {}
_ if !Self::returns_via_arg_pointer(layout_interner, layout) => {
let (base_offset, size) = storage_manager.stack_offset_and_size(sym);
@ -1333,6 +1353,14 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
single_register_layouts!() => {
internal_error!("single register layouts are not complex symbols");
}
// For windows (and zig 0.9 changes in zig 0.10) we need to match what zig does,
// in this case uses RAX & RDX to return the value
LayoutRepr::I128 | LayoutRepr::U128 => {
let size = layout_interner.stack_size(*layout);
let offset = storage_manager.claim_stack_area(sym, size);
X86_64Assembler::mov_base32_reg64(buf, offset, X86_64GeneralReg::RAX);
X86_64Assembler::mov_base32_reg64(buf, offset + 0x08, X86_64GeneralReg::RDX);
}
_ if layout_interner.stack_size(*layout) == 0 => {
storage_manager.no_data(sym);
}
@ -1508,7 +1536,10 @@ impl X86_64WindowsFastcall {
) -> bool {
// TODO: This is not fully correct there are some exceptions for "vector" types.
// details here: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160#return-values
interner.stack_size(*ret_layout) > 8
match *ret_layout {
Layout::I128 | Layout::U128 => false,
_ => interner.stack_size(*ret_layout) > 8,
}
}
}

View File

@ -18,7 +18,13 @@ wasi_libc_sys = { path = "../../wasi-libc-sys" }
tempfile.workspace = true
[dependencies]
roc_gen_llvm = { path = "../gen_llvm", optional = true }
inkwell = { workspace = true, optional = true }
[dev-dependencies]
roc_gen_dev = { path = "../gen_dev" }
roc_gen_wasm = { path = "../gen_wasm" }
roc_bitcode = { path = "../builtins/bitcode" }
roc_build = { path = "../build", features = ["target-aarch64", "target-x86_64", "target-wasm32"] }
roc_builtins = { path = "../builtins" }
@ -28,9 +34,6 @@ roc_command_utils = { path = "../../utils/command" }
roc_constrain = { path = "../constrain" }
roc_debug_flags = { path = "../debug_flags" }
roc_error_macros = { path = "../../error_macros" }
roc_gen_dev = { path = "../gen_dev" }
roc_gen_llvm = { path = "../gen_llvm" }
roc_gen_wasm = { path = "../gen_wasm" }
roc_load = { path = "../load" }
roc_module = { path = "../module" }
roc_mono = { path = "../mono" }
@ -50,8 +53,6 @@ roc_wasm_module = { path = "../../wasm_module" }
bumpalo.workspace = true
criterion.workspace = true
indoc.workspace = true
inkwell.workspace = true
lazy_static.workspace = true
libc.workspace = true
libloading.workspace = true
target-lexicon.workspace = true
@ -61,7 +62,7 @@ tempfile.workspace = true
[features]
default = ["gen-llvm"]
gen-dev = []
gen-llvm = []
gen-llvm = ["roc_gen_llvm", "inkwell"]
gen-llvm-wasm = ["gen-llvm"]
gen-wasm = []

View File

@ -1,5 +1,6 @@
use std::mem::MaybeUninit;
use std::path::PathBuf;
use std::sync::OnceLock;
use inkwell::module::Module;
use libloading::Library;
@ -414,10 +415,6 @@ fn write_final_wasm() -> bool {
false
}
lazy_static::lazy_static! {
static ref TEMP_DIR: tempfile::TempDir = tempfile::tempdir().unwrap();
}
#[allow(dead_code)]
fn compile_to_wasm_bytes<'a>(
arena: &'a bumpalo::Bump,
@ -426,13 +423,17 @@ fn compile_to_wasm_bytes<'a>(
context: &'a inkwell::context::Context,
function_kind: FunctionKind,
) -> Vec<u8> {
// globally cache the temporary directory
static TEMP_DIR: OnceLock<tempfile::TempDir> = OnceLock::new();
let temp_dir = TEMP_DIR.get_or_init(|| tempfile::tempdir().unwrap());
let target = wasm32_target_tripple();
let (_main_fn_name, _delayed_errors, llvm_module) =
create_llvm_module(arena, src, config, context, &target, function_kind);
let content_hash = crate::helpers::src_hash(src);
let wasm_file = llvm_module_to_wasm_file(&TEMP_DIR, content_hash, llvm_module);
let wasm_file = llvm_module_to_wasm_file(temp_dir, content_hash, llvm_module);
let compiled_bytes = std::fs::read(wasm_file).unwrap();
if write_final_wasm() {