diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 652d6eca3f6..47d9a3b93f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,10 +50,12 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - # s390x requires QEMU 6.1 or greater, we could build it from source, but ubuntu 22.04 comes with 6.2 by default - os: ubuntu-latest env: TARGET_TRIPLE: s390x-unknown-linux-gnu + - os: ubuntu-latest + env: + TARGET_TRIPLE: riscv64gc-unknown-linux-gnu - os: windows-latest env: TARGET_TRIPLE: x86_64-pc-windows-msvc @@ -92,6 +94,12 @@ jobs: sudo apt-get update sudo apt-get install -y gcc-s390x-linux-gnu qemu-user + - name: Install riscv64gc toolchain and qemu + if: matrix.env.TARGET_TRIPLE == 'riscv64gc-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-riscv64-linux-gnu qemu-user + - name: Prepare dependencies run: ./y.sh prepare diff --git a/build_system/utils.rs b/build_system/utils.rs index 9f24c043a50..149f1618f5c 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -42,6 +42,16 @@ impl Compiler { "/usr/s390x-linux-gnu".to_owned(), ]; } + "riscv64gc-unknown-linux-gnu" => { + // We are cross-compiling for riscv64. Use the correct linker and run tests in qemu. + self.rustflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned()); + self.rustdocflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned()); + self.runner = vec![ + "qemu-riscv64".to_owned(), + "-L".to_owned(), + "/usr/riscv64-linux-gnu".to_owned(), + ]; + } "x86_64-pc-windows-gnu" => { // We are cross-compiling for Windows. Run tests in wine. self.runner = vec!["wine".to_owned()]; diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 60ac6bc9951..6bcf56abb95 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -13,23 +13,6 @@ git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \ am ../patches/*-stdlib-*.patch -git apply - < config.toml <, global_asm: &mut String, } } +pub(crate) fn asm_supported(tcx: TyCtxt<'_>) -> bool { + cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows +} + #[derive(Debug)] pub(crate) struct GlobalAsmConfig { asm_enabled: bool, @@ -90,10 +94,8 @@ pub(crate) struct GlobalAsmConfig { impl GlobalAsmConfig { pub(crate) fn new(tcx: TyCtxt<'_>) -> Self { - let asm_enabled = cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows; - GlobalAsmConfig { - asm_enabled, + asm_enabled: asm_supported(tcx), assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"), output_filenames: tcx.output_filenames(()).clone(), } diff --git a/src/inline_asm.rs b/src/inline_asm.rs index dd2127d554d..ed077234254 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -8,6 +8,7 @@ use rustc_span::sym; use rustc_target::asm::*; use target_lexicon::BinaryFormat; +use crate::global_asm::asm_supported; use crate::prelude::*; enum CInlineAsmOperand<'tcx> { @@ -44,9 +45,13 @@ pub(crate) fn codegen_inline_asm<'tcx>( ) { // FIXME add .eh_frame unwind info directives - if !template.is_empty() - && (cfg!(not(feature = "inline_asm")) || fx.tcx.sess.target.is_like_windows) - { + if !asm_supported(fx.tcx) { + if template.is_empty() { + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); + return; + } + // Used by panic_abort if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) { fx.bcx.ins().trap(TrapCode::User(1)); @@ -144,6 +149,16 @@ pub(crate) fn codegen_inline_asm<'tcx>( return; } + // Used by core::hint::spin_loop() + if template[0] + == InlineAsmTemplatePiece::String(".insn i 0x0F, 0, x0, x0, 0x010".to_string()) + && template.len() == 1 + { + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); + return; + } + // Used by measureme if template[0] == InlineAsmTemplatePiece::String("xor %eax, %eax".to_string()) && template[1] == InlineAsmTemplatePiece::String("\n".to_string()) @@ -223,6 +238,16 @@ pub(crate) fn codegen_inline_asm<'tcx>( fx.bcx.ins().jump(destination_block, &[]); return; } + + if cfg!(not(feature = "inline_asm")) { + fx.tcx.sess.span_err( + span, + "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift", + ); + } else { + fx.tcx.sess.span_err(span, "asm! and global_asm! are not yet supported on Windows"); + } + return; } let operands = operands @@ -745,6 +770,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // x19 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it generated_asm.push_str(" mov x19, x0\n"); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" addi sp, sp, -16\n"); + generated_asm.push_str(" sd ra, 8(sp)\n"); + generated_asm.push_str(" sd s1, 0(sp)\n"); // s1 is callee saved + // s1/x9 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it + generated_asm.push_str(" mv s1, a0\n"); + } _ => unimplemented!("prologue for {:?}", arch), } } @@ -761,6 +793,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(" ldp fp, lr, [sp], #32\n"); generated_asm.push_str(" ret\n"); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ld s1, 0(sp)\n"); + generated_asm.push_str(" ld ra, 8(sp)\n"); + generated_asm.push_str(" addi sp, sp, 16\n"); + generated_asm.push_str(" ret\n"); + } _ => unimplemented!("epilogue for {:?}", arch), } } @@ -771,7 +809,10 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(" ud2\n"); } InlineAsmArch::AArch64 => { - generated_asm.push_str(" brk #0x1"); + generated_asm.push_str(" brk #0x1\n"); + } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ebreak\n"); } _ => unimplemented!("epilogue_noreturn for {:?}", arch), } @@ -794,6 +835,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" sd "); + reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap(); + } _ => unimplemented!("save_register for {:?}", arch), } } @@ -815,6 +861,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ld "); + reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap(); + } _ => unimplemented!("restore_register for {:?}", arch), } }