Skip to content

Commit

Permalink
ARM64 wip;
Browse files Browse the repository at this point in the history
  • Loading branch information
bnjbvr committed Dec 16, 2017
1 parent dbb9163 commit a951fa2
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 7 deletions.
20 changes: 20 additions & 0 deletions filetests/isa/arm64/binary.cton
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; Binary emission.
test binemit
isa arm64

; The binary encodings can be verified with the command:
;
; sed -ne 's/^ *; asm: *//p' filetests/isa/arm64/binary.cton | llvm-mc -show-encoding -triple=arm64
;

function %RV32I(i32 link [%x1]) -> i32 link [%x1] {
fn0 = function %foo()
sig0 = ()

ebb0(v9999: i32):
; asm: mov w2, #1
[-,%x2] v1 = iconst.i32 1 ; bin: 52800022
; asm: mov x3, #2
[-,%x3] v2 = iconst.i64 2 ; bin: d2800043
return v1
}
4 changes: 2 additions & 2 deletions lib/cretonne/meta/gen_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Generate sources for instruction encoding.
The tables and functions generated here support the `TargetISA::encode()`
function which determines if a given instruction is legal, and if so, it's
function which determines if a given instruction is legal, and if so, its
`Encoding` data which consists of a *recipe* and some *encoding* bits.
The `encode` function doesn't actually generate the binary machine bits. Each
Expand Down Expand Up @@ -44,7 +44,7 @@
satisfied. Otherwise, stop with the default legalization code.
3. Stop with legalization code.
4. Predicate + skip count. Test predicate and skip N entries if it is false.
4. Predicate + stop. Test predicate and stop with the default legalization code
5. Predicate + stop. Test predicate and stop with the default legalization code
if it is false.
The instruction predicate is also used to distinguish between polymorphic
Expand Down
2 changes: 1 addition & 1 deletion lib/cretonne/meta/isa/arm64/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

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()
3 changes: 0 additions & 3 deletions lib/cretonne/meta/isa/arm64/defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,3 @@

ISA = TargetISA('arm64', [base.instructions.GROUP])
A64 = CPUMode('A64', ISA)

# TODO: Refine these
A64.legalize_type(narrow)
139 changes: 139 additions & 0 deletions lib/cretonne/meta/isa/arm64/encodings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"""
ARM64 Encodings.
"""
from __future__ import absolute_import
from base import instructions as base
from base.immediates import intcc

from .defs import A64
from .recipes import MOVZ
from .recipes import Move16

from cdsl.ast import Var
from base.legalize import narrow, expand

# TODO what does this control?
A64.legalize_monomorphic(expand)
A64.legalize_type(
default=narrow,
i32=expand,
i64=expand,
f32=expand,
f64=expand)

# Dummies for instruction predicates.
x = Var('x')
y = Var('y')
dest = Var('dest')
args = Var('args')

# Small constants (16 bits).
A64.enc(base.iconst.i32, Move16, MOVZ(is64bits=0b0))
A64.enc(base.iconst.i64, Move16, MOVZ(is64bits=0b1))

# Integer constants with the low 12 bits clear are materialized by lui.
# A64.enc(base.iconst.i32, U, LUI())
# A64.enc(base.iconst.i64, U, LUI())

# # Basic arithmetic binary instructions are encoded in an R-type instruction.
# for inst, inst_imm, f3, f7 in [
# (base.iadd, base.iadd_imm, 0b000, 0b0000000),
# (base.isub, None, 0b000, 0b0100000),
# (base.bxor, base.bxor_imm, 0b100, 0b0000000),
# (base.bor, base.bor_imm, 0b110, 0b0000000),
# (base.band, base.band_imm, 0b111, 0b0000000)
# ]:
# A64.enc(inst.i64, R, OP(f3, f7))

# # Immediate versions for add/xor/or/and.
# if inst_imm:
# A64.enc(inst_imm.i64, Ii, OPIMM(f3))

# # 32-bit ops in A64.
# A64.enc(base.iadd.i32, R, OP32(0b000, 0b0000000))
# A64.enc(base.isub.i32, R, OP32(0b000, 0b0100000))
# # There are no andiw/oriw/xoriw variations.
# A64.enc(base.iadd_imm.i32, Ii, OPIMM32(0b000))

# # Dynamic shifts have the same masking semantics as the cton base instructions.
# for inst, inst_imm, f3, f7 in [
# (base.ishl, base.ishl_imm, 0b001, 0b0000000),
# (base.ushr, base.ushr_imm, 0b101, 0b0000000),
# (base.sshr, base.sshr_imm, 0b101, 0b0100000),
# ]:

# A64.enc(inst.i64.i64, R, OP(f3, f7))
# A64.enc(inst.i32.i32, R, OP32(f3, f7))
# # Allow i32 shift amounts in 64-bit shifts.
# A64.enc(inst.i64.i32, R, OP(f3, f7))
# A64.enc(inst.i32.i64, R, OP32(f3, f7))

# # Immediate shifts.

# A64.enc(inst_imm.i64, Rshamt, OPIMM(f3, f7))
# A64.enc(inst_imm.i32, Rshamt, OPIMM32(f3, f7))

# # Signed and unsigned integer 'less than'. There are no 'w' variants for
# # comparing 32-bit numbers in A64.

# A64.enc(base.icmp.i64(intcc.slt, x, y), Ricmp, OP(0b010, 0b0000000))

# A64.enc(base.icmp.i64(intcc.ult, x, y), Ricmp, OP(0b011, 0b0000000))


# A64.enc(base.icmp_imm.i64(intcc.slt, x, y), Iicmp, OPIMM(0b010))

# A64.enc(base.icmp_imm.i64(intcc.ult, x, y), Iicmp, OPIMM(0b011))

# # Control flow.

# # Unconditional branches.

# A64.enc(base.jump, UJ, JAL())

# A64.enc(base.call, UJcall, JAL())

# # Conditional branches.
# for cond, f3 in [
# (intcc.eq, 0b000),
# (intcc.ne, 0b001),
# (intcc.slt, 0b100),
# (intcc.sge, 0b101),
# (intcc.ult, 0b110),
# (intcc.uge, 0b111)
# ]:

# A64.enc(base.br_icmp.i64(cond, x, y, dest, args), SB, BRANCH(f3))

# for inst, f3 in [
# (base.brz, 0b000),
# (base.brnz, 0b001)
# ]:

# A64.enc(inst.i64, SBzero, BRANCH(f3))

# A64.enc(inst.b1, SBzero, BRANCH(f3))

# # Returns are a special case of JALR using %x1 to hold the return address.
# # The return address is provided by a special-purpose `link` return value that
# # is added by legalize_signature().

# A64.enc(base.x_return, Iret, JALR())

# A64.enc(base.call_indirect.i64, Icall, JALR())

# # Spill and fill.

# A64.enc(base.spill.i32, GPsp, STORE(0b010))
# A64.enc(base.spill.i64, GPsp, STORE(0b011))

# A64.enc(base.fill.i32, GPfi, LOAD(0b010))
# A64.enc(base.fill.i64, GPfi, LOAD(0b011))

# # Register copies.

# A64.enc(base.copy.i64, Icopy, OPIMM(0b000))
# A64.enc(base.copy.i32, Icopy, OPIMM32(0b000))

# A64.enc(base.regmove.i64, Irmov, OPIMM(0b000))
# A64.enc(base.regmove.i32, Irmov, OPIMM32(0b000))
36 changes: 36 additions & 0 deletions lib/cretonne/meta/isa/arm64/recipes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
ARM64 Encoding recipes.
The encoding recipes defined here correspond to the ARM64 native instruction
formats described in the reference.
"""
from __future__ import absolute_import
from cdsl.isa import EncRecipe
from cdsl.predicates import IsSignedInt
from cdsl.registers import Stack
from base.formats import Binary, BinaryImm, MultiAry, IntCompare, IntCompareImm
from base.formats import Unary, UnaryImm, BranchIcmp, Branch, Jump
from base.formats import Call, IndirectCall, RegMove
from .registers import GPR, FPR, FLAG

def dataProcessing(op0):
assert op0 <= 0b111
return (0b100 << 26) | (op0 << 23)

def moveWide(is64bits, opc):
assert is64bits <= 0b1
assert opc <= 0b11
return ((is64bits << 31) | (opc << 29) | dataProcessing(0b101)) >> 23

def MOVN(is64bits):
return moveWide(is64bits, 0b00)
def MOVZ(is64bits):
return moveWide(is64bits, 0b10)
def MOVK(is64bits):
return moveWide(is64bits, 0b11)

Move16 = EncRecipe(
'Move16', UnaryImm, size=4, ins=(), outs=GPR,
# TODO the predicate could be more precise: has <= 16 adjacent non-zero bits
instp=IsSignedInt(UnaryImm.imm, 16),
emit='put_move(bits, imm.into(), out_reg0, sink);')
28 changes: 27 additions & 1 deletion lib/cretonne/src/isa/arm64/binemit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
//! Emitting binary ARM64 machine code.

use binemit::{CodeSink, bad_encoding};
use ir::{Function, Inst};
use ir::{Function, Inst, InstructionData};
use isa::{RegUnit, StackRef, StackBaseMask};
use regalloc::RegDiversions;

include!(concat!(env!("OUT_DIR"), "/binemit-arm64.rs"));

pub static RELOC_NAMES: [&'static str; 1] = ["Call"];

/// Move instruction.
///
/// 31 22 20 4
/// bits hw imm16 Rd
/// 23 21 5 0
fn put_move<CS: CodeSink + ?Sized>(bits: u16, imm: i64, rd: RegUnit, sink: &mut CS) {
let rd = u32::from(rd) & 0x1f;

let mut i: u32 = rd;
assert!(imm <= 0xffff);
i |= (imm as u32) << 5;

// TODO shifts are not handled here... yet.
let shift = 0;
assert!(shift <= 48 && shift % 16 == 0);
let hw = shift / 16;

i |= hw << 21;
i |= (bits as u32) << 23;

sink.put4(i);
}
2 changes: 2 additions & 0 deletions lib/cretonne/src/isa/arm64/enc_tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use isa;
use isa::constraints::*;
use isa::enc_tables::*;
use isa::encoding::RecipeSizing;
use super::registers::*;
use predicates;

include!(concat!(env!("OUT_DIR"), "/encoding-arm64.rs"));
include!(concat!(env!("OUT_DIR"), "/legalize-arm64.rs"));

0 comments on commit a951fa2

Please sign in to comment.