Skip to content

Commit

Permalink
Add a DynRex recipe type for x86, decreasing the number of recipes (b…
Browse files Browse the repository at this point in the history
…ytecodealliance#1298)

This patch adds a third mode for templates: REX inference is requestable
at template instantiation time. This reduces the number of recipes
by removing rex()/nonrex() redundancy for many instructions.
  • Loading branch information
sstangl authored Dec 19, 2019
1 parent b486289 commit cf9e762
Show file tree
Hide file tree
Showing 13 changed files with 873 additions and 512 deletions.
2 changes: 1 addition & 1 deletion cranelift/codegen/meta/src/cdsl/recipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ pub(crate) struct EncodingRecipeBuilder {
pub base_size: u64,
pub operands_in: Option<Vec<OperandConstraint>>,
pub operands_out: Option<Vec<OperandConstraint>>,
compute_size: Option<&'static str>,
pub compute_size: Option<&'static str>,
pub branch_range: Option<BranchRange>,
pub emit: Option<String>,
clobbers_flags: Option<bool>,
Expand Down
59 changes: 43 additions & 16 deletions cranelift/codegen/meta/src/isa/x86/encodings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,32 +140,59 @@ impl PerCpuModeEncodings {
self.enc64.push(encoding);
}

/// Adds I32/I64 encodings as appropriate for a typed instruction.
/// The REX prefix is always inferred at runtime.
///
/// Add encodings for `inst.i32` to X86_32.
/// Add encodings for `inst.i32` to X86_64 with and without REX.
/// Add encodings for `inst.i32` to X86_64 with optional, inferred REX.
/// Add encodings for `inst.i64` to X86_64 with a REX.W prefix.
fn enc_i32_i64(&mut self, inst: impl Into<InstSpec>, template: Template) {
let inst: InstSpec = inst.into();

// I32 on x86: no REX prefix.
self.enc32(inst.bind(I32), template.infer_rex());

// I32 on x86_64: REX.W unset; REX.RXB determined at runtime from registers.
self.enc64(inst.bind(I32), template.infer_rex());

// I64 on x86_64: REX.W set; REX.RXB determined at runtime from registers.
self.enc64(inst.bind(I64), template.infer_rex().w());
}

/// Adds I32/I64 encodings as appropriate for a typed instruction.
/// All variants of REX prefix are explicitly emitted, not inferred.
///
/// Add encodings for `inst.i32` to X86_32.
/// Add encodings for `inst.i32` to X86_64 with and without REX.
/// Add encodings for `inst.i64` to X86_64 with and without REX.
fn enc_i32_i64_explicit_rex(&mut self, inst: impl Into<InstSpec>, template: Template) {
let inst: InstSpec = inst.into();
self.enc32(inst.bind(I32), template.nonrex());

// REX-less encoding must come after REX encoding so we don't use it by default. Otherwise
// reg-alloc would never use r8 and up.
// REX-less encoding must come after REX encoding so we don't use it by default.
// Otherwise reg-alloc would never use r8 and up.
self.enc64(inst.bind(I32), template.rex());
self.enc64(inst.bind(I32), template.nonrex());
self.enc64(inst.bind(I64), template.rex().w());
}

/// Add encodings for `inst.b32` to X86_32.
/// Add encodings for `inst.b32` to X86_64 with and without REX.
/// Add encodings for `inst.b64` to X86_64 with a REX.W prefix.
/// Adds B32/B64 encodings as appropriate for a typed instruction.
/// The REX prefix is always inferred at runtime.
///
/// Adds encoding for `inst.b32` to X86_32.
/// Adds encoding for `inst.b32` to X86_64 with optional, inferred REX.
/// Adds encoding for `inst.b64` to X86_64 with a REX.W prefix.
fn enc_b32_b64(&mut self, inst: impl Into<InstSpec>, template: Template) {
let inst: InstSpec = inst.into();
self.enc32(inst.bind(B32), template.nonrex());

// REX-less encoding must come after REX encoding so we don't use it by default. Otherwise
// reg-alloc would never use r8 and up.
self.enc64(inst.bind(B32), template.rex());
self.enc64(inst.bind(B32), template.nonrex());
self.enc64(inst.bind(B64), template.rex().w());
// B32 on x86: no REX prefix.
self.enc32(inst.bind(B32), template.infer_rex());

// B32 on x86_64: REX.W unset; REX.RXB determined at runtime from registers.
self.enc64(inst.bind(B32), template.infer_rex());

// B64 on x86_64: REX.W set; REX.RXB determined at runtime from registers.
self.enc64(inst.bind(B64), template.infer_rex().w());
}

/// Add encodings for `inst.i32` to X86_32.
Expand Down Expand Up @@ -994,8 +1021,8 @@ pub(crate) fn define(
e.enc_x86_64(istore8.bind(I64).bind(Any), recipe.opcodes(&MOV_BYTE_STORE));
}

e.enc_i32_i64(spill, rec_spillSib32.opcodes(&MOV_STORE));
e.enc_i32_i64(regspill, rec_regspill32.opcodes(&MOV_STORE));
e.enc_i32_i64_explicit_rex(spill, rec_spillSib32.opcodes(&MOV_STORE));
e.enc_i32_i64_explicit_rex(regspill, rec_regspill32.opcodes(&MOV_STORE));
e.enc_r32_r64_rex_only(spill, rec_spillSib32.opcodes(&MOV_STORE));
e.enc_r32_r64_rex_only(regspill, rec_regspill32.opcodes(&MOV_STORE));

Expand All @@ -1020,8 +1047,8 @@ pub(crate) fn define(
e.enc_i32_i64_ld_st(sload8, true, recipe.opcodes(&MOVSX_BYTE));
}

e.enc_i32_i64(fill, rec_fillSib32.opcodes(&MOV_LOAD));
e.enc_i32_i64(regfill, rec_regfill32.opcodes(&MOV_LOAD));
e.enc_i32_i64_explicit_rex(fill, rec_fillSib32.opcodes(&MOV_LOAD));
e.enc_i32_i64_explicit_rex(regfill, rec_regfill32.opcodes(&MOV_LOAD));
e.enc_r32_r64_rex_only(fill, rec_fillSib32.opcodes(&MOV_LOAD));
e.enc_r32_r64_rex_only(regfill, rec_regfill32.opcodes(&MOV_LOAD));

Expand Down
Loading

0 comments on commit cf9e762

Please sign in to comment.