From 942039b2328c14e62183d609ca43c115db816631 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 20 Apr 2020 17:13:43 +0200 Subject: [PATCH] Pass ByRef values at fixed stack offset for extern "C" This makes it possible to build proc macros using cg_clif --- Cargo.lock | 44 ++++++++++++++++++++++---------------------- cargo.sh | 2 +- src/abi/mod.rs | 22 +++++++++++++--------- src/abi/pass_mode.rs | 19 ++++++++++--------- src/abi/returning.rs | 20 ++++++++++---------- src/debuginfo/mod.rs | 1 + test.sh | 6 +++--- 7 files changed, 60 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fc3623d8b6..bdc01941351 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,16 +43,16 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cranelift-bforest" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "byteorder", "cranelift-bforest", @@ -69,8 +69,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -78,18 +78,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" [[package]] name = "cranelift-entity" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" [[package]] name = "cranelift-frontend" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "cranelift-codegen", "log", @@ -99,8 +99,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "anyhow", "cranelift-codegen", @@ -111,8 +111,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -121,8 +121,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "anyhow", "cranelift-codegen", @@ -133,8 +133,8 @@ dependencies = [ [[package]] name = "cranelift-simplejit" -version = "0.65.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4ba3ee33682c293747a672bfb87d5235bb1e62b3" +version = "0.66.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#5c5a30f76c35e15697fc150fb00c4b86be621d66" dependencies = [ "cranelift-codegen", "cranelift-module", @@ -275,9 +275,9 @@ dependencies = [ [[package]] name = "regalloc" -version = "0.0.27" +version = "0.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ba8aaf5fe7cf307c6dbdaeed85478961d29e25e3bee5169e11b92fa9f027a8" +checksum = "3598bed0895fe0f72a9e0b00ef9e3a3c8af978a8401b2f2046dec5927de6364a" dependencies = [ "log", "rustc-hash", diff --git a/cargo.sh b/cargo.sh index 9b83deaf7ab..5ee21f467e2 100755 --- a/cargo.sh +++ b/cargo.sh @@ -20,4 +20,4 @@ fi cmd=$1 shift -cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@ +cargo +${TOOLCHAIN} $cmd $@ diff --git a/src/abi/mod.rs b/src/abi/mod.rs index f53aad1c259..1989b2b08b3 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -6,7 +6,7 @@ mod returning; use rustc_target::spec::abi::Abi; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use cranelift_codegen::ir::AbiParam; +use cranelift_codegen::ir::{AbiParam, ArgumentPurpose}; use self::pass_mode::*; use crate::prelude::*; @@ -123,7 +123,11 @@ fn clif_sig_from_fn_sig<'tcx>( if abi != Abi::Rust && abi != Abi::RustCall && abi != Abi::RustIntrinsic { match pass_mode { PassMode::NoPass | PassMode::ByVal(_) => {} - PassMode::ByValPair(_, _) | PassMode::ByRef { sized: _ } => { + PassMode::ByRef { size: Some(size) } => { + let purpose = ArgumentPurpose::StructArgument(u32::try_from(size.bytes()).expect("struct too big to pass on stack")); + return EmptySinglePair::Single(AbiParam::special(pointer_ty(tcx), purpose)).into_iter(); + } + PassMode::ByValPair(_, _) | PassMode::ByRef { size: None } => { tcx.sess.span_warn( span, &format!( @@ -137,7 +141,7 @@ fn clif_sig_from_fn_sig<'tcx>( } } } - pass_mode.get_param_ty(tcx).into_iter() + pass_mode.get_param_ty(tcx).map(AbiParam::new).into_iter() }) .flatten(); @@ -145,26 +149,26 @@ fn clif_sig_from_fn_sig<'tcx>( tcx, tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap(), ) { - PassMode::NoPass => (inputs.map(AbiParam::new).collect(), vec![]), + PassMode::NoPass => (inputs.collect(), vec![]), PassMode::ByVal(ret_ty) => ( - inputs.map(AbiParam::new).collect(), + inputs.collect(), vec![AbiParam::new(ret_ty)], ), PassMode::ByValPair(ret_ty_a, ret_ty_b) => ( - inputs.map(AbiParam::new).collect(), + inputs.collect(), vec![AbiParam::new(ret_ty_a), AbiParam::new(ret_ty_b)], ), - PassMode::ByRef { sized: true } => { + PassMode::ByRef { size: Some(_) } => { ( Some(pointer_ty(tcx)) // First param is place to put return val .into_iter() + .map(|ty| AbiParam::special(ty, ArgumentPurpose::StructReturn)) .chain(inputs) - .map(AbiParam::new) .collect(), vec![], ) } - PassMode::ByRef { sized: false } => todo!(), + PassMode::ByRef { size: None } => todo!(), }; if requires_caller_location { diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 68af0e6ca0f..390637e8e44 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -7,7 +7,7 @@ pub(super) enum PassMode { NoPass, ByVal(Type), ByValPair(Type, Type), - ByRef { sized: bool }, + ByRef { size: Option }, } #[derive(Copy, Clone, Debug)] @@ -70,8 +70,8 @@ impl PassMode { PassMode::NoPass => Empty, PassMode::ByVal(clif_type) => Single(clif_type), PassMode::ByValPair(a, b) => Pair(a, b), - PassMode::ByRef { sized: true } => Single(pointer_ty(tcx)), - PassMode::ByRef { sized: false } => Pair(pointer_ty(tcx), pointer_ty(tcx)), + PassMode::ByRef { size: Some(_) } => Single(pointer_ty(tcx)), + PassMode::ByRef { size: None } => Pair(pointer_ty(tcx), pointer_ty(tcx)), } } } @@ -93,16 +93,17 @@ pub(super) fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) // Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are // available on x86_64. Cranelift gets confused when too many return params // are used. - PassMode::ByRef { sized: true } + PassMode::ByRef { size: Some(layout.size) } } else { PassMode::ByValPair(a, b) } } // FIXME implement Vector Abi in a cg_llvm compatible way - Abi::Vector { .. } => PassMode::ByRef { sized: true }, + Abi::Vector { .. } => PassMode::ByRef { size: Some(layout.size) }, - &Abi::Aggregate { sized } => PassMode::ByRef { sized }, + Abi::Aggregate { sized: true } => PassMode::ByRef { size: Some(layout.size) }, + Abi::Aggregate { sized: false } => PassMode::ByRef { size: None }, } } } @@ -118,7 +119,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>( let (a, b) = arg.load_scalar_pair(fx); Pair(a, b) } - PassMode::ByRef { sized: _ } => { + PassMode::ByRef { size: _ } => { match arg.force_stack(fx) { (ptr, None) => Single(ptr.get_addr(fx)), (ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta), @@ -164,8 +165,8 @@ pub(super) fn cvalue_for_param<'tcx>( let (a, b) = block_params.assert_pair(); Some(CValue::by_val_pair(a, b, layout)) } - PassMode::ByRef { sized: true } => Some(CValue::by_ref(Pointer::new(block_params.assert_single()), layout)), - PassMode::ByRef { sized: false } => { + PassMode::ByRef { size: Some(_) } => Some(CValue::by_ref(Pointer::new(block_params.assert_single()), layout)), + PassMode::ByRef { size: None } => { let (ptr, meta) = block_params.assert_pair(); Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout)) } diff --git a/src/abi/returning.rs b/src/abi/returning.rs index 449c77c3c09..e445a12b2a8 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -9,7 +9,7 @@ pub(crate) fn can_return_to_ssa_var<'tcx>(tcx: TyCtxt<'tcx>, dest_layout: TyAndL match get_pass_mode(tcx, dest_layout) { PassMode::NoPass | PassMode::ByVal(_) => true, // FIXME Make it possible to return ByValPair and ByRef to an ssa var. - PassMode::ByValPair(_, _) | PassMode::ByRef { sized: _ } => false + PassMode::ByValPair(_, _) | PassMode::ByRef { size: _ } => false } } @@ -33,14 +33,14 @@ pub(super) fn codegen_return_param( Empty } - PassMode::ByRef { sized: true } => { + PassMode::ByRef { size: Some(_) } => { let ret_param = fx.bcx.append_block_param(start_block, fx.pointer_type); fx.local_map .insert(RETURN_PLACE, CPlace::for_ptr(Pointer::new(ret_param), ret_layout)); Single(ret_param) } - PassMode::ByRef { sized: false } => todo!(), + PassMode::ByRef { size: None } => todo!(), }; #[cfg(not(debug_assertions))] @@ -69,11 +69,11 @@ pub(super) fn codegen_with_call_return_arg<'tcx, B: Backend, T>( let output_pass_mode = get_pass_mode(fx.tcx, ret_layout); let return_ptr = match output_pass_mode { PassMode::NoPass => None, - PassMode::ByRef { sized: true } => match ret_place { + PassMode::ByRef { size: Some(_)} => match ret_place { Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)), - None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), + None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot }, - PassMode::ByRef { sized: false } => todo!(), + PassMode::ByRef { size: None } => todo!(), PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None, }; @@ -94,8 +94,8 @@ pub(super) fn codegen_with_call_return_arg<'tcx, B: Backend, T>( ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout)); } } - PassMode::ByRef { sized: true } => {} - PassMode::ByRef { sized: false } => todo!(), + PassMode::ByRef { size: Some(_) } => {} + PassMode::ByRef { size: None } => todo!(), } (call_inst, meta) @@ -103,10 +103,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx, B: Backend, T>( pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Backend>) { match get_pass_mode(fx.tcx, return_layout(fx)) { - PassMode::NoPass | PassMode::ByRef { sized: true } => { + PassMode::NoPass | PassMode::ByRef { size: Some(_) } => { fx.bcx.ins().return_(&[]); } - PassMode::ByRef { sized: false } => todo!(), + PassMode::ByRef { size: None } => todo!(), PassMode::ByVal(_) => { let place = fx.get_local_place(RETURN_PLACE); let ret_val = place.to_cvalue(fx).load_scalar(fx); diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index f3ba3b5ad11..37dc9f4e3c5 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -313,6 +313,7 @@ impl<'tcx> DebugContext<'tcx> { use cranelift_codegen::ir::ArgumentPurpose; let base_name = match param.purpose { ArgumentPurpose::Normal => "arg", + ArgumentPurpose::StructArgument(_) => "struct_arg", ArgumentPurpose::StructReturn => "sret", ArgumentPurpose::Link | ArgumentPurpose::FramePointer | ArgumentPurpose::CalleeSaved => continue, ArgumentPurpose::VMContext | ArgumentPurpose::SignatureId | ArgumentPurpose::StackLimit => unreachable!(), diff --git a/test.sh b/test.sh index 7127ba79fe9..74ead626e69 100755 --- a/test.sh +++ b/test.sh @@ -74,12 +74,12 @@ $RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE pushd simple-raytracer if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[BENCH COMPILE] ebobby/simple-raytracer" - hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "rm -r target/*/debug || true" \ - "RUSTFLAGS='' cargo build --target $TARGET_TRIPLE" \ + hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "cargo clean" \ + "RUSTFLAGS='' cargo build" \ "../cargo.sh build" echo "[BENCH RUN] ebobby/simple-raytracer" - cp ./target/*/debug/main ./raytracer_cg_clif + cp ./target/debug/main ./raytracer_cg_clif hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_clif else echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"