riscv64: Move is_null/is_invalid to ISLE (#5874)

* riscv64: Move `is_null`/`is_invalid` to ISLE

* riscv64: Fix `is_invalid` codegen

* Implement review suggestions

Thanks!

Co-authored-by: Jamey Sharp <jamey@minilop.net>

---------

Co-authored-by: Jamey Sharp <jamey@minilop.net>
This commit is contained in:
Afonso Bordado
2023-02-25 12:48:44 +00:00
committed by GitHub
parent 67e2e57b02
commit 36e92add6f
10 changed files with 33 additions and 116 deletions

View File

@@ -205,11 +205,6 @@
(x ValueRegs) (x ValueRegs)
(y ValueRegs)) (y ValueRegs))
(ReferenceCheck
(rd WritableReg)
(op ReferenceCheckOP)
(x Reg))
(BrTable (BrTable
(index Reg) (index Reg)
(tmp1 WritableReg) (tmp1 WritableReg)
@@ -370,11 +365,6 @@
(Umin) (Umin)
)) ))
(type ReferenceCheckOP (enum
(IsNull)
(IsInvalid)
))
(type AtomicOP (enum (type AtomicOP (enum
(LrW) (LrW)
(ScW) (ScW)
@@ -879,6 +869,17 @@
(rule (select_addi (fits_in_64 ty)) (AluOPRRI.Addi)) (rule (select_addi (fits_in_64 ty)) (AluOPRRI.Addi))
;; Helper for emiting the `sltiu` instruction
(decl sltiu (Reg Imm12) Reg)
(rule (sltiu r imm)
(alu_rr_imm12 (AluOPRRI.SltiU) r imm))
;; Helper for emiting the `seqz` mnemonic
(decl seqz (Reg) Reg)
(rule (seqz r)
(sltiu r (imm12_const 1)))
(decl bnot_128 (ValueRegs) ValueRegs) (decl bnot_128 (ValueRegs) ValueRegs)
(rule (rule
(bnot_128 val) (bnot_128 val)
@@ -1699,14 +1700,6 @@
(decl gen_moves (ValueRegs Type Type) ValueRegs) (decl gen_moves (ValueRegs Type Type) ValueRegs)
(extern constructor gen_moves gen_moves) (extern constructor gen_moves gen_moves)
;;
(decl gen_reference_check (ReferenceCheckOP Reg) Reg)
(rule
(gen_reference_check op r)
(let
((tmp WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.ReferenceCheck tmp op r))))
tmp))
;; ;;
(decl gen_select (Type Reg ValueRegs ValueRegs) ValueRegs) (decl gen_select (Type Reg ValueRegs ValueRegs) ValueRegs)

View File

@@ -1639,23 +1639,6 @@ impl IntSelectOP {
} }
} }
impl ReferenceCheckOP {
pub(crate) fn op_name(self) -> &'static str {
match self {
ReferenceCheckOP::IsNull => "is_null",
ReferenceCheckOP::IsInvalid => "is_invalid",
}
}
#[inline]
pub(crate) fn from_ir_op(op: crate::ir::Opcode) -> Self {
match op {
crate::ir::Opcode::IsInvalid => Self::IsInvalid,
crate::ir::Opcode::IsNull => Self::IsNull,
_ => unreachable!(),
}
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum CsrAddress { pub enum CsrAddress {
Fcsr = 0x3, Fcsr = 0x3,

View File

@@ -680,57 +680,6 @@ impl MachInstEmit for Inst {
.for_each(|inst| inst.emit(&[], sink, emit_info, state)); .for_each(|inst| inst.emit(&[], sink, emit_info, state));
} }
} }
&Inst::ReferenceCheck { rd, op, x } => {
let x = allocs.next(x);
let rd = allocs.next_writable(rd);
let mut insts = SmallInstVec::new();
match op {
ReferenceCheckOP::IsNull => {
insts.push(Inst::CondBr {
taken: BranchTarget::ResolvedOffset(Inst::INSTRUCTION_SIZE * 3),
not_taken: BranchTarget::zero(),
kind: IntegerCompare {
kind: IntCC::Equal,
rs1: zero_reg(),
rs2: x,
},
});
// here is false
insts.push(Inst::load_imm12(rd, Imm12::FALSE));
insts.push(Inst::Jal {
dest: BranchTarget::ResolvedOffset(Inst::INSTRUCTION_SIZE * 2),
});
// here is true
insts.push(Inst::load_imm12(rd, Imm12::TRUE));
}
ReferenceCheckOP::IsInvalid => {
// todo:: right now just check if it is null
// null is a valid reference??????
insts.push(Inst::CondBr {
taken: BranchTarget::ResolvedOffset(Inst::INSTRUCTION_SIZE * 3),
not_taken: BranchTarget::zero(),
kind: IntegerCompare {
kind: IntCC::Equal,
rs1: zero_reg(),
rs2: x,
},
});
// here is false
insts.push(Inst::load_imm12(rd, Imm12::FALSE));
insts.push(Inst::Jal {
dest: BranchTarget::ResolvedOffset(Inst::INSTRUCTION_SIZE * 2),
});
// here is true
insts.push(Inst::load_imm12(rd, Imm12::TRUE));
}
}
insts
.into_iter()
.for_each(|i| i.emit(&[], sink, emit_info, state));
}
&Inst::Args { .. } => { &Inst::Args { .. } => {
// Nothing: this is a pseudoinstruction that serves // Nothing: this is a pseudoinstruction that serves
// only to constrain registers at a certain point. // only to constrain registers at a certain point.

View File

@@ -51,8 +51,7 @@ pub(crate) type VecWritableReg = Vec<Writable<Reg>>;
use crate::isa::riscv64::lower::isle::generated_code::MInst; use crate::isa::riscv64::lower::isle::generated_code::MInst;
pub use crate::isa::riscv64::lower::isle::generated_code::{ pub use crate::isa::riscv64::lower::isle::generated_code::{
AluOPRRI, AluOPRRR, AtomicOP, CsrOP, FClassResult, FFlagsException, FenceFm, FloatRoundOP, AluOPRRI, AluOPRRR, AtomicOP, CsrOP, FClassResult, FFlagsException, FenceFm, FloatRoundOP,
FloatSelectOP, FpuOPRR, FpuOPRRR, FpuOPRRRR, IntSelectOP, LoadOP, MInst as Inst, FloatSelectOP, FpuOPRR, FpuOPRRR, FpuOPRRRR, IntSelectOP, LoadOP, MInst as Inst, StoreOP, FRM,
ReferenceCheckOP, StoreOP, FRM,
}; };
type BoxCallInfo = Box<CallInfo>; type BoxCallInfo = Box<CallInfo>;
@@ -471,10 +470,6 @@ fn riscv64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
collector.reg_early_def(d.clone()); collector.reg_early_def(d.clone());
} }
} }
&Inst::ReferenceCheck { rd, x, .. } => {
collector.reg_use(x);
collector.reg_def(rd);
}
&Inst::AtomicCas { &Inst::AtomicCas {
offset, offset,
t0, t0,
@@ -1185,12 +1180,6 @@ impl Inst {
imm.bits imm.bits
) )
} }
&Inst::ReferenceCheck { rd, op, x } => {
let x = format_reg(x, allocs);
let rd = format_reg(rd.to_reg(), allocs);
format!("{} {},{}", op.op_name(), rd, x)
}
&Inst::Jalr { rd, base, offset } => { &Inst::Jalr { rd, base, offset } => {
let base = format_reg(base, allocs); let base = format_reg(base, allocs);
let rd = format_reg(rd.to_reg(), allocs); let rd = format_reg(rd.to_reg(), allocs);
@@ -1344,6 +1333,9 @@ impl Inst {
(AluOPRRI::Xori, _, imm12) if imm12.as_i16() == -1 => { (AluOPRRI::Xori, _, imm12) if imm12.as_i16() == -1 => {
return format!("not {},{}", rd, rs_s); return format!("not {},{}", rd, rs_s);
} }
(AluOPRRI::SltiU, _, imm12) if imm12.as_i16() == 1 => {
return format!("seqz {},{}", rd, rs_s);
}
(alu_op, _, _) if alu_op.option_funct12().is_some() => { (alu_op, _, _) if alu_op.option_funct12().is_some() => {
format!("{} {},{}", alu_op.op_name(), rd, rs_s) format!("{} {},{}", alu_op.op_name(), rd, rs_s)
} }

View File

@@ -612,14 +612,16 @@
(gen_stack_addr ss offset)) (gen_stack_addr ss offset))
;;;;; Rules for `is_null`;;;;;;;;; ;;;;; Rules for `is_null`;;;;;;;;;
(rule
(lower (is_null v)) ;; Null references are represented by the constant value `0`.
(gen_reference_check (ReferenceCheckOP.IsNull) v)) (rule (lower (is_null v))
(seqz v))
;;;;; Rules for `is_invalid`;;;;;;;;; ;;;;; Rules for `is_invalid`;;;;;;;;;
(rule
(lower (is_invalid v)) ;; Invalid references are represented by the constant value `-1`.
(gen_reference_check (ReferenceCheckOP.IsInvalid) v)) (rule (lower (is_invalid v))
(seqz (alu_rr_imm12 (AluOPRRI.Addi) v (imm12_const 1))))
;;;;; Rules for `select`;;;;;;;;; ;;;;; Rules for `select`;;;;;;;;;
(rule (rule

View File

@@ -452,7 +452,7 @@ fn construct_dest<F: std::ops::FnMut(Type) -> WritableReg>(
mut alloc: F, mut alloc: F,
ty: Type, ty: Type,
) -> WritableValueRegs { ) -> WritableValueRegs {
if ty.is_int() { if ty.is_int() || ty.is_ref() {
if ty.bits() == 128 { if ty.bits() == 128 {
WritableValueRegs::two(alloc(I64), alloc(I64)) WritableValueRegs::two(alloc(I64), alloc(I64))
} else { } else {

View File

@@ -2025,7 +2025,7 @@
;; Rules for `is_invalid` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Rules for `is_invalid` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Null references are represented by the constant value `-1`. ;; Invalid references are represented by the constant value `-1`.
(rule (lower (is_invalid src @ (value_type $R64))) (rule (lower (is_invalid src @ (value_type $R64)))
(with_flags (with_flags
(x64_cmp_imm (OperandSize.Size64) 0xffffffff src) ;; simm32 0xffff_ffff is sign-extended to -1. (x64_cmp_imm (OperandSize.Size64) 0xffffffff src) ;; simm32 0xffff_ffff is sign-extended to -1.

View File

@@ -23,15 +23,12 @@ block0(v0: r64):
; VCode: ; VCode:
; block0: ; block0:
; is_null a0,a0 ; seqz a0,a0
; ret ; ret
; ;
; Disassembled: ; Disassembled:
; block0: ; offset 0x0 ; block0: ; offset 0x0
; beq zero, a0, 0xc ; seqz a0, a0
; mv a0, zero
; j 8
; addi a0, zero, 1
; ret ; ret
function %f2(r64) -> i8 { function %f2(r64) -> i8 {
@@ -42,15 +39,14 @@ block0(v0: r64):
; VCode: ; VCode:
; block0: ; block0:
; is_invalid a0,a0 ; addi t2,a0,1
; seqz a0,t2
; ret ; ret
; ;
; Disassembled: ; Disassembled:
; block0: ; offset 0x0 ; block0: ; offset 0x0
; beq zero, a0, 0xc ; addi t2, a0, 1
; mv a0, zero ; seqz a0, t2
; j 8
; addi a0, zero, 1
; ret ; ret
function %f3() -> r64 { function %f3() -> r64 {

View File

@@ -2,6 +2,7 @@ test run
target aarch64 target aarch64
target x86_64 target x86_64
target s390x target s390x
target riscv64gc
; the interpreter does not support bitcasting to/from references ; the interpreter does not support bitcasting to/from references
function %bitcast_ir64(i64) -> i8 { function %bitcast_ir64(i64) -> i8 {

View File

@@ -3,6 +3,7 @@ test run
target aarch64 target aarch64
target x86_64 target x86_64
target s390x target s390x
target riscv64gc
function %is_null_true_r64() -> i8 { function %is_null_true_r64() -> i8 {
block0: block0: