Skip to content

Commit

Permalink
big ole WIP: Add Bswap instruction to IR and implement in x64 (byteco…
Browse files Browse the repository at this point in the history
…dealliance#1092)

Adds Bswap to the Cranelift IR. Implements the Bswap instruction
in the x64 codegen backend (32 and 64 bit).

Does not implement Bswap for aarch64 or s390x, and also does not
handle 16-bit bswap in x64 (which requires a different instruction,
XCHG). Those are left for future commits.
  • Loading branch information
11evan committed Oct 18, 2022
1 parent ff0c45b commit f4509d3
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 1 deletion.
17 changes: 17 additions & 0 deletions cranelift/codegen/meta/src/shared/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2769,6 +2769,23 @@ pub(crate) fn define(
.operands_out(vec![a]),
);

// todo evan: are the argument types right for u64/u32/16 ??
// what is an iB?
//
ig.push(
Inst::new(
"bswap",
r#"
Reverse the byte order of an integer.
Reverses the bytes in ``x``.
"#,
&formats.unary,
)
.operands_in(vec![x])
.operands_out(vec![a]),
);

ig.push(
Inst::new(
"clz",
Expand Down
8 changes: 8 additions & 0 deletions cranelift/codegen/src/isa/aarch64/lower_inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ pub(crate) fn lower_insn_to_regs(

Opcode::Bitrev | Opcode::Clz | Opcode::Cls | Opcode::Ctz => implemented_in_isle(ctx),

Opcode::Bswap => {
unreachable!(
"TODO: not yet implemented in ISLE: inst = `{}`, type = `{:?}`",
ctx.dfg().display_inst(ir_inst),
ty
)
}

Opcode::Popcnt => implemented_in_isle(ctx),

Opcode::Load
Expand Down
3 changes: 2 additions & 1 deletion cranelift/codegen/src/isa/s390x/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ impl LowerBackend for S390xBackend {
| Opcode::DynamicStackLoad
| Opcode::DynamicStackStore
| Opcode::DynamicStackAddr
| Opcode::ExtractVector => {
| Opcode::ExtractVector
| Opcode::Bswap => {
unreachable!(
"TODO: not yet implemented in ISLE: inst = `{}`, type = `{:?}`",
ctx.dfg().display_inst(ir_inst),
Expand Down
28 changes: 28 additions & 0 deletions cranelift/codegen/src/isa/x64/inst.isle
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@
(Setcc (cc CC)
(dst WritableGpr))

;; todo evan how to give different sizes
;; todo evan where to put the xchg impl - hide behind this or expose?
;; Byteswap
(Bswap (size OperandSize) ;; 4 or 8
(dst WritableGpr))

;; =========================================
;; Conditional moves.

Expand Down Expand Up @@ -566,6 +572,8 @@
Tzcnt
Popcnt))

;; todo evan define Opcodes for BSWAP and XCHG

(type DivOrRemKind extern
(enum SignedDiv
UnsignedDiv
Expand Down Expand Up @@ -1965,6 +1973,26 @@
(rule (x64_sar ty src1 src2)
(shift_r ty (ShiftKind.ShiftRightArithmetic) src1 src2))

;; Helpers for creating byteswap instructions.
;; In x64, 32- and 64-bit registers use BSWAP instruction, however
;; this instruction is undefined for 16-bit registers, which instead
;; use XCHG

;; TODO EVAN
;; (decl unaryop_bswap (Type) UnaryOp)
;; (rule (unaryop_bswap $I32) (UnaryOp.BSwap32))
;; (rule (unaryop_bswap $I64) (UnaryOp.BSwap64))

;; (decl bswap_reg (Type Reg) Reg)
;; (rule (bswap_reg ty x) (unary_rr ty (unaryop_bswap ty) x))

;; (decl x64_bswap (Type Gpr) Gpr)
;; (rule (x64_bswap ty src)
;; (let ((dst WritableGpr (temp_writable_gpr))
;; (size OperandSize (operand_size_of_type_32_64 ty))
;; (_ Unit (emit (MInst.UnaryRmR size (UnaryRmROpcode.Lzcnt) src dst))))
;; dst))

;; Helper for creating `MInst.CmpRmiR` instructions.
(decl cmp_rmi_r (OperandSize CmpOpcode GprMemImm Gpr) ProducesFlags)
(rule (cmp_rmi_r size opcode src1 src2)
Expand Down
2 changes: 2 additions & 0 deletions cranelift/codegen/src/isa/x64/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,8 @@ pub(crate) fn emit(
);
}

// todo evan: implement BSWAP like the ShiftR?

Inst::Cmove {
size,
cc,
Expand Down
9 changes: 9 additions & 0 deletions cranelift/codegen/src/isa/x64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ impl Inst {
Inst::AluRmiR { .. }
| Inst::AluRM { .. }
| Inst::AtomicRmwSeq { .. }
| Inst::Bswap { .. }
| Inst::CallKnown { .. }
| Inst::CallUnknown { .. }
| Inst::CheckedDivOrRemSeq { .. }
Expand Down Expand Up @@ -1373,6 +1374,11 @@ impl PrettyPrint for Inst {
format!("{} {}", ljustify2("set".to_string(), cc.to_string()), dst)
}

Inst::Bswap { size, dst } => {
let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes(), allocs);
format!("{} {}", ljustify2("bswap".to_string(), suffix_bwlq(*size)), dst)
}

Inst::Cmove {
size,
cc,
Expand Down Expand Up @@ -1953,6 +1959,9 @@ fn x64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandCol
Inst::Setcc { dst, .. } => {
collector.reg_def(dst.to_writable_reg());
}
Inst::Bswap { dst, .. } => {
collector.reg_def(dst.to_writable_reg());
}
Inst::Cmove {
consequent,
alternative,
Expand Down
6 changes: 6 additions & 0 deletions cranelift/codegen/src/isa/x64/lower.isle
Original file line number Diff line number Diff line change
Expand Up @@ -2044,6 +2044,12 @@
hi32)))
swap32))

;; todo evan
;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; (rule (lower (has_type $I64 (bswap src)))
;; (do_bswap64 $I64 src))

;; Rules for `is_null` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Null references are represented by the constant value `0`.
Expand Down
1 change: 1 addition & 0 deletions cranelift/codegen/src/isa/x64/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ fn lower_insn_to_regs(
| Opcode::Ctz
| Opcode::Popcnt
| Opcode::Bitrev
| Opcode::Bswap
| Opcode::IsNull
| Opcode::IsInvalid
| Opcode::Uextend
Expand Down

0 comments on commit f4509d3

Please sign in to comment.