Files
wasmtime/winch/codegen/src/isa/x64/mod.rs
Saúl Cabrera 94b51cdb17 winch: Use cranelift-codegen x64 backend for emission. (#5581)
This change substitutes the string based emission mechanism with
cranelift-codegen's x64 backend.

This change _does not_:

* Introduce new functionality in terms of supported instructions.
* Change the semantics of the assembler/macroassembler in terms of the logic to
emit instructions.

The most notable differences between this change and the previous version are:

* Handling of shared flags and ISA-specific flags, which for now are left with
the default value.
* Simplification of instruction emission per operand size: previously the
assembler defined different methods depending on the operand size (e.g. `mov`
for 64 bits, and `movl` for 32 bits). This change updates such approach so that
each assembler method takes an operand size as a parameter, reducing duplication
and making the code more concise and easier to integrate with the x64's `Inst` enum.
* Introduction of a disassembler for testing purposes.

As of this change, Winch generates the following code for the following test
programs:

```wat
(module
  (export "main" (func $main))

  (func $main (result i32)
        (i32.const 10)
        (i32.const 20)
        i32.add
        ))
```

```asm
   0:	55                   	push	rbp
   1:	48 89 e5             	mov	rbp, rsp
   4:	b8 0a 00 00 00       	mov	eax, 0xa
   9:	83 c0 14             	add	eax, 0x14
   c:	5d                   	pop	rbp
   d:	c3                   	ret
```

```wat
(module
  (export "main" (func $main))

  (func $main (result i32)
        (local $foo i32)
    (local $bar i32)
        (i32.const 10)
    (local.set $foo)
        (i32.const 20)
    (local.set $bar)

        (local.get $foo)
        (local.get $bar)
        i32.add
        ))
```

```asm
   0:	55                   	push	rbp
   1:	48 89 e5             	mov	rbp, rsp
   4:	48 83 ec 08          	sub	rsp, 8
   8:	48 c7 04 24 00 00 00 00	mov	qword ptr [rsp], 0
  10:	b8 0a 00 00 00       	mov	eax, 0xa
  15:	89 44 24 04          	mov	dword ptr [rsp + 4], eax
  19:	b8 14 00 00 00       	mov	eax, 0x14
  1e:	89 04 24             	mov	dword ptr [rsp], eax
  21:	8b 04 24             	mov	eax, dword ptr [rsp]
  24:	8b 4c 24 04          	mov	ecx, dword ptr [rsp + 4]
  28:	01 c1                	add	ecx, eax
  2a:	48 89 c8             	mov	rax, rcx
  2d:	48 83 c4 08          	add	rsp, 8
  31:	5d                   	pop	rbp
  32:	c3                   	ret
```

```wat
(module
  (export "main" (func $main))

  (func $main (param i32) (param i32) (result i32)
        (local.get 0)
        (local.get 1)
        i32.add
        ))
```

```asm
   0:	55                   	push	rbp
   1:	48 89 e5             	mov	rbp, rsp
   4:	48 83 ec 08          	sub	rsp, 8
   8:	89 7c 24 04          	mov	dword ptr [rsp + 4], edi
   c:	89 34 24             	mov	dword ptr [rsp], esi
   f:	8b 04 24             	mov	eax, dword ptr [rsp]
  12:	8b 4c 24 04          	mov	ecx, dword ptr [rsp + 4]
  16:	01 c1                	add	ecx, eax
  18:	48 89 c8             	mov	rax, rcx
  1b:	48 83 c4 08          	add	rsp, 8
  1f:	5d                   	pop	rbp
  20:	c3                   	ret
```
2023-01-18 06:58:13 -05:00

97 lines
2.8 KiB
Rust

use crate::abi::ABI;
use crate::codegen::{CodeGen, CodeGenContext};
use crate::frame::Frame;
use crate::isa::x64::masm::MacroAssembler as X64Masm;
use crate::masm::MacroAssembler;
use crate::regalloc::RegAlloc;
use crate::stack::Stack;
use crate::{
isa::{Builder, TargetIsa},
regset::RegSet,
};
use anyhow::Result;
use cranelift_codegen::{
isa::x64::settings as x64_settings, settings::Flags, Final, MachBufferFinalized,
};
use target_lexicon::Triple;
use wasmparser::{FuncType, FuncValidator, FunctionBody, ValidatorResources};
use self::regs::ALL_GPR;
mod abi;
mod asm;
mod masm;
// Not all the fpr and gpr constructors are used at the moment;
// in that sense, this directive is a temporary measure to avoid
// dead code warnings.
#[allow(dead_code)]
mod regs;
/// Create an ISA builder.
pub(crate) fn isa_builder(triple: Triple) -> Builder {
Builder {
triple,
settings: x64_settings::builder(),
constructor: |triple, shared_flags, settings| {
// TODO: Once enabling/disabling flags is allowed, and once features like SIMD are supported
// ensure compatibility between shared flags and ISA flags.
let isa_flags = x64_settings::Flags::new(&shared_flags, settings);
let isa = X64::new(triple, shared_flags, isa_flags);
Ok(Box::new(isa))
},
}
}
/// x64 ISA.
pub(crate) struct X64 {
/// The target triple.
triple: Triple,
/// ISA specific flags.
isa_flags: x64_settings::Flags,
/// Shared flags.
shared_flags: Flags,
}
impl X64 {
/// Create a x64 ISA.
pub fn new(triple: Triple, shared_flags: Flags, isa_flags: x64_settings::Flags) -> Self {
Self {
isa_flags,
shared_flags,
triple,
}
}
}
impl TargetIsa for X64 {
fn name(&self) -> &'static str {
"x64"
}
fn triple(&self) -> &Triple {
&self.triple
}
fn compile_function(
&self,
sig: &FuncType,
body: &FunctionBody,
mut validator: FuncValidator<ValidatorResources>,
) -> Result<MachBufferFinalized<Final>> {
let mut body = body.get_binary_reader();
let mut masm = X64Masm::new(self.shared_flags.clone(), self.isa_flags.clone());
let stack = Stack::new();
let abi = abi::X64ABI::default();
let abi_sig = abi.sig(sig);
let frame = Frame::new(&abi_sig, &mut body, &mut validator, &abi)?;
// TODO Add in floating point bitmask
let regalloc = RegAlloc::new(RegSet::new(ALL_GPR, 0), regs::scratch());
let codegen_context = CodeGenContext::new(&mut masm, stack, &frame);
let mut codegen = CodeGen::new::<abi::X64ABI>(codegen_context, abi_sig, regalloc);
codegen.emit(&mut body, validator)?;
Ok(masm.finalize())
}
}