1 //! Glue for working with `peepmatic`-generated peephole optimizers.
2 
3 use crate::cursor::{Cursor, FuncCursor};
4 use crate::ir::{
5     dfg::DataFlowGraph,
6     entities::{Inst, Value},
7     immediates::{Imm64, Uimm64},
8     instructions::{InstructionData, Opcode},
9     types, InstBuilder,
10 };
11 use crate::isa::TargetIsa;
12 use cranelift_codegen_shared::condcodes::IntCC;
13 use peepmatic_runtime::{
14     cc::ConditionCode,
15     instruction_set::InstructionSet,
16     part::{Constant, Part},
17     r#type::{BitWidth, Kind, Type},
18     PeepholeOptimizations, PeepholeOptimizer,
19 };
20 use std::borrow::Cow;
21 use std::boxed::Box;
22 use std::convert::{TryFrom, TryInto};
23 use std::iter;
24 use std::ptr;
25 use std::sync::atomic::{AtomicPtr, Ordering};
26 
27 peepmatic_traits::define_parse_and_typing_rules_for_operator! {
28     Opcode {
29         adjust_sp_down => AdjustSpDown {
30             parameters(iNN);
31             result(void);
32         }
33         adjust_sp_down_imm => AdjustSpDownImm {
34             immediates(iNN);
35             result(void);
36         }
37         band => Band {
38             parameters(iNN, iNN);
39             result(iNN);
40         }
41         band_imm => BandImm {
42             immediates(iNN);
43             parameters(iNN);
44             result(iNN);
45         }
46         bconst => Bconst {
47             immediates(b1);
48             result(bNN);
49         }
50         bint => Bint {
51             parameters(bNN);
52             result(iNN);
53         }
54         bor => Bor {
55             parameters(iNN, iNN);
56             result(iNN);
57         }
58         bor_imm => BorImm {
59             immediates(iNN);
60             parameters(iNN);
61             result(iNN);
62         }
63         brnz => Brnz {
64             parameters(bool_or_int);
65             result(void);
66         }
67         brz => Brz {
68             parameters(bool_or_int);
69             result(void);
70         }
71         bxor => Bxor {
72             parameters(iNN, iNN);
73             result(iNN);
74         }
75         bxor_imm => BxorImm {
76             immediates(iNN);
77             parameters(iNN);
78             result(iNN);
79         }
80         iadd => Iadd {
81             parameters(iNN, iNN);
82             result(iNN);
83         }
84         iadd_imm => IaddImm {
85             immediates(iNN);
86             parameters(iNN);
87             result(iNN);
88         }
89         icmp => Icmp {
90             immediates(cc);
91             parameters(iNN, iNN);
92             result(b1);
93         }
94         icmp_imm => IcmpImm {
95             immediates(cc, iNN);
96             parameters(iNN);
97             result(b1);
98         }
99         iconst => Iconst {
100             immediates(iNN);
101             result(iNN);
102         }
103         ifcmp => Ifcmp {
104             parameters(iNN, iNN);
105             result(cpu_flags);
106         }
107         ifcmp_imm => IfcmpImm {
108             immediates(iNN);
109             parameters(iNN);
110             result(cpu_flags);
111         }
112         imul => Imul {
113             parameters(iNN, iNN);
114             result(iNN);
115         }
116         imul_imm => ImulImm {
117             immediates(iNN);
118             parameters(iNN);
119             result(iNN);
120         }
121         ireduce => Ireduce {
122             parameters(iNN);
123             result(iMM);
124             is_reduce(true);
125         }
126         irsub_imm => IrsubImm {
127             immediates(iNN);
128             parameters(iNN);
129             result(iNN);
130         }
131         ishl => Ishl {
132             parameters(iNN, iNN);
133             result(iNN);
134         }
135         ishl_imm => IshlImm {
136             immediates(iNN);
137             parameters(iNN);
138             result(iNN);
139         }
140         isub => Isub {
141             parameters(iNN, iNN);
142             result(iNN);
143         }
144         rotl => Rotl {
145             parameters(iNN, iNN);
146             result(iNN);
147         }
148         rotl_imm => RotlImm {
149             immediates(iNN);
150             parameters(iNN);
151             result(iNN);
152         }
153         rotr => Rotr {
154             parameters(iNN, iNN);
155             result(iNN);
156         }
157         rotr_imm => RotrImm {
158             immediates(iNN);
159             parameters(iNN);
160             result(iNN);
161         }
162         sdiv => Sdiv {
163             parameters(iNN, iNN);
164             result(iNN);
165         }
166         sdiv_imm => SdivImm {
167             immediates(iNN);
168             parameters(iNN);
169             result(iNN);
170         }
171         select => Select {
172             parameters(bool_or_int, any_t, any_t);
173             result(any_t);
174         }
175         sextend => Sextend {
176             parameters(iNN);
177             result(iMM);
178             is_extend(true);
179         }
180         srem => Srem {
181             parameters(iNN, iNN);
182             result(iNN);
183         }
184         srem_imm => SremImm {
185             immediates(iNN);
186             parameters(iNN);
187             result(iNN);
188         }
189         sshr => Sshr {
190             parameters(iNN, iNN);
191             result(iNN);
192         }
193         sshr_imm => SshrImm {
194             immediates(iNN);
195             parameters(iNN);
196             result(iNN);
197         }
198         trapnz => Trapnz {
199             parameters(bool_or_int);
200             result(void);
201         }
202         trapz => Trapz {
203             parameters(bool_or_int);
204             result(void);
205         }
206         udiv => Udiv {
207             parameters(iNN, iNN);
208             result(iNN);
209         }
210         udiv_imm => UdivImm {
211             immediates(iNN);
212             parameters(iNN);
213             result(iNN);
214         }
215         uextend => Uextend {
216             parameters(iNN);
217             result(iMM);
218             is_extend(true);
219         }
220         urem => Urem {
221             parameters(iNN, iNN);
222             result(iNN);
223         }
224         urem_imm => UremImm {
225             immediates(iNN);
226             parameters(iNN);
227             result(iNN);
228         }
229         ushr => Ushr {
230             parameters(iNN, iNN);
231             result(iNN);
232         }
233         ushr_imm => UshrImm {
234             immediates(iNN);
235             parameters(iNN);
236             result(iNN);
237         }
238     }
239     parse_cfg(feature = "rebuild-peephole-optimizers");
240 }
241 
242 /// Code required to rebuild Peepmatic-based peephole optimizers.
243 ///
244 /// This module is used to scope imports and dependencies that are only required
245 /// for building peephole optimizers (as opposed to just using pre-built
246 /// peephole optimizers). This helps ensure that our regular builds using
247 /// pre-built peephole optimizers stay lean.
248 #[cfg(feature = "rebuild-peephole-optimizers")]
249 mod rebuild {
250     use super::*;
251     use alloc::vec::Vec;
252     use std::fs;
253     use std::path::Path;
254 
255     /// Rebuild the `preopt.peepmatic` peephole optimizer.
256     ///
257     /// Saves and overwrites the old `preopt.serialized` build and returns a
258     /// copy of the result.
rebuild_preopt() -> Vec<u8>259     pub fn rebuild_preopt() -> Vec<u8> {
260         let codegen_path = Path::new(include_str!(concat!(
261             env!("OUT_DIR"),
262             "/CRANELIFT_CODEGEN_PATH"
263         )));
264         let source_path = codegen_path.join("src").join("preopt.peepmatic");
265 
266         let preopt = peepmatic::compile_file::<Opcode>(&source_path)
267             .expect("failed to compile `src/preopt.peepmatic`");
268 
269         let serialized_path = codegen_path.join("src").join("preopt.serialized");
270         preopt
271             .serialize_to_file(&serialized_path)
272             .expect("failed to serialize peephole optimizer to `src/preopt.serialized`");
273         fs::read(&serialized_path).expect("failed to read `src/preopt.serialized`")
274     }
275 }
276 
277 /// Get the `preopt.peepmatic` peephole optimizer.
preopt<'a, 'b>( isa: &'b dyn TargetIsa, ) -> PeepholeOptimizer<'static, 'a, &'b dyn TargetIsa>278 pub(crate) fn preopt<'a, 'b>(
279     isa: &'b dyn TargetIsa,
280 ) -> PeepholeOptimizer<'static, 'a, &'b dyn TargetIsa> {
281     #[cfg(feature = "rebuild-peephole-optimizers")]
282     fn get_serialized() -> Cow<'static, [u8]> {
283         rebuild::rebuild_preopt().into()
284     }
285 
286     #[cfg(not(feature = "rebuild-peephole-optimizers"))]
287     fn get_serialized() -> Cow<'static, [u8]> {
288         static SERIALIZED: &[u8] = include_bytes!("preopt.serialized");
289         SERIALIZED.into()
290     }
291 
292     // Once initialized, this must never be re-assigned. The initialized value
293     // is semantically "static data" and is intentionally leaked for the whole
294     // program's lifetime.
295     static DESERIALIZED: AtomicPtr<PeepholeOptimizations<Opcode>> = AtomicPtr::new(ptr::null_mut());
296 
297     // If `DESERIALIZED` has already been initialized, then just use it.
298     let ptr = DESERIALIZED.load(Ordering::SeqCst);
299     if let Some(peep_opts) = unsafe { ptr.as_ref() } {
300         return peep_opts.optimizer(isa);
301     }
302 
303     // Otherwise, if `DESERIALIZED` hasn't been initialized, then we need to
304     // deserialize the peephole optimizations and initialize it. However,
305     // another thread could be doing the same thing concurrently, so there is a
306     // race to see who initializes `DESERIALIZED` first, and we need to be
307     // prepared to both win or lose that race.
308     let peep_opts = PeepholeOptimizations::deserialize(&get_serialized())
309         .expect("should always be able to deserialize `preopt.serialized`");
310     let peep_opts = Box::into_raw(Box::new(peep_opts));
311 
312     // Only update `DESERIALIZE` if it is still null, attempting to perform the
313     // one-time transition from null -> non-null.
314     if DESERIALIZED
315         .compare_and_swap(ptr::null_mut(), peep_opts, Ordering::SeqCst)
316         .is_null()
317     {
318         // We won the race to initialize `DESERIALIZED`.
319         debug_assert_eq!(DESERIALIZED.load(Ordering::SeqCst), peep_opts);
320         let peep_opts = unsafe { &*peep_opts };
321         return peep_opts.optimizer(isa);
322     }
323 
324     // We lost the race to initialize `DESERIALIZED`. Drop our no-longer-needed
325     // instance of `peep_opts` and get the pointer to the instance that won the
326     // race.
327     let _ = unsafe { Box::from_raw(peep_opts) };
328     let peep_opts = DESERIALIZED.load(Ordering::SeqCst);
329     let peep_opts = unsafe { peep_opts.as_ref().unwrap() };
330     peep_opts.optimizer(isa)
331 }
332 
333 /// Either a `Value` or an `Inst`.
334 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
335 pub enum ValueOrInst {
336     Value(Value),
337     Inst(Inst),
338 }
339 
340 impl ValueOrInst {
341     /// Get the underlying `Value` if any.
value(&self) -> Option<Value>342     pub fn value(&self) -> Option<Value> {
343         match *self {
344             Self::Value(v) => Some(v),
345             Self::Inst(_) => None,
346         }
347     }
348 
349     /// Get the underlying `Inst` if any.
inst(&self) -> Option<Inst>350     pub fn inst(&self) -> Option<Inst> {
351         match *self {
352             Self::Inst(i) => Some(i),
353             Self::Value(_) => None,
354         }
355     }
356 
357     /// Unwrap the underlying `Value`, panicking if it is not a `Value.
unwrap_value(&self) -> Value358     pub fn unwrap_value(&self) -> Value {
359         self.value().unwrap()
360     }
361 
362     /// Unwrap the underlying `Inst`, panicking if it is not a `Inst.
unwrap_inst(&self) -> Inst363     pub fn unwrap_inst(&self) -> Inst {
364         self.inst().unwrap()
365     }
366 
367     /// Is this a `Value`?
is_value(&self) -> bool368     pub fn is_value(&self) -> bool {
369         self.value().is_some()
370     }
371 
372     /// Is this an `Inst`?
is_inst(&self) -> bool373     pub fn is_inst(&self) -> bool {
374         self.inst().is_some()
375     }
376 
resolve_inst(&self, dfg: &DataFlowGraph) -> Option<Inst>377     fn resolve_inst(&self, dfg: &DataFlowGraph) -> Option<Inst> {
378         match *self {
379             ValueOrInst::Inst(i) => Some(i),
380             ValueOrInst::Value(v) => dfg.value_def(v).inst(),
381         }
382     }
383 
result_bit_width(&self, dfg: &DataFlowGraph) -> u8384     fn result_bit_width(&self, dfg: &DataFlowGraph) -> u8 {
385         match *self {
386             ValueOrInst::Value(v) => dfg.value_type(v).bits().try_into().unwrap(),
387             ValueOrInst::Inst(inst) => {
388                 let result = dfg.first_result(inst);
389                 dfg.value_type(result).bits().try_into().unwrap()
390             }
391         }
392     }
393 
to_constant(&self, pos: &mut FuncCursor) -> Option<Constant>394     fn to_constant(&self, pos: &mut FuncCursor) -> Option<Constant> {
395         let inst = self.resolve_inst(&pos.func.dfg)?;
396         match pos.func.dfg[inst] {
397             InstructionData::UnaryImm {
398                 opcode: Opcode::Iconst,
399                 imm,
400             } => {
401                 let width = self.result_bit_width(&pos.func.dfg).try_into().unwrap();
402                 let x: i64 = imm.into();
403                 Some(Constant::Int(x as u64, width))
404             }
405             InstructionData::UnaryBool {
406                 opcode: Opcode::Bconst,
407                 imm,
408             } => {
409                 let width = self.result_bit_width(&pos.func.dfg).try_into().unwrap();
410                 Some(Constant::Bool(imm, width))
411             }
412             _ => None,
413         }
414     }
415 }
416 
417 impl From<Value> for ValueOrInst {
from(v: Value) -> ValueOrInst418     fn from(v: Value) -> ValueOrInst {
419         ValueOrInst::Value(v)
420     }
421 }
422 
423 impl From<Inst> for ValueOrInst {
from(i: Inst) -> ValueOrInst424     fn from(i: Inst) -> ValueOrInst {
425         ValueOrInst::Inst(i)
426     }
427 }
428 
429 /// Get the fixed bit width of `bit_width`, or if it is polymorphic, the bit
430 /// width of `root`.
bit_width(dfg: &DataFlowGraph, bit_width: BitWidth, root: Inst) -> u8431 fn bit_width(dfg: &DataFlowGraph, bit_width: BitWidth, root: Inst) -> u8 {
432     bit_width.fixed_width().unwrap_or_else(|| {
433         let tyvar = dfg.ctrl_typevar(root);
434         let ty = dfg.compute_result_type(root, 0, tyvar).unwrap();
435         u8::try_from(ty.bits()).unwrap()
436     })
437 }
438 
439 /// Convert the constant `c` into an instruction.
const_to_value<'a>(builder: impl InstBuilder<'a>, c: Constant, root: Inst) -> Value440 fn const_to_value<'a>(builder: impl InstBuilder<'a>, c: Constant, root: Inst) -> Value {
441     match c {
442         Constant::Bool(b, width) => {
443             let width = bit_width(builder.data_flow_graph(), width, root);
444             let ty = match width {
445                 1 => types::B1,
446                 8 => types::B8,
447                 16 => types::B16,
448                 32 => types::B32,
449                 64 => types::B64,
450                 128 => types::B128,
451                 _ => unreachable!(),
452             };
453             builder.bconst(ty, b)
454         }
455         Constant::Int(x, width) => {
456             let width = bit_width(builder.data_flow_graph(), width, root);
457             let ty = match width {
458                 8 => types::I8,
459                 16 => types::I16,
460                 32 => types::I32,
461                 64 => types::I64,
462                 128 => types::I128,
463                 _ => unreachable!(),
464             };
465             builder.iconst(ty, x as i64)
466         }
467     }
468 }
469 
part_to_value(pos: &mut FuncCursor, root: Inst, part: Part<ValueOrInst>) -> Option<Value>470 fn part_to_value(pos: &mut FuncCursor, root: Inst, part: Part<ValueOrInst>) -> Option<Value> {
471     match part {
472         Part::Instruction(ValueOrInst::Inst(inst)) => {
473             pos.func.dfg.inst_results(inst).first().copied()
474         }
475         Part::Instruction(ValueOrInst::Value(v)) => Some(v),
476         Part::Constant(c) => Some(const_to_value(pos.ins(), c, root)),
477         Part::ConditionCode(_) => None,
478     }
479 }
480 
481 impl TryFrom<Constant> for Imm64 {
482     type Error = &'static str;
483 
try_from(c: Constant) -> Result<Self, Self::Error>484     fn try_from(c: Constant) -> Result<Self, Self::Error> {
485         match c {
486             Constant::Int(x, _) => Ok(Imm64::from(x as i64)),
487             Constant::Bool(..) => Err("cannot create Imm64 from Constant::Bool"),
488         }
489     }
490 }
491 
492 impl Into<Constant> for Imm64 {
493     #[inline]
into(self) -> Constant494     fn into(self) -> Constant {
495         let x: i64 = self.into();
496         Constant::Int(x as _, BitWidth::SixtyFour)
497     }
498 }
499 
500 impl Into<Part<ValueOrInst>> for Imm64 {
501     #[inline]
into(self) -> Part<ValueOrInst>502     fn into(self) -> Part<ValueOrInst> {
503         let c: Constant = self.into();
504         c.into()
505     }
506 }
507 
part_to_imm64(pos: &mut FuncCursor, part: Part<ValueOrInst>) -> Imm64508 fn part_to_imm64(pos: &mut FuncCursor, part: Part<ValueOrInst>) -> Imm64 {
509     return match part {
510         Part::Instruction(x) => match x.to_constant(pos).unwrap_or_else(|| cannot_convert()) {
511             Constant::Int(x, _) => (x as i64).into(),
512             Constant::Bool(..) => cannot_convert(),
513         },
514         Part::Constant(Constant::Int(x, _)) => (x as i64).into(),
515         Part::ConditionCode(_) | Part::Constant(Constant::Bool(..)) => cannot_convert(),
516     };
517 
518     #[inline(never)]
519     #[cold]
520     fn cannot_convert() -> ! {
521         panic!("cannot convert part into `Imm64`")
522     }
523 }
524 
525 impl Into<Constant> for Uimm64 {
526     #[inline]
into(self) -> Constant527     fn into(self) -> Constant {
528         let x: u64 = self.into();
529         Constant::Int(x, BitWidth::SixtyFour)
530     }
531 }
532 
533 impl Into<Part<ValueOrInst>> for Uimm64 {
534     #[inline]
into(self) -> Part<ValueOrInst>535     fn into(self) -> Part<ValueOrInst> {
536         let c: Constant = self.into();
537         c.into()
538     }
539 }
540 
peepmatic_to_intcc(cc: ConditionCode) -> IntCC541 fn peepmatic_to_intcc(cc: ConditionCode) -> IntCC {
542     match cc {
543         ConditionCode::Eq => IntCC::Equal,
544         ConditionCode::Ne => IntCC::NotEqual,
545         ConditionCode::Slt => IntCC::SignedLessThan,
546         ConditionCode::Sle => IntCC::SignedGreaterThanOrEqual,
547         ConditionCode::Sgt => IntCC::SignedGreaterThan,
548         ConditionCode::Sge => IntCC::SignedLessThanOrEqual,
549         ConditionCode::Ult => IntCC::UnsignedLessThan,
550         ConditionCode::Uge => IntCC::UnsignedGreaterThanOrEqual,
551         ConditionCode::Ugt => IntCC::UnsignedGreaterThan,
552         ConditionCode::Ule => IntCC::UnsignedLessThanOrEqual,
553         ConditionCode::Of => IntCC::Overflow,
554         ConditionCode::Nof => IntCC::NotOverflow,
555     }
556 }
557 
intcc_to_peepmatic(cc: IntCC) -> ConditionCode558 fn intcc_to_peepmatic(cc: IntCC) -> ConditionCode {
559     match cc {
560         IntCC::Equal => ConditionCode::Eq,
561         IntCC::NotEqual => ConditionCode::Ne,
562         IntCC::SignedLessThan => ConditionCode::Slt,
563         IntCC::SignedGreaterThanOrEqual => ConditionCode::Sle,
564         IntCC::SignedGreaterThan => ConditionCode::Sgt,
565         IntCC::SignedLessThanOrEqual => ConditionCode::Sge,
566         IntCC::UnsignedLessThan => ConditionCode::Ult,
567         IntCC::UnsignedGreaterThanOrEqual => ConditionCode::Uge,
568         IntCC::UnsignedGreaterThan => ConditionCode::Ugt,
569         IntCC::UnsignedLessThanOrEqual => ConditionCode::Ule,
570         IntCC::Overflow => ConditionCode::Of,
571         IntCC::NotOverflow => ConditionCode::Nof,
572     }
573 }
574 
peepmatic_ty_to_ir_ty(ty: Type, dfg: &DataFlowGraph, root: Inst) -> types::Type575 fn peepmatic_ty_to_ir_ty(ty: Type, dfg: &DataFlowGraph, root: Inst) -> types::Type {
576     match (ty.kind, bit_width(dfg, ty.bit_width, root)) {
577         (Kind::Int, 8) => types::I8,
578         (Kind::Int, 16) => types::I16,
579         (Kind::Int, 32) => types::I32,
580         (Kind::Int, 64) => types::I64,
581         (Kind::Int, 128) => types::I128,
582         (Kind::Bool, 1) => types::B1,
583         (Kind::Bool, 8) => types::I8,
584         (Kind::Bool, 16) => types::I16,
585         (Kind::Bool, 32) => types::I32,
586         (Kind::Bool, 64) => types::I64,
587         (Kind::Bool, 128) => types::I128,
588         _ => unreachable!(),
589     }
590 }
591 
592 // NB: the unsafe contract we must uphold here is that our implementation of
593 // `instruction_result_bit_width` must always return a valid, non-zero bit
594 // width.
595 unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa {
596     type Context = FuncCursor<'b>;
597 
598     type Operator = Opcode;
599 
600     type Instruction = ValueOrInst;
601 
replace_instruction( &self, pos: &mut FuncCursor<'b>, old: ValueOrInst, new: Part<ValueOrInst>, ) -> ValueOrInst602     fn replace_instruction(
603         &self,
604         pos: &mut FuncCursor<'b>,
605         old: ValueOrInst,
606         new: Part<ValueOrInst>,
607     ) -> ValueOrInst {
608         log::trace!("replace {:?} with {:?}", old, new);
609         let old_inst = old.resolve_inst(&pos.func.dfg).unwrap();
610 
611         // Try to convert `new` to an instruction, because we prefer replacing
612         // an old instruction with a new one wholesale. However, if the
613         // replacement cannot be converted to an instruction (e.g. the
614         // right-hand side is a block/function parameter value) then we change
615         // the old instruction's result to an alias of the new value.
616         let new_inst = match new {
617             Part::Instruction(ValueOrInst::Inst(inst)) => Some(inst),
618             Part::Instruction(ValueOrInst::Value(_)) => {
619                 // Do not try and follow the value definition. If we transplant
620                 // this value's instruction, and there are other uses of this
621                 // value, then we could mess up ordering between instructions.
622                 None
623             }
624             Part::Constant(c) => {
625                 let v = const_to_value(pos.ins(), c, old_inst);
626                 let inst = pos.func.dfg.value_def(v).unwrap_inst();
627                 Some(inst)
628             }
629             Part::ConditionCode(_) => None,
630         };
631 
632         match new_inst {
633             Some(new_inst) => {
634                 pos.func.transplant_inst(old_inst, new_inst);
635                 debug_assert_eq!(pos.current_inst(), Some(old_inst));
636                 old_inst.into()
637             }
638             None => {
639                 let new_value = part_to_value(pos, old_inst, new).unwrap();
640 
641                 let old_results = pos.func.dfg.detach_results(old_inst);
642                 let old_results = old_results.as_slice(&pos.func.dfg.value_lists);
643                 assert_eq!(old_results.len(), 1);
644                 let old_value = old_results[0];
645 
646                 pos.func.dfg.change_to_alias(old_value, new_value);
647                 pos.func.dfg.replace(old_inst).nop();
648 
649                 new_value.into()
650             }
651         }
652     }
653 
operator<E>( &self, pos: &mut FuncCursor<'b>, value_or_inst: ValueOrInst, operands: &mut E, ) -> Option<Opcode> where E: Extend<Part<Self::Instruction>>,654     fn operator<E>(
655         &self,
656         pos: &mut FuncCursor<'b>,
657         value_or_inst: ValueOrInst,
658         operands: &mut E,
659     ) -> Option<Opcode>
660     where
661         E: Extend<Part<Self::Instruction>>,
662     {
663         let inst = value_or_inst.resolve_inst(&pos.func.dfg)?;
664         Some(match pos.func.dfg[inst] {
665             InstructionData::Binary {
666                 opcode: opcode @ Opcode::Band,
667                 args,
668             }
669             | InstructionData::Binary {
670                 opcode: opcode @ Opcode::Bor,
671                 args,
672             }
673             | InstructionData::Binary {
674                 opcode: opcode @ Opcode::Bxor,
675                 args,
676             }
677             | InstructionData::Binary {
678                 opcode: opcode @ Opcode::Iadd,
679                 args,
680             }
681             | InstructionData::Binary {
682                 opcode: opcode @ Opcode::Ifcmp,
683                 args,
684             }
685             | InstructionData::Binary {
686                 opcode: opcode @ Opcode::Imul,
687                 args,
688             }
689             | InstructionData::Binary {
690                 opcode: opcode @ Opcode::Ishl,
691                 args,
692             }
693             | InstructionData::Binary {
694                 opcode: opcode @ Opcode::Isub,
695                 args,
696             }
697             | InstructionData::Binary {
698                 opcode: opcode @ Opcode::Rotl,
699                 args,
700             }
701             | InstructionData::Binary {
702                 opcode: opcode @ Opcode::Rotr,
703                 args,
704             }
705             | InstructionData::Binary {
706                 opcode: opcode @ Opcode::Sdiv,
707                 args,
708             }
709             | InstructionData::Binary {
710                 opcode: opcode @ Opcode::Srem,
711                 args,
712             }
713             | InstructionData::Binary {
714                 opcode: opcode @ Opcode::Sshr,
715                 args,
716             }
717             | InstructionData::Binary {
718                 opcode: opcode @ Opcode::Udiv,
719                 args,
720             }
721             | InstructionData::Binary {
722                 opcode: opcode @ Opcode::Urem,
723                 args,
724             }
725             | InstructionData::Binary {
726                 opcode: opcode @ Opcode::Ushr,
727                 args,
728             } => {
729                 operands.extend(args.iter().map(|v| Part::Instruction((*v).into())));
730                 opcode
731             }
732 
733             InstructionData::BinaryImm64 {
734                 opcode: opcode @ Opcode::BandImm,
735                 imm,
736                 arg,
737             }
738             | InstructionData::BinaryImm64 {
739                 opcode: opcode @ Opcode::BorImm,
740                 imm,
741                 arg,
742             }
743             | InstructionData::BinaryImm64 {
744                 opcode: opcode @ Opcode::BxorImm,
745                 imm,
746                 arg,
747             }
748             | InstructionData::BinaryImm64 {
749                 opcode: opcode @ Opcode::IaddImm,
750                 imm,
751                 arg,
752             }
753             | InstructionData::BinaryImm64 {
754                 opcode: opcode @ Opcode::IfcmpImm,
755                 imm,
756                 arg,
757             }
758             | InstructionData::BinaryImm64 {
759                 opcode: opcode @ Opcode::ImulImm,
760                 imm,
761                 arg,
762             }
763             | InstructionData::BinaryImm64 {
764                 opcode: opcode @ Opcode::IrsubImm,
765                 imm,
766                 arg,
767             }
768             | InstructionData::BinaryImm64 {
769                 opcode: opcode @ Opcode::IshlImm,
770                 imm,
771                 arg,
772             }
773             | InstructionData::BinaryImm64 {
774                 opcode: opcode @ Opcode::RotlImm,
775                 imm,
776                 arg,
777             }
778             | InstructionData::BinaryImm64 {
779                 opcode: opcode @ Opcode::RotrImm,
780                 imm,
781                 arg,
782             }
783             | InstructionData::BinaryImm64 {
784                 opcode: opcode @ Opcode::SdivImm,
785                 imm,
786                 arg,
787             }
788             | InstructionData::BinaryImm64 {
789                 opcode: opcode @ Opcode::SremImm,
790                 imm,
791                 arg,
792             }
793             | InstructionData::BinaryImm64 {
794                 opcode: opcode @ Opcode::SshrImm,
795                 imm,
796                 arg,
797             }
798             | InstructionData::BinaryImm64 {
799                 opcode: opcode @ Opcode::UdivImm,
800                 imm,
801                 arg,
802             }
803             | InstructionData::BinaryImm64 {
804                 opcode: opcode @ Opcode::UremImm,
805                 imm,
806                 arg,
807             }
808             | InstructionData::BinaryImm64 {
809                 opcode: opcode @ Opcode::UshrImm,
810                 imm,
811                 arg,
812             } => {
813                 operands.extend(
814                     iter::once(imm.into()).chain(iter::once(Part::Instruction(arg.into()))),
815                 );
816                 opcode
817             }
818 
819             InstructionData::Branch {
820                 opcode: opcode @ Opcode::Brnz,
821                 ref args,
822                 destination: _,
823             }
824             | InstructionData::Branch {
825                 opcode: opcode @ Opcode::Brz,
826                 ref args,
827                 destination: _,
828             } => {
829                 operands.extend(
830                     args.as_slice(&pos.func.dfg.value_lists)
831                         .iter()
832                         .map(|v| Part::Instruction((*v).into()))
833                         // NB: Peepmatic only knows about the condition, not any
834                         // of the arguments to the block, which are special
835                         // cased elsewhere, if/when we actually replace the
836                         // instruction.
837                         .take(1),
838                 );
839                 opcode
840             }
841 
842             InstructionData::CondTrap {
843                 opcode: opcode @ Opcode::Trapnz,
844                 arg,
845                 code: _,
846             }
847             | InstructionData::CondTrap {
848                 opcode: opcode @ Opcode::Trapz,
849                 arg,
850                 code: _,
851             } => {
852                 operands.extend(iter::once(Part::Instruction(arg.into())));
853                 opcode
854             }
855 
856             InstructionData::IntCompare {
857                 opcode: opcode @ Opcode::Icmp,
858                 cond,
859                 args,
860             } => {
861                 operands.extend(
862                     iter::once(intcc_to_peepmatic(cond).into())
863                         .chain(args.iter().map(|v| Part::Instruction((*v).into()))),
864                 );
865                 opcode
866             }
867 
868             InstructionData::IntCompareImm {
869                 opcode: opcode @ Opcode::IcmpImm,
870                 cond,
871                 imm,
872                 arg,
873             } => {
874                 operands.extend(
875                     iter::once(intcc_to_peepmatic(cond).into())
876                         .chain(iter::once(Part::Constant(imm.into())))
877                         .chain(iter::once(Part::Instruction(arg.into()))),
878                 );
879                 opcode
880             }
881 
882             InstructionData::Ternary {
883                 opcode: opcode @ Opcode::Select,
884                 ref args,
885             } => {
886                 operands.extend(args.iter().map(|v| Part::Instruction((*v).into())));
887                 opcode
888             }
889 
890             InstructionData::Unary {
891                 opcode: opcode @ Opcode::AdjustSpDown,
892                 arg,
893             }
894             | InstructionData::Unary {
895                 opcode: opcode @ Opcode::Bint,
896                 arg,
897             }
898             | InstructionData::Unary {
899                 opcode: opcode @ Opcode::Ireduce,
900                 arg,
901             }
902             | InstructionData::Unary {
903                 opcode: opcode @ Opcode::Sextend,
904                 arg,
905             }
906             | InstructionData::Unary {
907                 opcode: opcode @ Opcode::Uextend,
908                 arg,
909             } => {
910                 operands.extend(iter::once(Part::Instruction(arg.into())));
911                 opcode
912             }
913 
914             InstructionData::UnaryBool { opcode, imm } => {
915                 operands.extend(iter::once(Part::Constant(Constant::Bool(
916                     imm,
917                     BitWidth::Polymorphic,
918                 ))));
919                 opcode
920             }
921 
922             InstructionData::UnaryImm {
923                 opcode: opcode @ Opcode::AdjustSpDownImm,
924                 imm,
925             }
926             | InstructionData::UnaryImm {
927                 opcode: opcode @ Opcode::Iconst,
928                 imm,
929             } => {
930                 operands.extend(iter::once(imm.into()));
931                 opcode
932             }
933             ref otherwise => {
934                 log::trace!("Not supported by Peepmatic: {:?}", otherwise);
935                 return None;
936             }
937         })
938     }
939 
make_inst_1( &self, pos: &mut FuncCursor<'b>, root: ValueOrInst, operator: Opcode, r#type: Type, a: Part<ValueOrInst>, ) -> ValueOrInst940     fn make_inst_1(
941         &self,
942         pos: &mut FuncCursor<'b>,
943         root: ValueOrInst,
944         operator: Opcode,
945         r#type: Type,
946         a: Part<ValueOrInst>,
947     ) -> ValueOrInst {
948         log::trace!("make_inst_1: {:?}({:?})", operator, a);
949 
950         let root = root.resolve_inst(&pos.func.dfg).unwrap();
951         match operator {
952             Opcode::AdjustSpDown => {
953                 let a = part_to_value(pos, root, a).unwrap();
954                 pos.ins().adjust_sp_down(a).into()
955             }
956             Opcode::AdjustSpDownImm => {
957                 let c = a.unwrap_constant();
958                 let imm = Imm64::try_from(c).unwrap();
959                 pos.ins().adjust_sp_down_imm(imm).into()
960             }
961             Opcode::Bconst => {
962                 let c = a.unwrap_constant();
963                 let val = const_to_value(pos.ins(), c, root);
964                 pos.func.dfg.value_def(val).unwrap_inst().into()
965             }
966             Opcode::Bint => {
967                 let a = part_to_value(pos, root, a).unwrap();
968                 let ty = peepmatic_ty_to_ir_ty(r#type, &pos.func.dfg, root);
969                 let val = pos.ins().bint(ty, a);
970                 pos.func.dfg.value_def(val).unwrap_inst().into()
971             }
972             Opcode::Bnot => {
973                 let a = part_to_value(pos, root, a).unwrap();
974                 let val = pos.ins().bnot(a);
975                 pos.func.dfg.value_def(val).unwrap_inst().into()
976             }
977             Opcode::Brnz => {
978                 let a = part_to_value(pos, root, a).unwrap();
979 
980                 // NB: branching instructions must be the root of an
981                 // optimization's right-hand side, so we get the destination
982                 // block and arguments from the left-hand side's root. Peepmatic
983                 // doesn't currently represent labels or varargs.
984                 let block = pos.func.dfg[root].branch_destination().unwrap();
985                 let args = pos.func.dfg.inst_args(root)[1..].to_vec();
986 
987                 pos.ins().brnz(a, block, &args).into()
988             }
989             Opcode::Brz => {
990                 let a = part_to_value(pos, root, a).unwrap();
991 
992                 // See the comment in the `Opcode::Brnz` match argm.
993                 let block = pos.func.dfg[root].branch_destination().unwrap();
994                 let args = pos.func.dfg.inst_args(root)[1..].to_vec();
995 
996                 pos.ins().brz(a, block, &args).into()
997             }
998             Opcode::Iconst => {
999                 let a = a.unwrap_constant();
1000                 let val = const_to_value(pos.ins(), a, root);
1001                 pos.func.dfg.value_def(val).unwrap_inst().into()
1002             }
1003             Opcode::Ireduce => {
1004                 let a = part_to_value(pos, root, a).unwrap();
1005                 let ty = peepmatic_ty_to_ir_ty(r#type, &pos.func.dfg, root);
1006                 let val = pos.ins().ireduce(ty, a);
1007                 pos.func.dfg.value_def(val).unwrap_inst().into()
1008             }
1009             Opcode::Sextend => {
1010                 let a = part_to_value(pos, root, a).unwrap();
1011                 let ty = peepmatic_ty_to_ir_ty(r#type, &pos.func.dfg, root);
1012                 let val = pos.ins().sextend(ty, a);
1013                 pos.func.dfg.value_def(val).unwrap_inst().into()
1014             }
1015             Opcode::Trapnz => {
1016                 let a = part_to_value(pos, root, a).unwrap();
1017 
1018                 // NB: similar to branching instructions (see comment in the
1019                 // `Opcode::Brnz` match arm) trapping instructions must be the
1020                 // root of an optimization's right-hand side, and we get the
1021                 // trap code from the root of the left-hand side. Peepmatic
1022                 // doesn't currently represent trap codes.
1023                 let code = pos.func.dfg[root].trap_code().unwrap();
1024 
1025                 pos.ins().trapnz(a, code).into()
1026             }
1027             Opcode::Trapz => {
1028                 let a = part_to_value(pos, root, a).unwrap();
1029                 // See comment in the `Opcode::Trapnz` match arm.
1030                 let code = pos.func.dfg[root].trap_code().unwrap();
1031                 pos.ins().trapz(a, code).into()
1032             }
1033             Opcode::Uextend => {
1034                 let a = part_to_value(pos, root, a).unwrap();
1035                 let ty = peepmatic_ty_to_ir_ty(r#type, &pos.func.dfg, root);
1036                 let val = pos.ins().uextend(ty, a);
1037                 pos.func.dfg.value_def(val).unwrap_inst().into()
1038             }
1039             _ => unreachable!(),
1040         }
1041     }
1042 
make_inst_2( &self, pos: &mut FuncCursor<'b>, root: ValueOrInst, operator: Opcode, _: Type, a: Part<ValueOrInst>, b: Part<ValueOrInst>, ) -> ValueOrInst1043     fn make_inst_2(
1044         &self,
1045         pos: &mut FuncCursor<'b>,
1046         root: ValueOrInst,
1047         operator: Opcode,
1048         _: Type,
1049         a: Part<ValueOrInst>,
1050         b: Part<ValueOrInst>,
1051     ) -> ValueOrInst {
1052         log::trace!("make_inst_2: {:?}({:?}, {:?})", operator, a, b);
1053 
1054         let root = root.resolve_inst(&pos.func.dfg).unwrap();
1055         match operator {
1056             Opcode::Band => {
1057                 let a = part_to_value(pos, root, a).unwrap();
1058                 let b = part_to_value(pos, root, b).unwrap();
1059                 let val = pos.ins().band(a, b);
1060                 pos.func.dfg.value_def(val).unwrap_inst().into()
1061             }
1062             Opcode::BandImm => {
1063                 let a = part_to_imm64(pos, a);
1064                 let b = part_to_value(pos, root, b).unwrap();
1065                 let val = pos.ins().band_imm(b, a);
1066                 pos.func.dfg.value_def(val).unwrap_inst().into()
1067             }
1068             Opcode::Bor => {
1069                 let a = part_to_value(pos, root, a).unwrap();
1070                 let b = part_to_value(pos, root, b).unwrap();
1071                 let val = pos.ins().bor(a, b);
1072                 pos.func.dfg.value_def(val).unwrap_inst().into()
1073             }
1074             Opcode::BorImm => {
1075                 let a = part_to_imm64(pos, a);
1076                 let b = part_to_value(pos, root, b).unwrap();
1077                 let val = pos.ins().bor_imm(b, a);
1078                 pos.func.dfg.value_def(val).unwrap_inst().into()
1079             }
1080             Opcode::Bxor => {
1081                 let a = part_to_value(pos, root, a).unwrap();
1082                 let b = part_to_value(pos, root, b).unwrap();
1083                 let val = pos.ins().bxor(a, b);
1084                 pos.func.dfg.value_def(val).unwrap_inst().into()
1085             }
1086             Opcode::BxorImm => {
1087                 let a = part_to_imm64(pos, a);
1088                 let b = part_to_value(pos, root, b).unwrap();
1089                 let val = pos.ins().bxor_imm(b, a);
1090                 pos.func.dfg.value_def(val).unwrap_inst().into()
1091             }
1092             Opcode::Iadd => {
1093                 let a = part_to_value(pos, root, a).unwrap();
1094                 let b = part_to_value(pos, root, b).unwrap();
1095                 let val = pos.ins().iadd(a, b);
1096                 pos.func.dfg.value_def(val).unwrap_inst().into()
1097             }
1098             Opcode::IaddImm => {
1099                 let a = part_to_imm64(pos, a);
1100                 let b = part_to_value(pos, root, b).unwrap();
1101                 let val = pos.ins().iadd_imm(b, a);
1102                 pos.func.dfg.value_def(val).unwrap_inst().into()
1103             }
1104             Opcode::Ifcmp => {
1105                 let a = part_to_value(pos, root, a).unwrap();
1106                 let b = part_to_value(pos, root, b).unwrap();
1107                 let val = pos.ins().ifcmp(a, b);
1108                 pos.func.dfg.value_def(val).unwrap_inst().into()
1109             }
1110             Opcode::IfcmpImm => {
1111                 let a = part_to_imm64(pos, a);
1112                 let b = part_to_value(pos, root, b).unwrap();
1113                 let val = pos.ins().ifcmp_imm(b, a);
1114                 pos.func.dfg.value_def(val).unwrap_inst().into()
1115             }
1116             Opcode::Imul => {
1117                 let a = part_to_value(pos, root, a).unwrap();
1118                 let b = part_to_value(pos, root, b).unwrap();
1119                 let val = pos.ins().imul(a, b);
1120                 pos.func.dfg.value_def(val).unwrap_inst().into()
1121             }
1122             Opcode::ImulImm => {
1123                 let a = part_to_imm64(pos, a);
1124                 let b = part_to_value(pos, root, b).unwrap();
1125                 let val = pos.ins().imul_imm(b, a);
1126                 pos.func.dfg.value_def(val).unwrap_inst().into()
1127             }
1128             Opcode::IrsubImm => {
1129                 let a = part_to_imm64(pos, a);
1130                 let b = part_to_value(pos, root, b).unwrap();
1131                 let val = pos.ins().irsub_imm(b, a);
1132                 pos.func.dfg.value_def(val).unwrap_inst().into()
1133             }
1134             Opcode::Ishl => {
1135                 let a = part_to_value(pos, root, a).unwrap();
1136                 let b = part_to_value(pos, root, b).unwrap();
1137                 let val = pos.ins().ishl(a, b);
1138                 pos.func.dfg.value_def(val).unwrap_inst().into()
1139             }
1140             Opcode::IshlImm => {
1141                 let a = part_to_imm64(pos, a);
1142                 let b = part_to_value(pos, root, b).unwrap();
1143                 let val = pos.ins().ishl_imm(b, a);
1144                 pos.func.dfg.value_def(val).unwrap_inst().into()
1145             }
1146             Opcode::Isub => {
1147                 let a = part_to_value(pos, root, a).unwrap();
1148                 let b = part_to_value(pos, root, b).unwrap();
1149                 let val = pos.ins().isub(a, b);
1150                 pos.func.dfg.value_def(val).unwrap_inst().into()
1151             }
1152             Opcode::Rotl => {
1153                 let a = part_to_value(pos, root, a).unwrap();
1154                 let b = part_to_value(pos, root, b).unwrap();
1155                 let val = pos.ins().rotl(a, b);
1156                 pos.func.dfg.value_def(val).unwrap_inst().into()
1157             }
1158             Opcode::RotlImm => {
1159                 let a = part_to_imm64(pos, a);
1160                 let b = part_to_value(pos, root, b).unwrap();
1161                 let val = pos.ins().rotl_imm(b, a);
1162                 pos.func.dfg.value_def(val).unwrap_inst().into()
1163             }
1164             Opcode::Rotr => {
1165                 let a = part_to_value(pos, root, a).unwrap();
1166                 let b = part_to_value(pos, root, b).unwrap();
1167                 let val = pos.ins().rotr(a, b);
1168                 pos.func.dfg.value_def(val).unwrap_inst().into()
1169             }
1170             Opcode::RotrImm => {
1171                 let a = part_to_imm64(pos, a);
1172                 let b = part_to_value(pos, root, b).unwrap();
1173                 let val = pos.ins().rotr_imm(b, a);
1174                 pos.func.dfg.value_def(val).unwrap_inst().into()
1175             }
1176             Opcode::Sdiv => {
1177                 let a = part_to_value(pos, root, a).unwrap();
1178                 let b = part_to_value(pos, root, b).unwrap();
1179                 let val = pos.ins().sdiv(a, b);
1180                 pos.func.dfg.value_def(val).unwrap_inst().into()
1181             }
1182             Opcode::SdivImm => {
1183                 let a = part_to_imm64(pos, a);
1184                 let b = part_to_value(pos, root, b).unwrap();
1185                 let val = pos.ins().sdiv_imm(b, a);
1186                 pos.func.dfg.value_def(val).unwrap_inst().into()
1187             }
1188             Opcode::Srem => {
1189                 let a = part_to_value(pos, root, a).unwrap();
1190                 let b = part_to_value(pos, root, b).unwrap();
1191                 let val = pos.ins().srem(a, b);
1192                 pos.func.dfg.value_def(val).unwrap_inst().into()
1193             }
1194             Opcode::SremImm => {
1195                 let a = part_to_imm64(pos, a);
1196                 let b = part_to_value(pos, root, b).unwrap();
1197                 let val = pos.ins().srem_imm(b, a);
1198                 pos.func.dfg.value_def(val).unwrap_inst().into()
1199             }
1200             Opcode::Sshr => {
1201                 let a = part_to_value(pos, root, a).unwrap();
1202                 let b = part_to_value(pos, root, b).unwrap();
1203                 let val = pos.ins().sshr(a, b);
1204                 pos.func.dfg.value_def(val).unwrap_inst().into()
1205             }
1206             Opcode::SshrImm => {
1207                 let a = part_to_imm64(pos, a);
1208                 let b = part_to_value(pos, root, b).unwrap();
1209                 let val = pos.ins().sshr_imm(b, a);
1210                 pos.func.dfg.value_def(val).unwrap_inst().into()
1211             }
1212             Opcode::Udiv => {
1213                 let a = part_to_value(pos, root, a).unwrap();
1214                 let b = part_to_value(pos, root, b).unwrap();
1215                 let val = pos.ins().udiv(a, b);
1216                 pos.func.dfg.value_def(val).unwrap_inst().into()
1217             }
1218             Opcode::UdivImm => {
1219                 let a = part_to_imm64(pos, a);
1220                 let b = part_to_value(pos, root, b).unwrap();
1221                 let val = pos.ins().udiv_imm(b, a);
1222                 pos.func.dfg.value_def(val).unwrap_inst().into()
1223             }
1224             Opcode::Urem => {
1225                 let a = part_to_value(pos, root, a).unwrap();
1226                 let b = part_to_value(pos, root, b).unwrap();
1227                 let val = pos.ins().urem(a, b);
1228                 pos.func.dfg.value_def(val).unwrap_inst().into()
1229             }
1230             Opcode::UremImm => {
1231                 let a = part_to_imm64(pos, a);
1232                 let b = part_to_value(pos, root, b).unwrap();
1233                 let val = pos.ins().urem_imm(b, a);
1234                 pos.func.dfg.value_def(val).unwrap_inst().into()
1235             }
1236             Opcode::Ushr => {
1237                 let a = part_to_value(pos, root, a).unwrap();
1238                 let b = part_to_value(pos, root, b).unwrap();
1239                 let val = pos.ins().ushr(a, b);
1240                 pos.func.dfg.value_def(val).unwrap_inst().into()
1241             }
1242             Opcode::UshrImm => {
1243                 let a = part_to_imm64(pos, a);
1244                 let b = part_to_value(pos, root, b).unwrap();
1245                 let val = pos.ins().ushr_imm(b, a);
1246                 pos.func.dfg.value_def(val).unwrap_inst().into()
1247             }
1248             _ => unreachable!(),
1249         }
1250     }
1251 
make_inst_3( &self, pos: &mut FuncCursor<'b>, root: ValueOrInst, operator: Opcode, _: Type, a: Part<ValueOrInst>, b: Part<ValueOrInst>, c: Part<ValueOrInst>, ) -> ValueOrInst1252     fn make_inst_3(
1253         &self,
1254         pos: &mut FuncCursor<'b>,
1255         root: ValueOrInst,
1256         operator: Opcode,
1257         _: Type,
1258         a: Part<ValueOrInst>,
1259         b: Part<ValueOrInst>,
1260         c: Part<ValueOrInst>,
1261     ) -> ValueOrInst {
1262         log::trace!("make_inst_3: {:?}({:?}, {:?}, {:?})", operator, a, b, c);
1263 
1264         let root = root.resolve_inst(&pos.func.dfg).unwrap();
1265         match operator {
1266             Opcode::Icmp => {
1267                 let cond = a.unwrap_condition_code();
1268                 let cond = peepmatic_to_intcc(cond);
1269                 let b = part_to_value(pos, root, b).unwrap();
1270                 let c = part_to_value(pos, root, c).unwrap();
1271                 let val = pos.ins().icmp(cond, b, c);
1272                 pos.func.dfg.value_def(val).unwrap_inst().into()
1273             }
1274             Opcode::IcmpImm => {
1275                 let cond = a.unwrap_condition_code();
1276                 let cond = peepmatic_to_intcc(cond);
1277                 let imm = part_to_imm64(pos, b);
1278                 let c = part_to_value(pos, root, c).unwrap();
1279                 let val = pos.ins().icmp_imm(cond, c, imm);
1280                 pos.func.dfg.value_def(val).unwrap_inst().into()
1281             }
1282             Opcode::Select => {
1283                 let a = part_to_value(pos, root, a).unwrap();
1284                 let b = part_to_value(pos, root, b).unwrap();
1285                 let c = part_to_value(pos, root, c).unwrap();
1286                 let val = pos.ins().select(a, b, c);
1287                 pos.func.dfg.value_def(val).unwrap_inst().into()
1288             }
1289             _ => unreachable!(),
1290         }
1291     }
1292 
instruction_to_constant( &self, pos: &mut FuncCursor<'b>, value_or_inst: ValueOrInst, ) -> Option<Constant>1293     fn instruction_to_constant(
1294         &self,
1295         pos: &mut FuncCursor<'b>,
1296         value_or_inst: ValueOrInst,
1297     ) -> Option<Constant> {
1298         value_or_inst.to_constant(pos)
1299     }
1300 
instruction_result_bit_width( &self, pos: &mut FuncCursor<'b>, value_or_inst: ValueOrInst, ) -> u81301     fn instruction_result_bit_width(
1302         &self,
1303         pos: &mut FuncCursor<'b>,
1304         value_or_inst: ValueOrInst,
1305     ) -> u8 {
1306         value_or_inst.result_bit_width(&pos.func.dfg)
1307     }
1308 
native_word_size_in_bits(&self, _pos: &mut FuncCursor<'b>) -> u81309     fn native_word_size_in_bits(&self, _pos: &mut FuncCursor<'b>) -> u8 {
1310         self.pointer_bits()
1311     }
1312 }
1313 
1314 #[cfg(test)]
1315 #[cfg(any(feature = "x64", feature = "x86", feature = "arm64"))]
1316 mod tests {
1317     use super::*;
1318     use crate::isa::{lookup, TargetIsa};
1319     use crate::settings::{builder, Flags};
1320     use std::str::FromStr;
1321     use target_lexicon::triple;
1322 
isa() -> Box<dyn TargetIsa>1323     fn isa() -> Box<dyn TargetIsa> {
1324         // We need a triple to instantiate and run the peephole optimizer, but we
1325         // don't care which one when we're just trying to trigger a rebuild of the
1326         // peephole optimizer (it doesn't affect the serialized bytes at all).
1327         let triple = if cfg!(any(feature = "x64", feature = "x86")) {
1328             triple!("x86_64")
1329         } else if cfg!(feature = "arm64") {
1330             triple!("aarch64")
1331         } else {
1332             panic!("unknown arch")
1333         };
1334         lookup(triple).unwrap().finish(Flags::new(builder()))
1335     }
1336 
1337     #[test]
get_peepmatic_preopt()1338     fn get_peepmatic_preopt() {
1339         let isa = isa();
1340         let _ = preopt(&*isa);
1341     }
1342 }
1343