Skip to content

Commit b617d50

Browse files
authored
riscv64: Move Round Instructions to ISLE (bytecodealliance#8546)
* riscv64: Split float rounding tests in separate files * riscv64: Move Float Round Instructions to ISLE This commit moves the lowerings for the various rounding instructions (ceil,floor,trunc,nearest) into ISLE. The algorithm is mostly unchanged, but with some slight tweaks to generate fewer instructions. * riscv64: Transform canonical NaN's into arithmetic Nan's for inexact values in round functions
1 parent b44c23d commit b617d50

File tree

11 files changed

+409
-560
lines changed

11 files changed

+409
-560
lines changed

cranelift/codegen/src/isa/riscv64/inst.isle

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,6 @@
249249
;; A dummy use, useful to keep a value alive.
250250
(DummyUse
251251
(reg Reg))
252-
;;;
253-
(FloatRound
254-
(op FloatRoundOP)
255-
(rd WritableReg)
256-
(int_tmp WritableReg)
257-
(f_tmp WritableReg)
258-
(rs Reg)
259-
(ty Type))
260252

261253
;; popcnt if target doesn't support extension B
262254
;; use iteration to implement.
@@ -358,14 +350,6 @@
358350
(vstate VState))
359351
))
360352

361-
362-
(type FloatRoundOP (enum
363-
(Nearest)
364-
(Ceil)
365-
(Floor)
366-
(Trunc)
367-
))
368-
369353
(type AtomicOP (enum
370354
(LrW)
371355
(ScW)
@@ -1059,16 +1043,6 @@
10591043
(decl pure has_zbs () bool)
10601044
(extern constructor has_zbs has_zbs)
10611045

1062-
(decl gen_float_round (FloatRoundOP Reg Type) Reg)
1063-
(rule
1064-
(gen_float_round op rs ty)
1065-
(let
1066-
((rd WritableReg (temp_writable_reg ty))
1067-
(tmp WritableXReg (temp_writable_xreg))
1068-
(tmp2 WritableFReg (temp_writable_freg))
1069-
(_ Unit (emit (MInst.FloatRound op rd tmp tmp2 rs ty))))
1070-
(writable_reg_to_reg rd)))
1071-
10721046

10731047
;;;; Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10741048

@@ -2489,6 +2463,37 @@
24892463
)
24902464

24912465

2466+
;; Rounds a FReg by converting the value into an integer and back with a specified
2467+
;; float rounding mode.
2468+
(decl float_round_fcvt (Type FRM FReg) FReg)
2469+
(rule (float_round_fcvt $F32 frm rs) (rv_fcvtsw frm (rv_fcvtws frm rs)))
2470+
(rule (float_round_fcvt $F64 frm rs) (rv_fcvtdl frm (rv_fcvtld frm rs)))
2471+
2472+
(decl gen_float_round (FRM FReg Type) FReg)
2473+
(rule (gen_float_round frm rs ty)
2474+
(let (;; if rs is NaN/+-Infinity/+-Zero or if the exponent is larger than # of bits
2475+
;; in mantissa, the result is the same as src, check for these cases first.
2476+
(max FReg (imm ty (float_int_max ty)))
2477+
(abs FReg (rv_fabs ty rs))
2478+
(exact XReg (rv_flt ty abs max))
2479+
2480+
;; Manually round the value using the fcvt instructions
2481+
;; to move the value to an integer register and back.
2482+
(fcvt FReg (float_round_fcvt ty frm rs))
2483+
;; Restore the sign bit from the initial value.
2484+
(rounded FReg (rv_fsgnj ty fcvt rs))
2485+
2486+
;; We want to return a arithmetic nan if the input is a canonical nan.
2487+
;; Convert them by adding 0.0 to the input.
2488+
(float_zero FReg (gen_bitcast (zero_reg) (float_int_of_same_size ty) ty))
2489+
(corrected_nan FReg (rv_fadd ty (FRM.RNE) rs float_zero)))
2490+
2491+
;; Check if the value cannot be rounded exactly and return the source input if so
2492+
(gen_select_freg (cmp_eqz exact) corrected_nan rounded)))
2493+
2494+
2495+
2496+
24922497
(decl gen_stack_addr (StackSlot Offset32) Reg)
24932498
(extern constructor gen_stack_addr gen_stack_addr)
24942499

cranelift/codegen/src/isa/riscv64/inst/args.rs

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -409,43 +409,6 @@ impl FpuOPRR {
409409
}
410410
}
411411

412-
pub(crate) fn float_convert_2_int_op(from: Type, is_type_signed: bool, to: Type) -> Self {
413-
let type_32 = to.bits() <= 32;
414-
match from {
415-
F32 => {
416-
if is_type_signed {
417-
if type_32 {
418-
Self::FcvtWS
419-
} else {
420-
Self::FcvtLS
421-
}
422-
} else {
423-
if type_32 {
424-
Self::FcvtWuS
425-
} else {
426-
Self::FcvtLuS
427-
}
428-
}
429-
}
430-
F64 => {
431-
if is_type_signed {
432-
if type_32 {
433-
Self::FcvtWD
434-
} else {
435-
Self::FcvtLD
436-
}
437-
} else {
438-
if type_32 {
439-
Self::FcvtWuD
440-
} else {
441-
Self::FcvtLuD
442-
}
443-
}
444-
}
445-
_ => unreachable!("from type:{}", from),
446-
}
447-
}
448-
449412
pub(crate) fn op_code(self) -> u32 {
450413
match self {
451414
FpuOPRR::FsqrtS
@@ -1606,27 +1569,6 @@ impl Inst {
16061569
}
16071570
}
16081571

1609-
impl FloatRoundOP {
1610-
pub(crate) fn op_name(self) -> &'static str {
1611-
match self {
1612-
FloatRoundOP::Nearest => "nearest",
1613-
FloatRoundOP::Ceil => "ceil",
1614-
FloatRoundOP::Floor => "floor",
1615-
FloatRoundOP::Trunc => "trunc",
1616-
}
1617-
}
1618-
1619-
pub(crate) fn to_frm(self) -> FRM {
1620-
match self {
1621-
FloatRoundOP::Nearest => FRM::RNE,
1622-
FloatRoundOP::Ceil => FRM::RUP,
1623-
FloatRoundOP::Floor => FRM::RDN,
1624-
FloatRoundOP::Trunc => FRM::RTZ,
1625-
}
1626-
}
1627-
}
1628-
1629-
///
16301572
pub(crate) fn f32_cvt_to_int_bounds(signed: bool, out_bits: u32) -> (f32, f32) {
16311573
match (signed, out_bits) {
16321574
(true, 8) => (i8::min_value() as f32 - 1., i8::max_value() as f32 + 1.),

cranelift/codegen/src/isa/riscv64/inst/emit.rs

Lines changed: 0 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -141,35 +141,6 @@ impl Inst {
141141
}
142142
}
143143

144-
// emit a float is not a nan.
145-
pub(crate) fn emit_not_nan(rd: Writable<Reg>, rs: Reg, ty: Type) -> Inst {
146-
Inst::FpuRRR {
147-
alu_op: if ty == F32 {
148-
FpuOPRRR::FeqS
149-
} else {
150-
FpuOPRRR::FeqD
151-
},
152-
frm: FRM::RDN,
153-
rd: rd,
154-
rs1: rs,
155-
rs2: rs,
156-
}
157-
}
158-
159-
pub(crate) fn emit_fabs(rd: Writable<Reg>, rs: Reg, ty: Type) -> Inst {
160-
Inst::FpuRRR {
161-
alu_op: if ty == F32 {
162-
FpuOPRRR::FsgnjxS
163-
} else {
164-
FpuOPRRR::FsgnjxD
165-
},
166-
frm: FRM::RDN,
167-
rd: rd,
168-
rs1: rs,
169-
rs2: rs,
170-
}
171-
}
172-
173144
/// Returns Some(VState) if this insturction is expecting a specific vector state
174145
/// before emission.
175146
fn expected_vstate(&self) -> Option<&VState> {
@@ -219,7 +190,6 @@ impl Inst {
219190
| Inst::TrapIf { .. }
220191
| Inst::Unwind { .. }
221192
| Inst::DummyUse { .. }
222-
| Inst::FloatRound { .. }
223193
| Inst::Popcnt { .. }
224194
| Inst::Cltz { .. }
225195
| Inst::Brev8 { .. }
@@ -2090,142 +2060,6 @@ impl Inst {
20902060
}
20912061
.emit(&[], sink, emit_info, state);
20922062
}
2093-
&Inst::FloatRound {
2094-
op,
2095-
rd,
2096-
int_tmp,
2097-
f_tmp,
2098-
rs,
2099-
ty,
2100-
} => {
2101-
// this code is port from glibc ceil floor ... implementation.
2102-
let label_nan = sink.get_label();
2103-
let label_x = sink.get_label();
2104-
let label_jump_over = sink.get_label();
2105-
// check if is nan.
2106-
Inst::emit_not_nan(int_tmp, rs, ty).emit(&[], sink, emit_info, state);
2107-
Inst::CondBr {
2108-
taken: CondBrTarget::Label(label_nan),
2109-
not_taken: CondBrTarget::Fallthrough,
2110-
kind: IntegerCompare {
2111-
kind: IntCC::Equal,
2112-
rs1: int_tmp.to_reg(),
2113-
rs2: zero_reg(),
2114-
},
2115-
}
2116-
.emit(&[], sink, emit_info, state);
2117-
fn max_value_need_round(ty: Type) -> u64 {
2118-
match ty {
2119-
F32 => {
2120-
let x: u64 = 1 << f32::MANTISSA_DIGITS;
2121-
let x = x as f32;
2122-
let x = u32::from_le_bytes(x.to_le_bytes());
2123-
x as u64
2124-
}
2125-
F64 => {
2126-
let x: u64 = 1 << f64::MANTISSA_DIGITS;
2127-
let x = x as f64;
2128-
u64::from_le_bytes(x.to_le_bytes())
2129-
}
2130-
_ => unreachable!(),
2131-
}
2132-
}
2133-
// load max value need to round.
2134-
if ty == F32 {
2135-
Inst::load_fp_constant32(f_tmp, max_value_need_round(ty) as u32, &mut |_| {
2136-
writable_spilltmp_reg()
2137-
})
2138-
} else {
2139-
Inst::load_fp_constant64(f_tmp, max_value_need_round(ty), &mut |_| {
2140-
writable_spilltmp_reg()
2141-
})
2142-
}
2143-
.into_iter()
2144-
.for_each(|i| i.emit(&[], sink, emit_info, state));
2145-
2146-
// get abs value.
2147-
Inst::emit_fabs(rd, rs, ty).emit(&[], sink, emit_info, state);
2148-
2149-
// branch if f_tmp < rd
2150-
Inst::FpuRRR {
2151-
frm: FRM::RTZ,
2152-
alu_op: if ty == F32 {
2153-
FpuOPRRR::FltS
2154-
} else {
2155-
FpuOPRRR::FltD
2156-
},
2157-
rd: int_tmp,
2158-
rs1: f_tmp.to_reg(),
2159-
rs2: rd.to_reg(),
2160-
}
2161-
.emit(&[], sink, emit_info, state);
2162-
2163-
Inst::CondBr {
2164-
taken: CondBrTarget::Label(label_x),
2165-
not_taken: CondBrTarget::Fallthrough,
2166-
kind: IntegerCompare {
2167-
kind: IntCC::NotEqual,
2168-
rs1: int_tmp.to_reg(),
2169-
rs2: zero_reg(),
2170-
},
2171-
}
2172-
.emit(&[], sink, emit_info, state);
2173-
2174-
//convert to int.
2175-
Inst::FpuRR {
2176-
alu_op: FpuOPRR::float_convert_2_int_op(ty, true, I64),
2177-
frm: op.to_frm(),
2178-
rd: int_tmp,
2179-
rs: rs,
2180-
}
2181-
.emit(&[], sink, emit_info, state);
2182-
//convert back.
2183-
Inst::FpuRR {
2184-
alu_op: if ty == F32 {
2185-
FpuOPRR::FcvtSL
2186-
} else {
2187-
FpuOPRR::FcvtDL
2188-
},
2189-
frm: op.to_frm(),
2190-
rd,
2191-
rs: int_tmp.to_reg(),
2192-
}
2193-
.emit(&[], sink, emit_info, state);
2194-
// copy sign.
2195-
Inst::FpuRRR {
2196-
alu_op: if ty == F32 {
2197-
FpuOPRRR::FsgnjS
2198-
} else {
2199-
FpuOPRRR::FsgnjD
2200-
},
2201-
frm: FRM::RNE,
2202-
rd,
2203-
rs1: rd.to_reg(),
2204-
rs2: rs,
2205-
}
2206-
.emit(&[], sink, emit_info, state);
2207-
// jump over.
2208-
Inst::gen_jump(label_jump_over).emit(&[], sink, emit_info, state);
2209-
// here is nan.
2210-
sink.bind_label(label_nan, &mut state.ctrl_plane);
2211-
Inst::FpuRRR {
2212-
alu_op: if ty == F32 {
2213-
FpuOPRRR::FaddS
2214-
} else {
2215-
FpuOPRRR::FaddD
2216-
},
2217-
frm: FRM::RNE,
2218-
rd: rd,
2219-
rs1: rs,
2220-
rs2: rs,
2221-
}
2222-
.emit(&[], sink, emit_info, state);
2223-
Inst::gen_jump(label_jump_over).emit(&[], sink, emit_info, state);
2224-
// here select origin x.
2225-
sink.bind_label(label_x, &mut state.ctrl_plane);
2226-
Inst::gen_move(rd, rs, ty).emit(&[], sink, emit_info, state);
2227-
sink.bind_label(label_jump_over, &mut state.ctrl_plane);
2228-
}
22292063

22302064
&Inst::Popcnt {
22312065
sum,

0 commit comments

Comments
 (0)