Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions cranelift/codegen/src/isa/x64/lower.isle
Original file line number Diff line number Diff line change
Expand Up @@ -2332,6 +2332,47 @@
(rule 0 (do_ctz ty orig_ty src)
(bsf_or_else ty src (imm $I64 (ty_bits_u64 orig_ty))))

;; Rules for `cls` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(rule 2 (lower (has_type (ty_32_or_64 ty) (cls src)))
(do_cls ty src))

(rule 1 (lower (has_type (ty_8_or_16 ty) (cls src)))
(let ((extended Gpr (extend_to_gpr src $I32 (ExtendKind.Sign)))
(cls Gpr (do_cls $I32 extended)))
(x64_sub $I32 cls (RegMemImm.Imm (u32_wrapping_sub 32 (ty_bits ty))))))

(rule 0 (lower
(has_type $I128
(cls src)))
(let ((upper Gpr (do_cls $I64 (value_regs_get_gpr src 1)))
(sign_fill Gpr (x64_sarq_mi (value_regs_get_gpr src 1) 63))
(xored Gpr (x64_xor $I64 (value_regs_get_gpr src 0) sign_fill))
(lower Gpr (x64_add $I64
(do_clz $I64 $I64 xored)
(RegMemImm.Imm 63)))
(result_lo Gpr
(with_flags_reg
(x64_cmpq_mi_sxb upper 63)
(cmove $I64 (CC.NZ) upper lower))))
(value_regs result_lo (imm $I64 0))))

;; Implementation helper for cls; operates on 32 or 64-bit units.
(decl do_cls (Type Gpr) Gpr)

;; cls is implemented via clz using the identity: cls(x) = clz(x ^ (x >> 1)) - 1
(rule 1 (do_cls $I64 src)
(let ((shifted Gpr (x64_sarq_mi src 1))
(xored Gpr (x64_xor $I64 src (RegMemImm.Reg shifted)))
(clz Gpr (do_clz $I64 $I64 xored)))
(x64_sub $I64 clz (RegMemImm.Imm 1))))

(rule 0 (do_cls $I32 src)
(let ((shifted Gpr (x64_sarl_mi src 1))
(xored Gpr (x64_xor $I32 src (RegMemImm.Reg shifted)))
(clz Gpr (do_clz $I32 $I32 xored)))
(x64_sub $I32 clz (RegMemImm.Imm 1))))

;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(rule 4 (lower (has_type (ty_32_or_64 ty) (popcnt src)))
Expand Down
53 changes: 53 additions & 0 deletions cranelift/filetests/filetests/isa/x64/cls.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
test interpret
test run
set enable_llvm_abi_extensions=true
target x86_64

function %a(i64) -> i64 {
block0(v0: i64):
v1 = cls.i64 v0
return v1
}

; run: %a(1) == 62
; run: %a(0) == 63 ;; all zeros, 63 matching sign bits
; run: %a(-1) == 63 ;; all ones, 63 matching sign bits
; run: %a(1) == 62 ;; already in the issue
; run: %a(-2) == 62 ;; 1111...1110, one bit differs

function %b(i32) -> i32 {
block0(v0: i32):
v1 = cls.i32 v0
return v1
}
; run: %b(1) == 30
; run: %b(0) == 31
; run: %b(-1) == 31
; run: %b(-2) == 30

function %c(i16) -> i16 {
block0(v0: i16):
v1 = cls.i16 v0
return v1
}
; run: %c(1) == 14
; run: %c(0) == 15
; run: %c(-1) == 15

function %d(i8) -> i8 {
block0(v0: i8):
v1 = cls.i8 v0
return v1
}
; run: %d(1) == 6
; run: %d(0) == 7
; run: %d(-1) == 7

function %e(i128) -> i128 {
block0(v0: i128):
v1 = cls.i128 v0
return v1
}
; run: %e(1) == 126
; run: %e(0) == 127
; run: %e(-1) == 127
Loading