3 pub fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
19 UnsignedLessThanOrEqual
25 SignedGreaterThanOrEqual
27 UnsignedGreaterThanOrEqual
41 fn codegen_compare_bin_op<'tcx>(
42 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
48 let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
49 let val = codegen_icmp(fx, intcc, lhs, rhs);
50 let val = fx.bcx.ins().bint(types::I8, val);
51 CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
54 pub fn codegen_binop<'tcx>(
55 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
61 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
62 match in_lhs.layout().ty.sty {
63 ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
64 let signed = type_sign(in_lhs.layout().ty);
65 let lhs = in_lhs.load_scalar(fx);
66 let rhs = in_rhs.load_scalar(fx);
68 let (lhs, rhs) = if (bin_op == BinOp::Eq || bin_op == BinOp::Ne)
69 && (in_lhs.layout().ty.sty == fx.tcx.types.i8.sty
70 || in_lhs.layout().ty.sty == fx.tcx.types.i16.sty)
72 // FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong.
74 fx.bcx.ins().sextend(types::I32, lhs),
75 fx.bcx.ins().sextend(types::I32, rhs),
81 return codegen_compare_bin_op(fx, bin_op, signed, lhs, rhs);
89 match in_lhs.layout().ty.sty {
90 ty::Bool => crate::num::trans_bool_binop(fx, bin_op, in_lhs, in_rhs),
91 ty::Uint(_) | ty::Int(_) => crate::num::trans_int_binop(fx, bin_op, in_lhs, in_rhs),
92 ty::Float(_) => crate::num::trans_float_binop(fx, bin_op, in_lhs, in_rhs),
93 ty::RawPtr(..) | ty::FnPtr(..) => crate::num::trans_ptr_binop(fx, bin_op, in_lhs, in_rhs),
103 pub fn trans_bool_binop<'tcx>(
104 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
106 in_lhs: CValue<'tcx>,
107 in_rhs: CValue<'tcx>,
109 let lhs = in_lhs.load_scalar(fx);
110 let rhs = in_rhs.load_scalar(fx);
112 let b = fx.bcx.ins();
113 let res = match bin_op {
114 BinOp::BitXor => b.bxor(lhs, rhs),
115 BinOp::BitAnd => b.band(lhs, rhs),
116 BinOp::BitOr => b.bor(lhs, rhs),
117 // Compare binops handles by `codegen_binop`.
118 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
121 CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
124 pub fn trans_int_binop<'tcx>(
125 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
127 in_lhs: CValue<'tcx>,
128 in_rhs: CValue<'tcx>,
130 if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
134 "int binop requires lhs and rhs of same type"
138 if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, in_lhs, in_rhs) {
142 let signed = type_sign(in_lhs.layout().ty);
144 let lhs = in_lhs.load_scalar(fx);
145 let rhs = in_rhs.load_scalar(fx);
147 let b = fx.bcx.ins();
148 let val = match bin_op {
149 BinOp::Add => b.iadd(lhs, rhs),
150 BinOp::Sub => b.isub(lhs, rhs),
151 BinOp::Mul => b.imul(lhs, rhs),
166 BinOp::BitXor => b.bxor(lhs, rhs),
167 BinOp::BitAnd => b.band(lhs, rhs),
168 BinOp::BitOr => b.bor(lhs, rhs),
170 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
171 let rhs = clif_intcast(fx, rhs, lhs_ty, false);
172 fx.bcx.ins().ishl(lhs, rhs)
175 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
176 let rhs = clif_intcast(fx, rhs, lhs_ty, false);
178 fx.bcx.ins().sshr(lhs, rhs)
180 fx.bcx.ins().ushr(lhs, rhs)
183 // Compare binops handles by `codegen_binop`.
192 CValue::by_val(val, in_lhs.layout())
195 pub fn trans_checked_int_binop<'tcx>(
196 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
198 in_lhs: CValue<'tcx>,
199 in_rhs: CValue<'tcx>,
201 if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
205 "checked int binop requires lhs and rhs of same type"
209 let lhs = in_lhs.load_scalar(fx);
210 let rhs = in_rhs.load_scalar(fx);
212 if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs) {
216 let signed = type_sign(in_lhs.layout().ty);
218 let (res, has_overflow) = match bin_op {
220 /*let (val, c_out) = fx.bcx.ins().iadd_cout(lhs, rhs);
222 // FIXME(CraneStation/cranelift#849) legalize iadd_cout for i8 and i16
223 let val = fx.bcx.ins().iadd(lhs, rhs);
224 let has_overflow = if !signed {
225 fx.bcx.ins().icmp(IntCC::UnsignedLessThan, val, lhs)
227 let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
228 let slt = fx.bcx.ins().icmp(IntCC::SignedLessThan, val, lhs);
229 fx.bcx.ins().bxor(rhs_is_negative, slt)
234 /*let (val, b_out) = fx.bcx.ins().isub_bout(lhs, rhs);
236 // FIXME(CraneStation/cranelift#849) legalize isub_bout for i8 and i16
237 let val = fx.bcx.ins().isub(lhs, rhs);
238 let has_overflow = if !signed {
239 fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, val, lhs)
241 let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
242 let sgt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, val, lhs);
243 fx.bcx.ins().bxor(rhs_is_negative, sgt)
248 let val = fx.bcx.ins().imul(lhs, rhs);
249 /*let val_hi = if !signed {
250 fx.bcx.ins().umulhi(lhs, rhs)
252 fx.bcx.ins().smulhi(lhs, rhs)
254 let has_overflow = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);*/
255 // TODO: check for overflow
256 let has_overflow = fx.bcx.ins().bconst(types::B1, false);
260 let val = fx.bcx.ins().ishl(lhs, rhs);
261 // TODO: check for overflow
262 let has_overflow = fx.bcx.ins().bconst(types::B1, false);
266 let val = if !signed {
267 fx.bcx.ins().ushr(lhs, rhs)
269 fx.bcx.ins().sshr(lhs, rhs)
271 // TODO: check for overflow
272 let has_overflow = fx.bcx.ins().bconst(types::B1, false);
276 "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
283 let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
284 let out_place = CPlace::new_stack_slot(
287 .mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()),
289 let out_layout = out_place.layout();
290 out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));
292 out_place.to_cvalue(fx)
295 pub fn trans_float_binop<'tcx>(
296 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
298 in_lhs: CValue<'tcx>,
299 in_rhs: CValue<'tcx>,
301 assert_eq!(in_lhs.layout().ty, in_rhs.layout().ty);
303 let lhs = in_lhs.load_scalar(fx);
304 let rhs = in_rhs.load_scalar(fx);
306 let b = fx.bcx.ins();
307 let res = match bin_op {
308 BinOp::Add => b.fadd(lhs, rhs),
309 BinOp::Sub => b.fsub(lhs, rhs),
310 BinOp::Mul => b.fmul(lhs, rhs),
311 BinOp::Div => b.fdiv(lhs, rhs),
313 let name = match in_lhs.layout().ty.sty {
314 ty::Float(FloatTy::F32) => "fmodf",
315 ty::Float(FloatTy::F64) => "fmod",
318 return fx.easy_call(name, &[in_lhs, in_rhs], in_lhs.layout().ty);
320 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
321 let fltcc = match bin_op {
322 BinOp::Eq => FloatCC::Equal,
323 BinOp::Lt => FloatCC::LessThan,
324 BinOp::Le => FloatCC::LessThanOrEqual,
325 BinOp::Ne => FloatCC::NotEqual,
326 BinOp::Ge => FloatCC::GreaterThanOrEqual,
327 BinOp::Gt => FloatCC::GreaterThan,
330 let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
331 let val = fx.bcx.ins().bint(types::I8, val);
332 return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
334 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
337 CValue::by_val(res, in_lhs.layout())
340 pub fn trans_ptr_binop<'tcx>(
341 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
343 in_lhs: CValue<'tcx>,
344 in_rhs: CValue<'tcx>,
346 let not_fat = match in_lhs.layout().ty.sty {
347 ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => {
348 ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all())
350 ty::FnPtr(..) => true,
351 _ => bug!("trans_ptr_binop on non ptr"),
355 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
356 let lhs = in_lhs.load_scalar(fx);
357 let rhs = in_rhs.load_scalar(fx);
359 return codegen_compare_bin_op(fx, bin_op, false, lhs, rhs);
362 let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
363 let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
364 let pointee_size = fx.layout_of(pointee_ty).size.bytes();
365 let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
366 let base_val = base.load_scalar(fx);
367 let res = fx.bcx.ins().iadd(base_val, ptr_diff);
368 return CValue::by_val(res, base.layout());
370 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
373 let (lhs_ptr, lhs_extra) = in_lhs.load_scalar_pair(fx);
374 let (rhs_ptr, rhs_extra) = in_rhs.load_scalar_pair(fx);
376 let res = match bin_op {
378 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
379 let extra_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_extra, rhs_extra);
380 fx.bcx.ins().band(ptr_eq, extra_eq)
383 let ptr_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_ptr, rhs_ptr);
384 let extra_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_extra, rhs_extra);
385 fx.bcx.ins().bor(ptr_ne, extra_ne)
387 BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
388 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
393 .icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
394 let extra_cmp = fx.bcx.ins().icmp(
395 bin_op_to_intcc(bin_op, false).unwrap(),
400 fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
402 _ => panic!("bin_op {:?} on ptr", bin_op),
406 fx.bcx.ins().bint(types::I8, res),
407 fx.layout_of(fx.tcx.types.bool),