Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support inline asm on AArch64 #1396

Merged
merged 3 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,12 @@ pub macro cfg() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro asm() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro global_asm() {
Expand Down
23 changes: 17 additions & 6 deletions src/global_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ use std::sync::Arc;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::{InlineAsmOperand, ItemId};
use rustc_session::config::{OutputFilenames, OutputType};
use rustc_target::asm::InlineAsmArch;

use crate::prelude::*;

pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
let item = tcx.hir().item(item_id);
if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
global_asm.push_str("\n.intel_syntax noprefix\n");
} else {
global_asm.push_str("\n.att_syntax\n");
let is_x86 =
matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);

if is_x86 {
if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
global_asm.push_str("\n.intel_syntax noprefix\n");
} else {
global_asm.push_str("\n.att_syntax\n");
}
}
for piece in asm.template {
match *piece {
Expand Down Expand Up @@ -65,7 +71,11 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
}
}
}
global_asm.push_str("\n.att_syntax\n\n");

global_asm.push('\n');
if is_x86 {
global_asm.push_str(".att_syntax\n\n");
}
} else {
bug!("Expected GlobalAsm found {:?}", item);
}
Expand Down Expand Up @@ -115,11 +125,12 @@ pub(crate) fn compile_global_asm(
}

// Remove all LLVM style comments
let global_asm = global_asm
let mut global_asm = global_asm
.lines()
.map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line })
.collect::<Vec<_>>()
.join("\n");
global_asm.push('\n');

let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name));

Expand Down
92 changes: 28 additions & 64 deletions src/inline_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,50 +699,34 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {

fn prologue(generated_asm: &mut String, arch: InlineAsmArch) {
match arch {
InlineAsmArch::X86 => {
generated_asm.push_str(" push ebp\n");
generated_asm.push_str(" mov ebp,[esp+8]\n");
}
InlineAsmArch::X86_64 => {
generated_asm.push_str(" push rbp\n");
generated_asm.push_str(" mov rbp,rdi\n");
}
InlineAsmArch::RiscV32 => {
generated_asm.push_str(" addi sp, sp, -8\n");
generated_asm.push_str(" sw ra, 4(sp)\n");
generated_asm.push_str(" sw s0, 0(sp)\n");
generated_asm.push_str(" mv s0, a0\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 s0, 0(sp)\n");
generated_asm.push_str(" mv s0, a0\n");
generated_asm.push_str(" mov rbp,rsp\n");
generated_asm.push_str(" push rbx\n"); // rbx is callee saved
// rbx is reserved by LLVM for the "base pointer", so rustc doesn't allow using it
generated_asm.push_str(" mov rbx,rdi\n");
}
InlineAsmArch::AArch64 => {
generated_asm.push_str(" stp fp, lr, [sp, #-32]!\n");
generated_asm.push_str(" mov fp, sp\n");
generated_asm.push_str(" str x19, [sp, #24]\n"); // x19 is callee saved
// x19 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it
generated_asm.push_str(" mov x19, x0\n");
}
_ => unimplemented!("prologue for {:?}", arch),
}
}

fn epilogue(generated_asm: &mut String, arch: InlineAsmArch) {
match arch {
InlineAsmArch::X86 => {
generated_asm.push_str(" pop ebp\n");
generated_asm.push_str(" ret\n");
}
InlineAsmArch::X86_64 => {
generated_asm.push_str(" pop rbx\n");
generated_asm.push_str(" pop rbp\n");
generated_asm.push_str(" ret\n");
}
InlineAsmArch::RiscV32 => {
generated_asm.push_str(" lw s0, 0(sp)\n");
generated_asm.push_str(" lw ra, 4(sp)\n");
generated_asm.push_str(" addi sp, sp, 8\n");
generated_asm.push_str(" ret\n");
}
InlineAsmArch::RiscV64 => {
generated_asm.push_str(" ld s0, 0(sp)\n");
generated_asm.push_str(" ld ra, 8(sp)\n");
generated_asm.push_str(" addi sp, sp, 16\n");
InlineAsmArch::AArch64 => {
generated_asm.push_str(" ldr x19, [sp, #24]\n");
generated_asm.push_str(" ldp fp, lr, [sp], #32\n");
generated_asm.push_str(" ret\n");
}
_ => unimplemented!("epilogue for {:?}", arch),
Expand All @@ -751,11 +735,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {

fn epilogue_noreturn(generated_asm: &mut String, arch: InlineAsmArch) {
match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
InlineAsmArch::X86_64 => {
generated_asm.push_str(" ud2\n");
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
generated_asm.push_str(" ebreak\n");
InlineAsmArch::AArch64 => {
generated_asm.push_str(" brk #0x1");
}
_ => unimplemented!("epilogue_noreturn for {:?}", arch),
}
Expand All @@ -768,25 +752,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
offset: Size,
) {
match arch {
InlineAsmArch::X86 => {
write!(generated_asm, " mov [ebp+0x{:x}], ", offset.bytes()).unwrap();
reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap();
generated_asm.push('\n');
}
InlineAsmArch::X86_64 => {
write!(generated_asm, " mov [rbp+0x{:x}], ", offset.bytes()).unwrap();
write!(generated_asm, " mov [rbx+0x{:x}], ", offset.bytes()).unwrap();
reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap();
generated_asm.push('\n');
}
InlineAsmArch::RiscV32 => {
generated_asm.push_str(" sw ");
reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap();
writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap();
}
InlineAsmArch::RiscV64 => {
generated_asm.push_str(" sd ");
reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap();
writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap();
InlineAsmArch::AArch64 => {
generated_asm.push_str(" str ");
reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap();
writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
}
_ => unimplemented!("save_register for {:?}", arch),
}
Expand All @@ -799,25 +773,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
offset: Size,
) {
match arch {
InlineAsmArch::X86 => {
generated_asm.push_str(" mov ");
reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap();
writeln!(generated_asm, ", [ebp+0x{:x}]", offset.bytes()).unwrap();
}
InlineAsmArch::X86_64 => {
generated_asm.push_str(" mov ");
reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap();
writeln!(generated_asm, ", [rbp+0x{:x}]", offset.bytes()).unwrap();
}
InlineAsmArch::RiscV32 => {
generated_asm.push_str(" lw ");
reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap();
writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap();
writeln!(generated_asm, ", [rbx+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}(s0)", offset.bytes()).unwrap();
InlineAsmArch::AArch64 => {
generated_asm.push_str(" ldr ");
reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap();
writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
}
_ => unimplemented!("restore_register for {:?}", arch),
}
Expand Down