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