From 5e3bb588a86cb00d53990deac3ecd0bd07b997c4 Mon Sep 17 00:00:00 2001 From: Damian Heaton <87125748+dheaton-arm@users.noreply.github.com> Date: Thu, 28 Jul 2022 23:36:13 +0100 Subject: [PATCH] Port `Fence`, `IsNull`/`IsInvalid` & `Debugtrap` to ISLE (AArch64) (#4548) Ported the existing implementation of the following Opcodes for AArch64 to ISLE: - `Fence` - `IsNull` - `IsInvalid` - `Debugtrap` Copyright (c) 2022 Arm Limited --- cranelift/codegen/src/isa/aarch64/inst.isle | 21 ++++++++++ cranelift/codegen/src/isa/aarch64/lower.isle | 26 ++++++++++++ .../codegen/src/isa/aarch64/lower_inst.rs | 37 ++-------------- .../runtests/ref64-invalid-null.clif | 42 +++++++++++++++++++ 4 files changed, 92 insertions(+), 34 deletions(-) create mode 100644 cranelift/filetests/filetests/runtests/ref64-invalid-null.clif diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 041bda01c4ac..60aa7fc45cd9 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -1567,6 +1567,27 @@ (MInst.AluRRR (ALUOp.SubS) (operand_size ty) dst src1 src2) dst))) +;; Helper for materializing a boolean value into a register from +;; flags. +(decl materialize_bool_result (u8 Cond) ConsumesFlags) +(rule (materialize_bool_result 1 cond) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.CSet dst cond) + dst))) + +(rule -1 (materialize_bool_result _ty_bits cond) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.CSetm dst cond) + dst))) + +(decl cmn_imm (OperandSize Reg Imm12) ProducesFlags) +(rule (cmn_imm size src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRImm12 (ALUOp.AddS) size (writable_zero_reg) + src1 src2))) + (decl cmp_imm (OperandSize Reg Imm12) ProducesFlags) (rule (cmp_imm size src1 src2) (ProducesFlags.ProducesFlagsSideEffect diff --git a/cranelift/codegen/src/isa/aarch64/lower.isle b/cranelift/codegen/src/isa/aarch64/lower.isle index 34c758227a1c..1a79d908ae27 100644 --- a/cranelift/codegen/src/isa/aarch64/lower.isle +++ b/cranelift/codegen/src/isa/aarch64/lower.isle @@ -1699,3 +1699,29 @@ (let ((low_half Reg (uqxtn x (lane_size ty))) (result Reg (uqxtn2 low_half y (lane_size ty)))) result)) + +;;;; Rules for `Fence` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (fence)) + (let ((_ Unit (emit (MInst.Fence)))) + (output_none))) + +;;;; Rules for `IsNull` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type out_ty (is_null x @ (value_type ty)))) + (with_flags (cmp_imm (operand_size ty) x (u8_into_imm12 0)) + (materialize_bool_result + (ty_bits out_ty) (Cond.Eq)))) + +;;;; Rules for `IsInvalid` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type out_ty (is_invalid x @ (value_type ty)))) + (with_flags (cmn_imm (operand_size ty) x (u8_into_imm12 1)) + (materialize_bool_result + (ty_bits out_ty) (Cond.Eq)))) + +;;;; Rules for `Debugtrap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (debugtrap)) + (let ((_ Unit (emit (MInst.Brk)))) + (output_none))) diff --git a/cranelift/codegen/src/isa/aarch64/lower_inst.rs b/cranelift/codegen/src/isa/aarch64/lower_inst.rs index e02de737bb4f..127219700233 100644 --- a/cranelift/codegen/src/isa/aarch64/lower_inst.rs +++ b/cranelift/codegen/src/isa/aarch64/lower_inst.rs @@ -254,9 +254,7 @@ pub(crate) fn lower_insn_to_regs>( Opcode::AtomicStore => implemented_in_isle(ctx), - Opcode::Fence => { - ctx.emit(Inst::Fence {}); - } + Opcode::Fence => implemented_in_isle(ctx), Opcode::StackLoad | Opcode::StackStore @@ -399,34 +397,7 @@ pub(crate) fn lower_insn_to_regs>( materialize_bool_result(ctx, insn, rd, cond); } - Opcode::IsNull | Opcode::IsInvalid => { - // Null references are represented by the constant value 0; invalid references are - // represented by the constant value -1. See `define_reftypes()` in - // `meta/src/isa/x86/encodings.rs` to confirm. - let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); - let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); - let ty = ctx.input_ty(insn, 0); - let (alu_op, const_value) = match op { - Opcode::IsNull => { - // cmp rn, #0 - (ALUOp::SubS, 0) - } - Opcode::IsInvalid => { - // cmn rn, #1 - (ALUOp::AddS, 1) - } - _ => unreachable!(), - }; - let const_value = ResultRSEImm12::Imm12(Imm12::maybe_from_u64(const_value).unwrap()); - ctx.emit(alu_inst_imm12( - alu_op, - ty, - writable_zero_reg(), - rn, - const_value, - )); - materialize_bool_result(ctx, insn, rd, Cond::Eq); - } + Opcode::IsNull | Opcode::IsInvalid => implemented_in_isle(ctx), Opcode::Copy => { let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); @@ -546,9 +517,7 @@ pub(crate) fn lower_insn_to_regs>( } } - Opcode::Debugtrap => { - ctx.emit(Inst::Brk); - } + Opcode::Debugtrap => implemented_in_isle(ctx), Opcode::Trap | Opcode::ResumableTrap => implemented_in_isle(ctx), diff --git a/cranelift/filetests/filetests/runtests/ref64-invalid-null.clif b/cranelift/filetests/filetests/runtests/ref64-invalid-null.clif new file mode 100644 index 000000000000..f052b5ac5e45 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/ref64-invalid-null.clif @@ -0,0 +1,42 @@ +; Tests for platforms with 64-bit references. +test run +target aarch64 +target x86_64 +target s390x + +function %is_null_true_r64() -> b1 { +block0: + v0 = null.r64 + v1 = is_null v0 + return v1 +} +; run: %is_null_true_r64() == true + +function %is_null_r64(i64) -> b1 { +block0(v0: i64): + v1 = raw_bitcast.r64 v0 + v2 = is_null v1 + return v2 +} +; run: %is_null_r64(256347) == false +; run: %is_null_r64(-1) == false +; run: %is_null_r64(0) == true + +function %is_invalid_r64(i64) -> b1 { +block0(v0: i64): + v1 = raw_bitcast.r64 v0 + v2 = is_invalid v1 + return v2 +} +; run: %is_invalid_r64(0xffffffffffffffff) == true +; run: %is_invalid_r64(-1) == true +; run: %is_invalid_r64(256347) == false +; run: %is_invalid_r64(0) == false + +function %is_invalid_null_r64() -> b1 { +block0: + v0 = null.r64 + v1 = is_invalid v0 + return v1 +} +; run: %is_invalid_null_r64() == false