1use crate::cursor::{Cursor, FuncCursor};
7use crate::divconst_magic_numbers::{magic_s32, magic_s64, magic_u32, magic_u64};
8use crate::divconst_magic_numbers::{MS32, MS64, MU32, MU64};
9use crate::ir::{
10 condcodes::IntCC,
11 instructions::Opcode,
12 types::{I128, I32, I64},
13 DataFlowGraph, Function, Inst, InstBuilder, InstructionData, Type, Value,
14};
15use crate::isa::TargetIsa;
16use crate::timing;
17
18#[inline]
19fn replace_single_result_with_alias(dfg: &mut DataFlowGraph, inst: Inst, value: Value) {
23 let results = dfg.detach_results(inst);
25 debug_assert!(results.len(&dfg.value_lists) == 1);
26 let result = results.get(0, &dfg.value_lists).unwrap();
27 dfg.change_to_alias(result, value);
28
29 dfg.replace(inst).nop();
31}
32
33#[inline]
42fn i32_is_power_of_two(x: i32) -> Option<(bool, u32)> {
43 if x == -0x8000_0000 {
45 return Some((true, 31));
46 }
47 let abs_x = i32::wrapping_abs(x) as u32;
48 if abs_x.is_power_of_two() {
49 return Some((x < 0, abs_x.trailing_zeros()));
50 }
51 None
52}
53
54#[inline]
56fn i64_is_power_of_two(x: i64) -> Option<(bool, u32)> {
57 if x == -0x8000_0000_0000_0000 {
59 return Some((true, 63));
60 }
61 let abs_x = i64::wrapping_abs(x) as u64;
62 if abs_x.is_power_of_two() {
63 return Some((x < 0, abs_x.trailing_zeros()));
64 }
65 None
66}
67
68#[derive(Debug)]
71enum DivRemByConstInfo {
72 DivU32(Value, u32),
73 DivU64(Value, u64),
74 DivS32(Value, i32),
75 DivS64(Value, i64),
76 RemU32(Value, u32),
77 RemU64(Value, u64),
78 RemS32(Value, i32),
79 RemS64(Value, i64),
80}
81
82fn package_up_divrem_info(
85 value: Value,
86 value_type: Type,
87 imm_i64: i64,
88 is_signed: bool,
89 is_rem: bool,
90) -> Option<DivRemByConstInfo> {
91 let imm_u64 = imm_i64 as u64;
92
93 match (is_signed, value_type) {
94 (false, I32) => {
95 if imm_u64 < 0x1_0000_0000 {
96 if is_rem {
97 Some(DivRemByConstInfo::RemU32(value, imm_u64 as u32))
98 } else {
99 Some(DivRemByConstInfo::DivU32(value, imm_u64 as u32))
100 }
101 } else {
102 None
103 }
104 }
105
106 (false, I64) => {
107 if is_rem {
109 Some(DivRemByConstInfo::RemU64(value, imm_u64))
110 } else {
111 Some(DivRemByConstInfo::DivU64(value, imm_u64))
112 }
113 }
114
115 (true, I32) => {
116 if imm_u64 <= 0x7fff_ffff || imm_u64 >= 0xffff_ffff_8000_0000 {
117 if is_rem {
118 Some(DivRemByConstInfo::RemS32(value, imm_u64 as i32))
119 } else {
120 Some(DivRemByConstInfo::DivS32(value, imm_u64 as i32))
121 }
122 } else {
123 None
124 }
125 }
126
127 (true, I64) => {
128 if is_rem {
130 Some(DivRemByConstInfo::RemS64(value, imm_u64 as i64))
131 } else {
132 Some(DivRemByConstInfo::DivS64(value, imm_u64 as i64))
133 }
134 }
135
136 _ => None,
137 }
138}
139
140fn get_div_info(inst: Inst, dfg: &DataFlowGraph) -> Option<DivRemByConstInfo> {
143 if let InstructionData::BinaryImm64 { opcode, arg, imm } = dfg.insts[inst] {
144 let (is_signed, is_rem) = match opcode {
145 Opcode::UdivImm => (false, false),
146 Opcode::UremImm => (false, true),
147 Opcode::SdivImm => (true, false),
148 Opcode::SremImm => (true, true),
149 _ => return None,
150 };
151 return package_up_divrem_info(arg, dfg.value_type(arg), imm.into(), is_signed, is_rem);
152 }
153
154 None
155}
156
157fn do_divrem_transformation(divrem_info: &DivRemByConstInfo, pos: &mut FuncCursor, inst: Inst) {
163 let is_rem = match *divrem_info {
164 DivRemByConstInfo::DivU32(_, _)
165 | DivRemByConstInfo::DivU64(_, _)
166 | DivRemByConstInfo::DivS32(_, _)
167 | DivRemByConstInfo::DivS64(_, _) => false,
168 DivRemByConstInfo::RemU32(_, _)
169 | DivRemByConstInfo::RemU64(_, _)
170 | DivRemByConstInfo::RemS32(_, _)
171 | DivRemByConstInfo::RemS64(_, _) => true,
172 };
173
174 match *divrem_info {
175 DivRemByConstInfo::DivU32(_n1, 0) | DivRemByConstInfo::RemU32(_n1, 0) => {}
179
180 DivRemByConstInfo::DivU32(n1, 1) | DivRemByConstInfo::RemU32(n1, 1) => {
183 if is_rem {
184 pos.func.dfg.replace(inst).iconst(I32, 0);
185 } else {
186 replace_single_result_with_alias(&mut pos.func.dfg, inst, n1);
187 }
188 }
189
190 DivRemByConstInfo::DivU32(n1, d) | DivRemByConstInfo::RemU32(n1, d)
192 if d.is_power_of_two() =>
193 {
194 debug_assert!(d >= 2);
195 let k = d.trailing_zeros();
197 debug_assert!(k >= 1 && k <= 31);
198 if is_rem {
199 let mask = (1u64 << k) - 1;
200 pos.func.dfg.replace(inst).band_imm(n1, mask as i64);
201 } else {
202 pos.func.dfg.replace(inst).ushr_imm(n1, k as i64);
203 }
204 }
205
206 DivRemByConstInfo::DivU32(n1, d) | DivRemByConstInfo::RemU32(n1, d) => {
208 debug_assert!(d >= 3);
209 let MU32 {
210 mul_by,
211 do_add,
212 shift_by,
213 } = magic_u32(d);
214 let qf; let q0 = pos.ins().iconst(I32, mul_by as i64);
216 let q1 = pos.ins().umulhi(n1, q0);
217 if do_add {
218 debug_assert!(shift_by >= 1 && shift_by <= 32);
219 let t1 = pos.ins().isub(n1, q1);
220 let t2 = pos.ins().ushr_imm(t1, 1);
221 let t3 = pos.ins().iadd(t2, q1);
222 debug_assert_ne!(shift_by, 1);
225 qf = pos.ins().ushr_imm(t3, (shift_by - 1) as i64);
226 } else {
227 debug_assert!(shift_by >= 0 && shift_by <= 31);
228 if shift_by > 0 {
230 qf = pos.ins().ushr_imm(q1, shift_by as i64);
231 } else {
232 qf = q1;
233 }
234 }
235 if is_rem {
238 let tt = pos.ins().imul_imm(qf, d as i64);
239 pos.func.dfg.replace(inst).isub(n1, tt);
240 } else {
241 replace_single_result_with_alias(&mut pos.func.dfg, inst, qf);
242 }
243 }
244
245 DivRemByConstInfo::DivU64(_n1, 0) | DivRemByConstInfo::RemU64(_n1, 0) => {}
249
250 DivRemByConstInfo::DivU64(n1, 1) | DivRemByConstInfo::RemU64(n1, 1) => {
253 if is_rem {
254 pos.func.dfg.replace(inst).iconst(I64, 0);
255 } else {
256 replace_single_result_with_alias(&mut pos.func.dfg, inst, n1);
257 }
258 }
259
260 DivRemByConstInfo::DivU64(n1, d) | DivRemByConstInfo::RemU64(n1, d)
262 if d.is_power_of_two() =>
263 {
264 debug_assert!(d >= 2);
265 let k = d.trailing_zeros();
267 debug_assert!(k >= 1 && k <= 63);
268 if is_rem {
269 let mask = (1u64 << k) - 1;
270 pos.func.dfg.replace(inst).band_imm(n1, mask as i64);
271 } else {
272 pos.func.dfg.replace(inst).ushr_imm(n1, k as i64);
273 }
274 }
275
276 DivRemByConstInfo::DivU64(n1, d) | DivRemByConstInfo::RemU64(n1, d) => {
278 debug_assert!(d >= 3);
279 let MU64 {
280 mul_by,
281 do_add,
282 shift_by,
283 } = magic_u64(d);
284 let qf; let q0 = pos.ins().iconst(I64, mul_by as i64);
286 let q1 = pos.ins().umulhi(n1, q0);
287 if do_add {
288 debug_assert!(shift_by >= 1 && shift_by <= 64);
289 let t1 = pos.ins().isub(n1, q1);
290 let t2 = pos.ins().ushr_imm(t1, 1);
291 let t3 = pos.ins().iadd(t2, q1);
292 debug_assert_ne!(shift_by, 1);
295 qf = pos.ins().ushr_imm(t3, (shift_by - 1) as i64);
296 } else {
297 debug_assert!(shift_by >= 0 && shift_by <= 63);
298 if shift_by > 0 {
300 qf = pos.ins().ushr_imm(q1, shift_by as i64);
301 } else {
302 qf = q1;
303 }
304 }
305 if is_rem {
308 let tt = pos.ins().imul_imm(qf, d as i64);
309 pos.func.dfg.replace(inst).isub(n1, tt);
310 } else {
311 replace_single_result_with_alias(&mut pos.func.dfg, inst, qf);
312 }
313 }
314
315 DivRemByConstInfo::DivS32(_n1, -1)
319 | DivRemByConstInfo::RemS32(_n1, -1)
320 | DivRemByConstInfo::DivS32(_n1, 0)
321 | DivRemByConstInfo::RemS32(_n1, 0) => {}
322
323 DivRemByConstInfo::DivS32(n1, 1) | DivRemByConstInfo::RemS32(n1, 1) => {
326 if is_rem {
327 pos.func.dfg.replace(inst).iconst(I32, 0);
328 } else {
329 replace_single_result_with_alias(&mut pos.func.dfg, inst, n1);
330 }
331 }
332
333 DivRemByConstInfo::DivS32(n1, d) | DivRemByConstInfo::RemS32(n1, d) => {
334 if let Some((is_negative, k)) = i32_is_power_of_two(d) {
335 debug_assert!(k >= 1 && k <= 31);
337 let t1 = if k - 1 == 0 {
338 n1
339 } else {
340 pos.ins().sshr_imm(n1, (k - 1) as i64)
341 };
342 let t2 = pos.ins().ushr_imm(t1, (32 - k) as i64);
343 let t3 = pos.ins().iadd(n1, t2);
344 if is_rem {
345 let t4 = pos.ins().band_imm(t3, i32::wrapping_neg(1 << k) as i64);
347 pos.func.dfg.replace(inst).isub(n1, t4);
349 } else {
350 let t4 = pos.ins().sshr_imm(t3, k as i64);
352 if is_negative {
353 pos.func.dfg.replace(inst).irsub_imm(t4, 0);
354 } else {
355 replace_single_result_with_alias(&mut pos.func.dfg, inst, t4);
356 }
357 }
358 } else {
359 debug_assert!(d < -2 || d > 2);
361 let MS32 { mul_by, shift_by } = magic_s32(d);
362 let q0 = pos.ins().iconst(I32, mul_by as i64);
363 let q1 = pos.ins().smulhi(n1, q0);
364 let q2 = if d > 0 && mul_by < 0 {
365 pos.ins().iadd(q1, n1)
366 } else if d < 0 && mul_by > 0 {
367 pos.ins().isub(q1, n1)
368 } else {
369 q1
370 };
371 debug_assert!(shift_by >= 0 && shift_by <= 31);
372 let q3 = if shift_by == 0 {
373 q2
374 } else {
375 pos.ins().sshr_imm(q2, shift_by as i64)
376 };
377 let t1 = pos.ins().ushr_imm(q3, 31);
378 let qf = pos.ins().iadd(q3, t1);
379 if is_rem {
382 let tt = pos.ins().imul_imm(qf, d as i64);
383 pos.func.dfg.replace(inst).isub(n1, tt);
384 } else {
385 replace_single_result_with_alias(&mut pos.func.dfg, inst, qf);
386 }
387 }
388 }
389
390 DivRemByConstInfo::DivS64(_n1, -1)
394 | DivRemByConstInfo::RemS64(_n1, -1)
395 | DivRemByConstInfo::DivS64(_n1, 0)
396 | DivRemByConstInfo::RemS64(_n1, 0) => {}
397
398 DivRemByConstInfo::DivS64(n1, 1) | DivRemByConstInfo::RemS64(n1, 1) => {
401 if is_rem {
402 pos.func.dfg.replace(inst).iconst(I64, 0);
403 } else {
404 replace_single_result_with_alias(&mut pos.func.dfg, inst, n1);
405 }
406 }
407
408 DivRemByConstInfo::DivS64(n1, d) | DivRemByConstInfo::RemS64(n1, d) => {
409 if let Some((is_negative, k)) = i64_is_power_of_two(d) {
410 debug_assert!(k >= 1 && k <= 63);
412 let t1 = if k - 1 == 0 {
413 n1
414 } else {
415 pos.ins().sshr_imm(n1, (k - 1) as i64)
416 };
417 let t2 = pos.ins().ushr_imm(t1, (64 - k) as i64);
418 let t3 = pos.ins().iadd(n1, t2);
419 if is_rem {
420 let t4 = pos.ins().band_imm(t3, i64::wrapping_neg(1 << k));
422 pos.func.dfg.replace(inst).isub(n1, t4);
424 } else {
425 let t4 = pos.ins().sshr_imm(t3, k as i64);
427 if is_negative {
428 pos.func.dfg.replace(inst).irsub_imm(t4, 0);
429 } else {
430 replace_single_result_with_alias(&mut pos.func.dfg, inst, t4);
431 }
432 }
433 } else {
434 debug_assert!(d < -2 || d > 2);
436 let MS64 { mul_by, shift_by } = magic_s64(d);
437 let q0 = pos.ins().iconst(I64, mul_by);
438 let q1 = pos.ins().smulhi(n1, q0);
439 let q2 = if d > 0 && mul_by < 0 {
440 pos.ins().iadd(q1, n1)
441 } else if d < 0 && mul_by > 0 {
442 pos.ins().isub(q1, n1)
443 } else {
444 q1
445 };
446 debug_assert!(shift_by >= 0 && shift_by <= 63);
447 let q3 = if shift_by == 0 {
448 q2
449 } else {
450 pos.ins().sshr_imm(q2, shift_by as i64)
451 };
452 let t1 = pos.ins().ushr_imm(q3, 63);
453 let qf = pos.ins().iadd(q3, t1);
454 if is_rem {
457 let tt = pos.ins().imul_imm(qf, d);
458 pos.func.dfg.replace(inst).isub(n1, tt);
459 } else {
460 replace_single_result_with_alias(&mut pos.func.dfg, inst, qf);
461 }
462 }
463 }
464 }
465}
466
467mod simplify {
468 use super::*;
469 use crate::ir::{
470 dfg::ValueDef,
471 immediates,
472 instructions::Opcode,
473 types::{I16, I32, I8},
474 };
475 use std::marker::PhantomData;
476
477 pub struct PeepholeOptimizer<'a, 'b> {
478 phantom: PhantomData<(&'a (), &'b ())>,
479 }
480
481 pub fn peephole_optimizer<'a, 'b>(_: &dyn TargetIsa) -> PeepholeOptimizer<'a, 'b> {
482 PeepholeOptimizer {
483 phantom: PhantomData,
484 }
485 }
486
487 pub fn apply_all<'a, 'b>(
488 _optimizer: &mut PeepholeOptimizer<'a, 'b>,
489 pos: &mut FuncCursor<'a>,
490 inst: Inst,
491 native_word_width: u32,
492 ) {
493 simplify(pos, inst, native_word_width);
494 branch_opt(pos, inst);
495 }
496
497 #[inline]
498 fn resolve_imm64_value(dfg: &DataFlowGraph, value: Value) -> Option<immediates::Imm64> {
499 if let ValueDef::Result(candidate_inst, _) = dfg.value_def(value) {
500 if let InstructionData::UnaryImm {
501 opcode: Opcode::Iconst,
502 imm,
503 } = dfg.insts[candidate_inst]
504 {
505 return Some(imm);
506 }
507 }
508 None
509 }
510
511 fn try_fold_extended_move(
514 pos: &mut FuncCursor,
515 inst: Inst,
516 opcode: Opcode,
517 arg: Value,
518 imm: immediates::Imm64,
519 ) -> bool {
520 if let ValueDef::Result(arg_inst, _) = pos.func.dfg.value_def(arg) {
521 if let InstructionData::BinaryImm64 {
522 opcode: Opcode::IshlImm,
523 arg: prev_arg,
524 imm: prev_imm,
525 } = &pos.func.dfg.insts[arg_inst]
526 {
527 if imm != *prev_imm {
528 return false;
529 }
530
531 let dest_ty = pos.func.dfg.ctrl_typevar(inst);
532 if dest_ty != pos.func.dfg.ctrl_typevar(arg_inst) || !dest_ty.is_int() {
533 return false;
534 }
535
536 let imm_bits: i64 = imm.into();
537 let ireduce_ty = match (dest_ty.lane_bits() as i64).wrapping_sub(imm_bits) {
538 8 => I8,
539 16 => I16,
540 32 => I32,
541 _ => return false,
542 };
543 let ireduce_ty = ireduce_ty.by(dest_ty.lane_count()).unwrap();
544
545 let arg = *prev_arg;
548 let narrower_arg = pos.ins().ireduce(ireduce_ty, arg);
549
550 if opcode == Opcode::UshrImm {
551 pos.func.dfg.replace(inst).uextend(dest_ty, narrower_arg);
552 } else {
553 pos.func.dfg.replace(inst).sextend(dest_ty, narrower_arg);
554 }
555 return true;
556 }
557 }
558 false
559 }
560
561 fn simplify(pos: &mut FuncCursor, inst: Inst, native_word_width: u32) {
571 match pos.func.dfg.insts[inst] {
572 InstructionData::Binary { opcode, args } => {
573 if let Some(mut imm) = resolve_imm64_value(&pos.func.dfg, args[1]) {
574 let new_opcode = match opcode {
575 Opcode::Iadd => Opcode::IaddImm,
576 Opcode::Imul => Opcode::ImulImm,
577 Opcode::Sdiv => Opcode::SdivImm,
578 Opcode::Udiv => Opcode::UdivImm,
579 Opcode::Srem => Opcode::SremImm,
580 Opcode::Urem => Opcode::UremImm,
581 Opcode::Band => Opcode::BandImm,
582 Opcode::Bor => Opcode::BorImm,
583 Opcode::Bxor => Opcode::BxorImm,
584 Opcode::Rotl => Opcode::RotlImm,
585 Opcode::Rotr => Opcode::RotrImm,
586 Opcode::Ishl => Opcode::IshlImm,
587 Opcode::Ushr => Opcode::UshrImm,
588 Opcode::Sshr => Opcode::SshrImm,
589 Opcode::Isub => {
590 imm = imm.wrapping_neg();
591 Opcode::IaddImm
592 }
593 _ => return,
594 };
595 let ty = pos.func.dfg.ctrl_typevar(inst);
596 if ty.bytes() <= native_word_width {
597 pos.func
598 .dfg
599 .replace(inst)
600 .BinaryImm64(new_opcode, ty, imm, args[0]);
601
602 simplify(pos, inst, native_word_width);
604 }
605 } else if let Some(imm) = resolve_imm64_value(&pos.func.dfg, args[0]) {
606 let new_opcode = match opcode {
607 Opcode::Iadd => Opcode::IaddImm,
608 Opcode::Imul => Opcode::ImulImm,
609 Opcode::Band => Opcode::BandImm,
610 Opcode::Bor => Opcode::BorImm,
611 Opcode::Bxor => Opcode::BxorImm,
612 Opcode::Isub => Opcode::IrsubImm,
613 _ => return,
614 };
615 let ty = pos.func.dfg.ctrl_typevar(inst);
616 if ty.bytes() <= native_word_width {
617 pos.func
618 .dfg
619 .replace(inst)
620 .BinaryImm64(new_opcode, ty, imm, args[1]);
621 }
622 }
623 }
624
625 InstructionData::BinaryImm64 { opcode, arg, imm } => {
626 let ty = pos.func.dfg.ctrl_typevar(inst);
627
628 let mut arg = arg;
629 let mut imm = imm;
630 match opcode {
631 Opcode::IaddImm
632 | Opcode::ImulImm
633 | Opcode::BorImm
634 | Opcode::BandImm
635 | Opcode::BxorImm => {
636 if let ValueDef::Result(arg_inst, _) = pos.func.dfg.value_def(arg) {
638 if let InstructionData::BinaryImm64 {
639 opcode: prev_opcode,
640 arg: prev_arg,
641 imm: prev_imm,
642 } = &pos.func.dfg.insts[arg_inst]
643 {
644 if opcode == *prev_opcode
645 && ty == pos.func.dfg.ctrl_typevar(arg_inst)
646 {
647 let lhs: i64 = imm.into();
648 let rhs: i64 = (*prev_imm).into();
649 let new_imm = match opcode {
650 Opcode::BorImm => lhs | rhs,
651 Opcode::BandImm => lhs & rhs,
652 Opcode::BxorImm => lhs ^ rhs,
653 Opcode::IaddImm => lhs.wrapping_add(rhs),
654 Opcode::ImulImm => lhs.wrapping_mul(rhs),
655 _ => panic!("can't happen"),
656 };
657 let new_imm = immediates::Imm64::from(new_imm);
658 let new_arg = *prev_arg;
659 pos.func
660 .dfg
661 .replace(inst)
662 .BinaryImm64(opcode, ty, new_imm, new_arg);
663 imm = new_imm;
664 arg = new_arg;
665 }
666 }
667 }
668 }
669
670 Opcode::UshrImm | Opcode::SshrImm => {
671 if pos.func.dfg.ctrl_typevar(inst).bytes() <= native_word_width
672 && try_fold_extended_move(pos, inst, opcode, arg, imm)
673 {
674 return;
675 }
676 }
677
678 _ => {}
679 };
680
681 match (opcode, imm.into(), ty) {
683 (Opcode::IaddImm, 0, _)
684 | (Opcode::ImulImm, 1, _)
685 | (Opcode::SdivImm, 1, _)
686 | (Opcode::UdivImm, 1, _)
687 | (Opcode::BorImm, 0, _)
688 | (Opcode::BandImm, -1, _)
689 | (Opcode::BxorImm, 0, _)
690 | (Opcode::RotlImm, 0, _)
691 | (Opcode::RotrImm, 0, _)
692 | (Opcode::IshlImm, 0, _)
693 | (Opcode::UshrImm, 0, _)
694 | (Opcode::SshrImm, 0, _) => {
695 replace_single_result_with_alias(&mut pos.func.dfg, inst, arg);
697 }
698 (Opcode::ImulImm, 0, ty) | (Opcode::BandImm, 0, ty) if ty != I128 => {
699 pos.func.dfg.replace(inst).iconst(ty, 0);
701 }
702 (Opcode::BorImm, -1, ty) if ty != I128 => {
703 pos.func.dfg.replace(inst).iconst(ty, -1);
705 }
706 _ => {}
707 }
708 }
709
710 InstructionData::IntCompare { opcode, cond, args } => {
711 debug_assert_eq!(opcode, Opcode::Icmp);
712 if let Some(imm) = resolve_imm64_value(&pos.func.dfg, args[1]) {
713 if pos.func.dfg.ctrl_typevar(inst).bytes() <= native_word_width {
714 pos.func.dfg.replace(inst).icmp_imm(cond, args[0], imm);
715 }
716 }
717 }
718
719 _ => {}
720 }
721 }
722
723 fn branch_opt(pos: &mut FuncCursor, inst: Inst) {
728 let (cmp_arg, new_then, new_else) = if let InstructionData::Brif {
729 arg: first_arg,
730 blocks: [block_then, block_else],
731 ..
732 } = pos.func.dfg.insts[inst]
733 {
734 let icmp_inst =
735 if let ValueDef::Result(icmp_inst, _) = pos.func.dfg.value_def(first_arg) {
736 icmp_inst
737 } else {
738 return;
739 };
740
741 if let InstructionData::IntCompareImm {
742 opcode: Opcode::IcmpImm,
743 arg: cmp_arg,
744 cond: cmp_cond,
745 imm: cmp_imm,
746 } = pos.func.dfg.insts[icmp_inst]
747 {
748 let cmp_imm: i64 = cmp_imm.into();
749 if cmp_imm != 0 {
750 return;
751 }
752
753 let (new_then, new_else) = match cmp_cond {
754 IntCC::Equal => (block_else, block_then),
755 IntCC::NotEqual => (block_then, block_else),
756 _ => return,
757 };
758
759 (cmp_arg, new_then, new_else)
760 } else {
761 return;
762 }
763 } else {
764 return;
765 };
766
767 if let InstructionData::Brif { arg, blocks, .. } = &mut pos.func.dfg.insts[inst] {
768 *arg = cmp_arg;
769 blocks[0] = new_then;
770 blocks[1] = new_else;
771 } else {
772 unreachable!();
773 }
774 }
775}
776
777pub fn do_preopt(func: &mut Function, isa: &dyn TargetIsa) {
779 let _tt = timing::preopt();
780
781 let mut pos = FuncCursor::new(func);
782 let native_word_width = isa.pointer_bytes() as u32;
783 let mut optimizer = simplify::peephole_optimizer(isa);
784
785 while let Some(_) = pos.next_block() {
786 while let Some(inst) = pos.next_inst() {
787 simplify::apply_all(&mut optimizer, &mut pos, inst, native_word_width);
788
789 if let Some(divrem_info) = get_div_info(inst, &pos.func.dfg) {
791 do_divrem_transformation(&divrem_info, &mut pos, inst);
792 continue;
793 }
794 }
795 }
796}