Add the very basics of Intel 32-bit instruction encodings.
Tabulate the Intel opcode representations and implement an OP() function which computes the encoding bits. Implement the single-byte opcode with a reg-reg ModR/M byte.
This commit is contained in:
23
cranelift/filetests/isa/intel/binary32.cton
Normal file
23
cranelift/filetests/isa/intel/binary32.cton
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
; binary emission of 32-bit code.
|
||||||
|
test binemit
|
||||||
|
isa intel
|
||||||
|
|
||||||
|
; The binary encodings can be verified with the command:
|
||||||
|
;
|
||||||
|
; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/binary32.cton | llvm-mc -show-encoding -triple=i386
|
||||||
|
;
|
||||||
|
|
||||||
|
function I32() {
|
||||||
|
ebb0:
|
||||||
|
[-,%rcx] v1 = iconst.i32 1
|
||||||
|
[-,%rsi] v2 = iconst.i32 2
|
||||||
|
|
||||||
|
; Integer Register-Register Operations.
|
||||||
|
|
||||||
|
; asm: addl %esi, %ecx
|
||||||
|
[-,%rcx] v10 = iadd v1, v2 ; bin: 01 f1
|
||||||
|
; asm: addl %ecx, %esi
|
||||||
|
[-,%rsi] v11 = iadd v2, v1 ; bin: 01 ce
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ is no x87 floating point support.
|
|||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from . import defs
|
from . import defs
|
||||||
from . import settings, registers # noqa
|
from . import encodings, settings, registers # noqa
|
||||||
|
|
||||||
# Re-export the primary target ISA definition.
|
# Re-export the primary target ISA definition.
|
||||||
ISA = defs.ISA.finish()
|
ISA = defs.ISA.finish()
|
||||||
|
|||||||
10
lib/cretonne/meta/isa/intel/encodings.py
Normal file
10
lib/cretonne/meta/isa/intel/encodings.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
"""
|
||||||
|
Intel Encodings.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from base import instructions as base
|
||||||
|
from .defs import I32
|
||||||
|
from .recipes import Op1rr
|
||||||
|
from .recipes import OP
|
||||||
|
|
||||||
|
I32.enc(base.iadd.i32, Op1rr, OP(0x01))
|
||||||
67
lib/cretonne/meta/isa/intel/recipes.py
Normal file
67
lib/cretonne/meta/isa/intel/recipes.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
Intel Encoding recipes.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from cdsl.isa import EncRecipe
|
||||||
|
# from cdsl.predicates import IsSignedInt
|
||||||
|
from base.formats import Binary
|
||||||
|
from .registers import GPR
|
||||||
|
|
||||||
|
# Opcode representation.
|
||||||
|
#
|
||||||
|
# Cretonne requires each recipe to have a single encoding size in bytes, and
|
||||||
|
# Intel opcodes are variable length, so we use separate recipes for different
|
||||||
|
# styles of opcodes and prefixes. The opcode format is indicated by the recipe
|
||||||
|
# name prefix:
|
||||||
|
#
|
||||||
|
# <op> Op1* OP(op)
|
||||||
|
# 0F <op> Op2* OP(op)
|
||||||
|
# 0F 38 <op> Op3* OP38(op)
|
||||||
|
# 0F 3A <op> Op3* OP3A(op)
|
||||||
|
# 66 <op> Mp1* MP66(op)
|
||||||
|
# 66 0F <op> Mp2* MP66(op)
|
||||||
|
# 66 0F 38 <op> Mp3* MP6638(op)
|
||||||
|
# 66 0F 3A <op> Mp3* MP663A(op)
|
||||||
|
# F2 <op> Mp1* MPF2(op)
|
||||||
|
# F2 0F <op> Mp2* MPF2(op)
|
||||||
|
# F2 0F 38 <op> Mp3* MPF238(op)
|
||||||
|
# F2 0F 3A <op> Mp3* MPF23A(op)
|
||||||
|
# F3 <op> Mp1* MPF3(op)
|
||||||
|
# F3 0F <op> Mp2* MPF3(op)
|
||||||
|
# F3 0F 38 <op> Mp3* MPF338(op)
|
||||||
|
# F3 0F 3A <op> Mp3* MPF33A(op)
|
||||||
|
#
|
||||||
|
# VEX/XOP and EVEX prefixes are not yet supported.
|
||||||
|
#
|
||||||
|
# The encoding bits are:
|
||||||
|
#
|
||||||
|
# 0-7: The opcode byte <op>.
|
||||||
|
# 8-9: pp, mandatory prefix:
|
||||||
|
# 00 none (Op*)
|
||||||
|
# 01 66 (Mp*)
|
||||||
|
# 10 F3 (Mp*)
|
||||||
|
# 11 F2 (Mp*)
|
||||||
|
# 10-11: mm, opcode map:
|
||||||
|
# 00 <op> (Op1/Mp1)
|
||||||
|
# 01 0F <op> (Op2/Mp2)
|
||||||
|
# 10 0F 38 <op> (Op3/Mp3)
|
||||||
|
# 11 0F 3A <op> (Op3/Mp3)
|
||||||
|
# 12-14 rrr, opcode bits for the ModR/M byte for certain opcodes.
|
||||||
|
# 15: REX.W bit (or VEX.W/E)
|
||||||
|
#
|
||||||
|
# There is some redundancy between bits 8-11 and the recipe names, but we have
|
||||||
|
# enough bits, and the pp+mm format is ready for supporting VEX prefixes.
|
||||||
|
|
||||||
|
|
||||||
|
def OP(op, pp=0, mm=0, rrr=0, w=0):
|
||||||
|
# type: (int, int, int, int, int) -> int
|
||||||
|
assert op <= 0xff
|
||||||
|
assert pp <= 0b11
|
||||||
|
assert mm <= 0b11
|
||||||
|
assert rrr <= 0b111
|
||||||
|
assert w <= 1
|
||||||
|
return op | (pp << 8) | (mm << 10) | (rrr << 12) | (w << 15)
|
||||||
|
|
||||||
|
|
||||||
|
# XX /r
|
||||||
|
Op1rr = EncRecipe('Op1rr', Binary, size=2, ins=(GPR, GPR), outs=0)
|
||||||
@@ -1,6 +1,34 @@
|
|||||||
//! Emitting binary Intel machine code.
|
//! Emitting binary Intel machine code.
|
||||||
|
|
||||||
use binemit::{CodeSink, bad_encoding};
|
use binemit::{CodeSink, bad_encoding};
|
||||||
use ir::{Function, Inst};
|
use ir::{Function, Inst, InstructionData};
|
||||||
|
use isa::RegUnit;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
||||||
|
|
||||||
|
pub static RELOC_NAMES: [&'static str; 1] = ["Call"];
|
||||||
|
|
||||||
|
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
||||||
|
debug_assert!(bits & 0x0f00 == 0, "Invalid encoding bits for Op1*");
|
||||||
|
sink.put1(bits as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modrm_rr<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
|
||||||
|
let reg = reg as u8 & 7;
|
||||||
|
let rm = rm as u8 & 7;
|
||||||
|
let mut b = 0b11000000;
|
||||||
|
b |= reg << 3;
|
||||||
|
b |= rm;
|
||||||
|
sink.put1(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recipe_op1rr<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
|
||||||
|
if let InstructionData::Binary { args, .. } = func.dfg[inst] {
|
||||||
|
put_op1(func.encodings[inst].bits(), sink);
|
||||||
|
modrm_rr(func.locations[args[0]].unwrap_reg(),
|
||||||
|
func.locations[args[1]].unwrap_reg(),
|
||||||
|
sink);
|
||||||
|
} else {
|
||||||
|
panic!("Expected Binary format: {:?}", func.dfg[inst]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
//! Encoding tables for Intel ISAs.
|
//! Encoding tables for Intel ISAs.
|
||||||
|
|
||||||
use ir::InstructionData;
|
use ir::{Opcode, InstructionData};
|
||||||
use ir::types;
|
use ir::types;
|
||||||
use isa::EncInfo;
|
use isa::EncInfo;
|
||||||
use isa::constraints::*;
|
use isa::constraints::*;
|
||||||
use isa::enc_tables::{Level1Entry, Level2Entry};
|
use isa::enc_tables::{Level1Entry, Level2Entry};
|
||||||
use isa::encoding::RecipeSizing;
|
use isa::encoding::RecipeSizing;
|
||||||
|
use super::registers::*;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/encoding-intel.rs"));
|
include!(concat!(env!("OUT_DIR"), "/encoding-intel.rs"));
|
||||||
|
|||||||
@@ -94,4 +94,8 @@ impl TargetIsa for Isa {
|
|||||||
fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) {
|
fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) {
|
||||||
binemit::emit_inst(func, inst, sink)
|
binemit::emit_inst(func, inst, sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reloc_names(&self) -> &'static [&'static str] {
|
||||||
|
&binemit::RELOC_NAMES
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user