From 041fda63acdee5a4c2c235f31ab8fef1231fb1dd Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Sun, 30 Apr 2017 13:34:51 -0700 Subject: [PATCH] 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. --- cranelift/filetests/isa/intel/binary32.cton | 23 +++++++ lib/cretonne/meta/isa/intel/__init__.py | 2 +- lib/cretonne/meta/isa/intel/encodings.py | 10 +++ lib/cretonne/meta/isa/intel/recipes.py | 67 +++++++++++++++++++++ lib/cretonne/src/isa/intel/binemit.rs | 30 ++++++++- lib/cretonne/src/isa/intel/enc_tables.rs | 3 +- lib/cretonne/src/isa/intel/mod.rs | 4 ++ 7 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 cranelift/filetests/isa/intel/binary32.cton create mode 100644 lib/cretonne/meta/isa/intel/encodings.py create mode 100644 lib/cretonne/meta/isa/intel/recipes.py diff --git a/cranelift/filetests/isa/intel/binary32.cton b/cranelift/filetests/isa/intel/binary32.cton new file mode 100644 index 0000000000..c8440440b9 --- /dev/null +++ b/cranelift/filetests/isa/intel/binary32.cton @@ -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 +} diff --git a/lib/cretonne/meta/isa/intel/__init__.py b/lib/cretonne/meta/isa/intel/__init__.py index 6aea0fd288..0828d790aa 100644 --- a/lib/cretonne/meta/isa/intel/__init__.py +++ b/lib/cretonne/meta/isa/intel/__init__.py @@ -17,7 +17,7 @@ is no x87 floating point support. from __future__ import absolute_import from . import defs -from . import settings, registers # noqa +from . import encodings, settings, registers # noqa # Re-export the primary target ISA definition. ISA = defs.ISA.finish() diff --git a/lib/cretonne/meta/isa/intel/encodings.py b/lib/cretonne/meta/isa/intel/encodings.py new file mode 100644 index 0000000000..5d1ffdb4ec --- /dev/null +++ b/lib/cretonne/meta/isa/intel/encodings.py @@ -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)) diff --git a/lib/cretonne/meta/isa/intel/recipes.py b/lib/cretonne/meta/isa/intel/recipes.py new file mode 100644 index 0000000000..9535598917 --- /dev/null +++ b/lib/cretonne/meta/isa/intel/recipes.py @@ -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: +# +# Op1* OP(op) +# 0F Op2* OP(op) +# 0F 38 Op3* OP38(op) +# 0F 3A Op3* OP3A(op) +# 66 Mp1* MP66(op) +# 66 0F Mp2* MP66(op) +# 66 0F 38 Mp3* MP6638(op) +# 66 0F 3A Mp3* MP663A(op) +# F2 Mp1* MPF2(op) +# F2 0F Mp2* MPF2(op) +# F2 0F 38 Mp3* MPF238(op) +# F2 0F 3A Mp3* MPF23A(op) +# F3 Mp1* MPF3(op) +# F3 0F Mp2* MPF3(op) +# F3 0F 38 Mp3* MPF338(op) +# F3 0F 3A Mp3* MPF33A(op) +# +# VEX/XOP and EVEX prefixes are not yet supported. +# +# The encoding bits are: +# +# 0-7: The opcode byte . +# 8-9: pp, mandatory prefix: +# 00 none (Op*) +# 01 66 (Mp*) +# 10 F3 (Mp*) +# 11 F2 (Mp*) +# 10-11: mm, opcode map: +# 00 (Op1/Mp1) +# 01 0F (Op2/Mp2) +# 10 0F 38 (Op3/Mp3) +# 11 0F 3A (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) diff --git a/lib/cretonne/src/isa/intel/binemit.rs b/lib/cretonne/src/isa/intel/binemit.rs index 8870abd8f1..4b322c6969 100644 --- a/lib/cretonne/src/isa/intel/binemit.rs +++ b/lib/cretonne/src/isa/intel/binemit.rs @@ -1,6 +1,34 @@ //! Emitting binary Intel machine code. 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")); + +pub static RELOC_NAMES: [&'static str; 1] = ["Call"]; + +fn put_op1(bits: u16, sink: &mut CS) { + debug_assert!(bits & 0x0f00 == 0, "Invalid encoding bits for Op1*"); + sink.put1(bits as u8); +} + +fn modrm_rr(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(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]); + } +} diff --git a/lib/cretonne/src/isa/intel/enc_tables.rs b/lib/cretonne/src/isa/intel/enc_tables.rs index 1ee1fbd4b3..1ec93f00a9 100644 --- a/lib/cretonne/src/isa/intel/enc_tables.rs +++ b/lib/cretonne/src/isa/intel/enc_tables.rs @@ -1,10 +1,11 @@ //! Encoding tables for Intel ISAs. -use ir::InstructionData; +use ir::{Opcode, InstructionData}; use ir::types; use isa::EncInfo; use isa::constraints::*; use isa::enc_tables::{Level1Entry, Level2Entry}; use isa::encoding::RecipeSizing; +use super::registers::*; include!(concat!(env!("OUT_DIR"), "/encoding-intel.rs")); diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs index 5871c8766a..1711be3166 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -94,4 +94,8 @@ impl TargetIsa for Isa { fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } + + fn reloc_names(&self) -> &'static [&'static str] { + &binemit::RELOC_NAMES + } }